diff --git a/docs/api/modules/modinfo.rst b/docs/api/modules/modinfo.rst index ee3aa1b..3021cbe 100644 --- a/docs/api/modules/modinfo.rst +++ b/docs/api/modules/modinfo.rst @@ -11,15 +11,17 @@ import and use a decorator from this module. For example: # ... - @info("help [command] show the manual for all or [commands]", cmds=["help"]) + @info("help [command]", "show the manual for all or [commands]", cmds=["help"]) @command("help") def cmd_help(self, msg, cmd): # ... -The `info` decorator takes a mandatory string parameter describing the command. The second, optional, list parameter -`cmds` is a list of short names thart are aliases for the function that aide in help lookup. In all cases, the cases, -commands will be prefixed with the default command prefix (`from pyircbot.modulebase.command.prefix`). +The `info` decorator takes mandatory string parameters describing the command. The first is an argspec; simply the name +of the command with parameters marked using `<` and `>`. Optional parameters should be encased in `[`square brackets`]`. +The second parameter is a short text description of the command. The third, optional, list parameter `cmds` is a list of +short names thart are aliases for the function that aide in help lookup. In all cases, the cases, commands will be +prefixed with the default command prefix (`from pyircbot.modulebase.command.prefix`). Class Reference diff --git a/pyircbot/modules/ASCII.py b/pyircbot/modules/ASCII.py index 3067278..e5fb050 100644 --- a/pyircbot/modules/ASCII.py +++ b/pyircbot/modules/ASCII.py @@ -32,7 +32,7 @@ class ASCII(ModuleBase): self.running_asciis = defaultdict(lambda: None) self.killed_channels = defaultdict(lambda: False) - @info("listascii list available asciis", cmds=["listascii"]) + @info("listascii", "list available asciis", cmds=["listascii"]) @command("listascii") def cmd_listascii(self, msg, cmd): """ @@ -48,7 +48,7 @@ class ASCII(ModuleBase): self.bot.act_PRIVMSG(msg.args[0], "...and {} more".format(len(fnames) - self.config.get("list_max"))) return - @info("ascii print an ascii", cmds=["ascii"]) + @info("ascii ", "print an ascii", cmds=["ascii"]) @command("ascii", require_args=True) def cmd_ascii(self, msg, cmd): if self.channel_busy(msg.args[0]): @@ -68,7 +68,7 @@ class ASCII(ModuleBase): except FileNotFoundError: return - @info("stopascii stop the currently scrolling ascii", cmds=["stopascii"]) + @info("stopascii", "stop the currently scrolling ascii", cmds=["stopascii"]) @command("stopascii") def cmd_stopascii(self, msg, cmd): """ @@ -119,7 +119,7 @@ class ASCII(ModuleBase): del self.running_asciis[channel] del self.killed_channels[channel] - @info("asciiedit customize an ascii with input", cmds=["asciiedit"]) + @info("asciiedit ", "customize an ascii with input", cmds=["asciiedit"]) @command("asciiedit", require_args=True) def cmd_asciiedit(self, msg, cmd): ascii_name = cmd.args.pop(0) diff --git a/pyircbot/modules/BitcoinPrice.py b/pyircbot/modules/BitcoinPrice.py index 4419d35..af7add3 100644 --- a/pyircbot/modules/BitcoinPrice.py +++ b/pyircbot/modules/BitcoinPrice.py @@ -20,7 +20,7 @@ class BitcoinPrice(ModuleBase): self.cache = None self.cacheAge = 0 - @info("btc retrieve the current price of bitcoin", cmds=["btc"]) + @info("btc", "retrieve the current price of bitcoin", cmds=["btc"]) @command("btc", "bitcoin") def btc(self, msg, cmd): replyTo = msg.prefix.nick if "#" not in msg.args[0] else msg.args[0] diff --git a/pyircbot/modules/Calc.py b/pyircbot/modules/Calc.py index 6714711..3083ff7 100644 --- a/pyircbot/modules/Calc.py +++ b/pyircbot/modules/Calc.py @@ -80,7 +80,7 @@ class Calc(ModuleBase): seconds = int(remaining - (minutes * 60)) return "Please wait %s minute(s) and %s second(s)." % (minutes, seconds) - @info("quote [key[ =[ value]]] set or update facts", cmds=["quote"]) + @info("quote [key[ =[ value]]]", "set or update facts", cmds=["quote"]) @regex(r'(?:^\.?(?:calc|quote)(?:\s+?(?:([^=]+)(?:\s?(=)\s?(.+)?)?)?)?)', types=['PRIVMSG']) def cmd_calc(self, message, match): word, changeit, value = match.groups() @@ -136,7 +136,7 @@ class Calc(ModuleBase): randCalc["definition"], randCalc["by"])) self.updateTimeSince(channel, "calc") - @info("match search for facts by key", cmds=["match"]) + @info("match ", "search for facts by key", cmds=["match"]) @command("match", require_args=True) def cmd_match(self, msg, cmd): if self.config["delayMatch"] > 0 and self.timeSince(msg.args[0], "match") < self.config["delayMatch"]: diff --git a/pyircbot/modules/CryptoWallet.py b/pyircbot/modules/CryptoWallet.py index 45550ea..2dbaeb3 100755 --- a/pyircbot/modules/CryptoWallet.py +++ b/pyircbot/modules/CryptoWallet.py @@ -21,7 +21,7 @@ class CryptoWallet(ModuleBase): def getMods(self): return (self.bot.getBestModuleForService("attributes"), self.bot.getBestModuleForService("bitcoinrpc")) - @info("setaddr
set withdraw address", cmds=["setaddr"]) + @info("setaddr
", "set withdraw address", cmds=["setaddr"]) @command("setaddr", require_args=2, allow_private=True) def handle_setaddr(self, msg, cmd): if not self.check_login(msg.prefix, msg.args[0]): @@ -46,7 +46,7 @@ class CryptoWallet(ModuleBase): self.bot.act_PRIVMSG(msg.args[0], ".setaddr: Your address has been saved as: {}. Please verify that this is " "correct or your coins could be lost.".format(cmd.args[1])) - @info("getbal retrieve your balance ", cmds=["getbal"]) + @info("getbal ", "retrieve your balance ", cmds=["getbal"]) @command("getbal", require_args=1, allow_private=True) def handle_getbal(self, msg, cmd): if not self.check_login(msg.prefix, msg.args[0]): @@ -72,7 +72,7 @@ class CryptoWallet(ModuleBase): self.bot.act_PRIVMSG(msg.args[0], "{}: your balance is: {} {}".format(msg.prefix.nick, amount, cmd.args[0].upper())) - @info("withdraw send coins to your withdraw address", cmds=["withdraw"]) + @info("withdraw ", "send coins to your withdraw address", cmds=["withdraw"]) @command("withdraw", require_args=2, allow_private=True) def handle_withdraw(self, msg, cmd): if not self.check_login(msg.prefix, msg.args[0]): @@ -132,7 +132,7 @@ class CryptoWallet(ModuleBase): self.bot.act_PRIVMSG(msg.args[0], "{}: .withdraw: Transaction create failed. Maybe the transaction was too " "large for the network? Try a smaller increment.".format(msg.prefix.nick)) - @info("send send coins elsewhere", cmds=["send"]) + @info("send ", "send coins elsewhere", cmds=["send"]) @command("send", require_args=3, allow_private=True) def handle_send(self, msg, cmd): if not self.check_login(msg.prefix, msg.args[0]): @@ -217,7 +217,7 @@ class CryptoWallet(ModuleBase): self.bot.act_PRIVMSG(msg.args[0], "{}: uh-oh, something went wrong doing that." .format(msg.prefix.nick)) - @info("getaddr get deposit address", cmds=["getaddr"]) + @info("getaddr ", "get deposit address", cmds=["getaddr"]) @command("getaddr", require_args=1, allow_private=True) def handle_getaddr(self, msg, cmd): if not self.check_login(msg.prefix, msg.args[0]): @@ -237,7 +237,7 @@ class CryptoWallet(ModuleBase): self.bot.act_PRIVMSG(msg.args[0], "{}: your {} deposit address is: {}" .format(msg.prefix.nick, cmd.args[0].upper(), walletaddr)) - @info("curinfo list supported coins", cmds=["curinfo"]) + @info("curinfo", "list supported coins", cmds=["curinfo"]) @command("curinfo", allow_private=True) def handle_curinfo(self, msg, cmd): attr, rpc = self.getMods() diff --git a/pyircbot/modules/DuckHunt.py b/pyircbot/modules/DuckHunt.py index 47d9d0b..adf6e04 100755 --- a/pyircbot/modules/DuckHunt.py +++ b/pyircbot/modules/DuckHunt.py @@ -29,7 +29,7 @@ class DuckHunt(ModuleBase): self.startHunt() - @info("huntscore show your duckhunt score", cmds=["huntscore"]) + @info("huntscore", "show your duckhunt score", cmds=["huntscore"]) @command("huntscore", allow_private=True) def hunt(self, msg, cmd): scores = self.loadScores() @@ -61,7 +61,7 @@ class DuckHunt(ModuleBase): (prime, runts, shots, misses)) # self.bot.act_PRIVMSG(fromWho, "More info & highscores: http://duckhunt.xmopx.net/") - @info("shoot shoot active targets", cmds=["shoot"]) + @info("shoot", "shoot active targets", cmds=["shoot"]) @command("shoot") def cmd_shoot(self, msg, args): if self.isDuckOut: diff --git a/pyircbot/modules/Inventory.py b/pyircbot/modules/Inventory.py index e3aba4a..b02a4e7 100755 --- a/pyircbot/modules/Inventory.py +++ b/pyircbot/modules/Inventory.py @@ -33,7 +33,7 @@ class Inventory(ModuleBase): ) ;""") c.close() - @info("have give the bot an item", cmds=["have"]) + @info("have ", "give the bot an item", cmds=["have"]) @command("have") def checkInv(self, msg, cmd): if len(cmd.args) < 1: @@ -57,7 +57,7 @@ class Inventory(ModuleBase): self.bot.act_PRIVMSG(msg.args[0], self.config["recv_msg"] % {"item": newItem, "adjective": "these " if newItem[-1:] == "s" else "this "}) - @info("inventory show the bot's inventory", cmds=["inventory", "inv"]) + @info("inventory", "show the bot's inventory", cmds=["inventory", "inv"]) @command("inventory", "inv") def cmd_inv(self, msg, cmd): inv = self.getinventory() diff --git a/pyircbot/modules/LMGTFY.py b/pyircbot/modules/LMGTFY.py index 882b041..51d9464 100644 --- a/pyircbot/modules/LMGTFY.py +++ b/pyircbot/modules/LMGTFY.py @@ -15,7 +15,7 @@ BASE_URL = "http://lmgtfy.com/?q=" class LMGTFY(ModuleBase): - @info("lmgtfy display a condescending internet query", cmds=["lmgtfy"]) + @info("lmgtfy ", "display a condescending internet query", cmds=["lmgtfy"]) @command("lmgtfy", require_args=True) def handleMessage(self, msg, cmd): link = self.createLink(cmd.args_str) diff --git a/pyircbot/modules/ModInfo.py b/pyircbot/modules/ModInfo.py index 482b88c..11faaca 100644 --- a/pyircbot/modules/ModInfo.py +++ b/pyircbot/modules/ModInfo.py @@ -29,49 +29,70 @@ class info(object): command has the alias "rtfm" :type cmds: list """ - def __init__(self, docstring, cmds=None): + def __init__(self, cmdspec, docstring, cmds=None): + self.cmdspec = cmdspec self.docstring = docstring - self.commands = cmds or [] + self.aliases = cmds or [] def __call__(self, func): if hasattr(func, "irchelp"): - func.irchelp.append(self.docstring) + func.irchelp.append(self) else: - setattr(func, "irchelp", [self.docstring]) - - if hasattr(func, "irchelpc"): - func.irchelpc.append(self.commands) - else: - setattr(func, "irchelpc", [self.commands]) - + setattr(func, "irchelp", [self]) return func class ModInfo(ModuleBase): - @info("help [command] show the manual for all or [commands]", cmds=["help"]) + @info("help [command]", "show the manual for all or [commands]", cmds=["help"]) @command("help") def cmd_help(self, msg, cmd): """ Get help on a command """ if cmd.args: - for modname, module, helptext, helpcommands in self.iter_modules(): - if cmd.args[0] in ["{}{}".format(command.prefix, i) for i in helpcommands]: - self.bot.act_PRIVMSG(msg.args[0], "RTFM: {}: {}".format(cmd.args[0], helptext)) + for modname, module, cmdspec, docstring, aliases in self.iter_modules(): + if cmd.args[0] in ["{}{}".format(command.prefix, i) for i in aliases]: + self.bot.act_PRIVMSG(msg.args[0], "RTFM: {}: ({}{}) {}" + .format(cmd.args[0], command.prefix, cmdspec, docstring)) else: - for modname, module, helptext, helpcommands in self.iter_modules(): - self.bot.act_PRIVMSG(msg.args[0], "{}: {}{}".format(modname, command.prefix, helptext)) + rows = [] + for modname, module, cmdspec, docstring, aliases in self.iter_modules(): + rows.append((modname, command.prefix + cmdspec, docstring)) + rows.sort(key=lambda item: item[0] + item[1]) + self.send_columnized(msg.args[0], rows) - @info("helpindex show a short list of all commands", cmds=["helpindex"]) + def send_columnized(self, channel, rows): + if not rows: + return + widths = [] + # Find how many col widths we must calculate + for _ in rows[0]: + widths.append(0) + # Find widest value per col + for row in rows: + for col, value in enumerate(row): + print(col, value) + vlen = len(value) + if vlen > widths[col]: + widths[col] = vlen + # Print each row + for row in rows: + message = "" + for colid, col in enumerate(row): + message += str(col) + message += (" " * (widths[colid] - len(col) + 1)) + self.bot.act_PRIVMSG(channel, message) + + @info("helpindex", "show a short list of all commands", cmds=["helpindex"]) @command("helpindex") def cmd_helpindex(self, msg, cmd): """ Short index of commands """ commands = [] - for modname, module, helptext, helpcommands in self.iter_modules(): - commands += ["{}{}".format(command.prefix, i) for i in helpcommands] + for modname, module, cmdspec, docstring, aliases in self.iter_modules(): + commands += ["{}{}".format(command.prefix, i) for i in aliases] self.bot.act_PRIVMSG(msg.args[0], "{}: commands: {}".format(msg.prefix.nick, ", ".join(commands))) @@ -80,12 +101,12 @@ class ModInfo(ModuleBase): Iterator that cycles through module methods that are tagged with help information. The iterator yields tuples of: - (module_name, module_object, helptext, command_list) + (module_name, module_object, command_spec, command_help, command_list) """ for modname, module in self.bot.moduleInstances.items(): for attr_name in dir(module): attr = getattr(module, attr_name) if callable(attr) and hasattr(attr, "irchelp"): - for cmdhelp, cmdaliases in zip(getattr(attr, "irchelp"), getattr(attr, "irchelpc")): - yield (modname, module, cmdhelp, cmdaliases, ) + for cmdinfo in attr.irchelp: + yield (modname, module, cmdinfo.cmdspec, cmdinfo.docstring, cmdinfo.aliases) raise StopIteration() diff --git a/pyircbot/modules/NFLLive.py b/pyircbot/modules/NFLLive.py index 360d220..67ae89a 100644 --- a/pyircbot/modules/NFLLive.py +++ b/pyircbot/modules/NFLLive.py @@ -20,7 +20,7 @@ class NFLLive(ModuleBase): self.cache = None self.cacheAge = 0 - @info("nfl show nfl schedule & score", cmds=["nfl"]) + @info("nfl", "show nfl schedule & score", cmds=["nfl"]) @command("nfl") def nflitup(self, message, cmd): games = self.getNflGamesCached() diff --git a/pyircbot/modules/NickUser.py b/pyircbot/modules/NickUser.py index a7724bd..8ba108e 100755 --- a/pyircbot/modules/NickUser.py +++ b/pyircbot/modules/NickUser.py @@ -36,9 +36,9 @@ class NickUser(ModuleBase): else: self.handlePm(msg.prefix, msg.trailing) - @info("setpass [] set or change password", cmds=["setpass"]) - @info("login authenticate with the bot", cmds=["login"]) - @info("logout log out of the bot", cmds=["logout"]) + @info("setpass [] ", "set or change password", cmds=["setpass"]) + @info("login ", "authenticate with the bot", cmds=["login"]) + @info("logout", "log out of the bot", cmds=["logout"]) def handlePm(self, prefix, trailing): cmd = messageHasCommand(".setpass", trailing) if cmd: diff --git a/pyircbot/modules/RandQuote.py b/pyircbot/modules/RandQuote.py index 499bc63..6201ec8 100755 --- a/pyircbot/modules/RandQuote.py +++ b/pyircbot/modules/RandQuote.py @@ -33,7 +33,7 @@ class RandQuote(ModuleBase): ) ;""") c.close() - @info("randquote print a random quote", cmds=["randquote", "randomquote", "rq"]) + @info("randquote", "print a random quote", cmds=["randquote", "randomquote", "rq"]) @command("randquote", "randomquote", "rq") def fetchquotes(self, msg, cmd): c = self.db.query("SELECT * FROM `chat` ORDER BY RANDOM() LIMIT 1;") diff --git a/pyircbot/modules/Remind.py b/pyircbot/modules/Remind.py index 26a114e..4d870a5 100644 --- a/pyircbot/modules/Remind.py +++ b/pyircbot/modules/Remind.py @@ -106,7 +106,7 @@ class Remind(ModuleBase): def ondisable(self): self.disabled = True - @info("remind