Check command keywords using keyword help (passed in @hook)

This commit is contained in:
nemunaire 2015-11-01 12:35:46 +01:00
parent 70b52d5567
commit ea9829b341
11 changed files with 189 additions and 5 deletions

View file

@ -61,6 +61,8 @@ def reload():
import nemubot.exception import nemubot.exception
imp.reload(nemubot.exception) imp.reload(nemubot.exception)
nemubot.exception.reload()
import nemubot.hooks import nemubot.hooks
imp.reload(nemubot.hooks) imp.reload(nemubot.hooks)

View file

@ -101,7 +101,7 @@ class Bot(threading.Thread):
if s == "in_Command" and (h.name is not None or h.regexp is not None) and h.is_matching(msg.args[0][1:]): if s == "in_Command" and (h.name is not None or h.regexp is not None) and h.is_matching(msg.args[0][1:]):
if h.help_usage: if h.help_usage:
lp = ["\x03\x02%s%s\x03\x02: %s" % (msg.args[0], (" " + k if k is not None else ""), h.help_usage[k]) for k in h.help_usage] lp = ["\x03\x02%s%s\x03\x02: %s" % (msg.args[0], (" " + k if k is not None else ""), h.help_usage[k]) for k in h.help_usage]
jp = ["\x03\x02@%s\x03\x02: %s" % (k, h.keywords[k]) for k in h.keywords] jp = h.keywords.help()
return res.append_message(lp + ([". Moreover, you can provides some optional parameters: "] + jp if len(jp) else []), title="Usage for command %s from module %s" % (msg.args[0], module)) return res.append_message(lp + ([". Moreover, you can provides some optional parameters: "] + jp if len(jp) else []), title="Usage for command %s from module %s" % (msg.args[0], module))
elif h.help: elif h.help:
return res.append_message("Command %s from module %s: %s" % (msg.args[0], module, h.help)) return res.append_message("Command %s from module %s: %s" % (msg.args[0], module, h.help))

View file

@ -32,3 +32,10 @@ class IMException(Exception):
from nemubot.message import Text from nemubot.message import Text
return Text(*self.args, return Text(*self.args,
server=msg.server, to=msg.to_response) server=msg.server, to=msg.to_response)
def reload():
import imp
import nemubot.exception.Keyword
imp.reload(nemubot.exception.printer.IRC)

View file

@ -0,0 +1,23 @@
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2015 Mercier Pierre-Olivier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from nemubot.exception import IMException
class KeywordException(IMException):
def __init__(self, message):
super(KeywordException, self).__init__(message)

View file

@ -38,5 +38,9 @@ def reload():
imp.reload(nemubot.hooks.message) imp.reload(nemubot.hooks.message)
Message = nemubot.hooks.message.Message Message = nemubot.hooks.message.Message
import nemubot.hooks.keywords
imp.reload(nemubot.hooks.keywords)
nemubot.hooks.keywords.reload()
import nemubot.hooks.manager import nemubot.hooks.manager
imp.reload(nemubot.hooks.manager) imp.reload(nemubot.hooks.manager)

View file

@ -50,8 +50,12 @@ class Abstract:
self.end_call = end_call self.end_call = end_call
def check(self, data1):
return True
def match(self, data1, server): def match(self, data1, server):
return NotImplemented return True
def run(self, data1, *args): def run(self, data1, *args):
@ -60,8 +64,11 @@ class Abstract:
from nemubot.exception import IMException from nemubot.exception import IMException
self.times -= 1 self.times -= 1
ret = None
try: try:
ret = call_game(self.call, data1, self.data, *args) if self.check(data1):
ret = call_game(self.call, data1, self.data, *args)
except IMException as e: except IMException as e:
ret = e.fill_response(data1) ret = e.fill_response(data1)
finally: finally:

View file

@ -0,0 +1,36 @@
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2015 Mercier Pierre-Olivier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from nemubot.exception.keyword import KeywordException
from nemubot.hooks.keywords.abstract import Abstract
class NoKeyword(Abstract):
def check(self, mkw):
if len(mkw):
raise KeywordException("This command doesn't take any keyword arguments.")
return super().check(mkw)
def reload():
import imp
import nemubot.hooks.keywords.abstract
imp.reload(nemubot.hooks.keywords.abstract)
import nemubot.hooks.keywords.dict
imp.reload(nemubot.hooks.keywords.dict)

View file

@ -0,0 +1,35 @@
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2015 Mercier Pierre-Olivier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class Abstract:
def __init__(self):
pass
def check(self, mkw):
"""Check that all given message keywords are valid
Argument:
mkw -- dictionnary of keywords present in the message
"""
assert type(mkw) is dict, mkw
return True
def help(self):
return ""

View file

@ -0,0 +1,59 @@
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2015 Mercier Pierre-Olivier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from nemubot.exception.keyword import KeywordException
from nemubot.hooks.keywords.abstract import Abstract
from nemubot.tools.human import guess
class Dict(Abstract):
def __init__(self, d):
super().__init__()
self.d = d
@property
def chk_noarg(self):
if not hasattr(self, "_cache_chk_noarg"):
self._cache_chk_noarg = [k for k in self.d if "=" not in k]
return self._cache_chk_noarg
@property
def chk_args(self):
if not hasattr(self, "_cache_chk_args"):
self._cache_chk_args = [k.split("=", 1)[0] for k in self.d if "=" in k]
return self._cache_chk_args
def check(self, mkw):
for k in mkw:
if (mkw[k] and k not in self.chk_args) or (not mkw[k] and k not in self.chk_noarg):
if mkw[k] and k in self.chk_noarg:
raise KeywordException("Keyword %s doesn't take value." % k)
elif not mkw[k] and k in self.chk_args:
raise KeywordException("Keyword %s requires a value." % k)
else:
ch = [c for c in guess(k, self.d)]
raise KeywordException("Unknown keyword %s." % k + (" Did you mean: " + ", ".join(ch) + "?" if len(ch) else ""))
return super().check(mkw)
def help(self):
return ["\x03\x02@%s\x03\x02: %s" % (k, self.d[k]) for k in self.d]

View file

@ -17,6 +17,9 @@
import re import re
from nemubot.hooks.abstract import Abstract from nemubot.hooks.abstract import Abstract
from nemubot.hooks.keywords import NoKeyword
from nemubot.hooks.keywords.abstract import Abstract as AbstractKeywords
from nemubot.hooks.keywords.dict import Dict as DictKeywords
import nemubot.message import nemubot.message
@ -25,16 +28,19 @@ class Message(Abstract):
"""Class storing hook information, specialized for a generic Message""" """Class storing hook information, specialized for a generic Message"""
def __init__(self, call, name=None, regexp=None, channels=list(), def __init__(self, call, name=None, regexp=None, channels=list(),
server=None, help=None, help_usage=dict(), keywords=dict(), server=None, help=None, help_usage=dict(), keywords=NoKeyword(),
**kargs): **kargs):
Abstract.__init__(self, call=call, **kargs) Abstract.__init__(self, call=call, **kargs)
if isinstance(keywords, dict):
keywords = DictKeywords(keywords)
assert regexp is None or type(regexp) is str, regexp assert regexp is None or type(regexp) is str, regexp
assert channels is None or type(channels) is list, channels assert channels is None or type(channels) is list, channels
assert server is None or type(server) is str, server assert server is None or type(server) is str, server
assert type(help_usage) is dict, help_usage assert type(help_usage) is dict, help_usage
assert type(keywords) is dict, keywords assert isinstance(keywords, AbstractKeywords), keywords
self.name = str(name) if name is not None else None self.name = str(name) if name is not None else None
self.regexp = regexp self.regexp = regexp
@ -53,6 +59,10 @@ class Message(Abstract):
) )
def check(self, msg):
return not hasattr(msg, "kwargs") or self.keywords.check(msg.kwargs)
def match(self, msg, server=None): def match(self, msg, server=None):
if not isinstance(msg, nemubot.message.abstract.Abstract): if not isinstance(msg, nemubot.message.abstract.Abstract):
return True return True

View file

@ -65,6 +65,7 @@ setup(
'nemubot.event', 'nemubot.event',
'nemubot.exception', 'nemubot.exception',
'nemubot.hooks', 'nemubot.hooks',
'nemubot.hooks.keywords',
'nemubot.message', 'nemubot.message',
'nemubot.message.printer', 'nemubot.message.printer',
'nemubot.prompt', 'nemubot.prompt',