Auto detection of the arguments of commands

This commit is contained in:
Shadow15510 2023-06-12 15:52:51 +02:00
parent 9c4b6916be
commit 9ab3568e6a
4 changed files with 183 additions and 42 deletions

View File

@ -1,32 +1,64 @@
from random import choice
import re
import requests
import time
from irc_api import api
from irc_api.api import auto_help
@api.on(lambda m: "au revoir glados" in m.text.lower())
def greetings_bye(bot, msg, *args):
bot.send(msg.to, f"Au revoir {msg.author}")
@api.on(lambda m: isinstance(re.match(r"(.*)(bonjour|coucou|salut|hey|hello|hi|yo) glados(.*)", m.text, re.IGNORECASE), re.Match))
def greetings_hello(bot, msg):
"""Dit bonjour à l'utilisateur"""
greetings = ("Bonjour", "Coucou", "Salut", "Hey", "Hello", "Hi", "Yo")
bot.send(msg.to, f"{choice(greetings)} {msg.author}.")
@api.on(lambda m: isinstance(re.match(r"(.*)(au revoir|à plus|a\+|à toute|bye|see you|see you soon) glados(.*)", m.text, re.IGNORECASE), re.Match))
def greetings_bye(bot, msg):
"""Dit au revoir à l'utilisateur."""
greetings = ("Au revoir", "À plus", "À toute", "Bye bye", "See you soon")
bot.send(msg.to, f"{choice(greetings)} {msg.author}.")
@api.on(lambda m: isinstance(re.match(r"(.*)(merci|merci beaucoup|thx|thanks|thank you) glados(.*)", m.text, re.IGNORECASE), re.Match))
def thanks(bot, msg):
"""Répond aux remerciements de l'utilisateur."""
thanks_choice = ("Mais je vous en prie", "Tout le plaisir est pour moi", "C'est tout naturel", "Je n'en ferais rien")
bot.send(msg.to, f"{choice(thanks_choice)}, {msg.author}")
@api.on(lambda m: isinstance(re.match(r"(.*)quelle heure(.*)?", m.text, re.IGNORECASE), re.Match))
def hour(bot, msg):
"""Donne l'heure actuelle"""
now = time.strftime("%Hh%M", time.localtime())
bot.send(msg.to, f"Il est très exactement {now}.")
@api.command("wiki", desc="wiki <recherche> [limite=1]\nFait une recherche wikipedia.")
def wiki(bot, msg, text: str, limit: int=1):
session = requests.Session()
params = {
'action': 'opensearch',
'search': text,
'limit': limit,
'namespace': 0,
'redirects': 'resolve',
'format': 'json'
}
response = session.get(url="https://fr.wikipedia.org/w/api.php", params=params, timeout=(4, 12)).json()
if len(response[1]) == 0:
bot.send(msg.to, f"Aucun résultat trouvé pour la recherche : {text}.")
else:
bot.send(msg.to, f"{len(response[1])} résultat{('', 's')[limit > 1]} pour la recherche : '{text}'.")
for name, link in zip(response[1], response[3]):
bot.send(msg.to, f" {name} : {link}")
@api.channel("#glados")
@api.on(
event=lambda m: "bonjour glados" in m.text.lower(),
desc="Réagis au 'bonjour glados' uniquement si le message est envoyé depuis le channel "\
"#glados."
)
def greetings_hello(bot, msg, *args):
bot.send(msg.to, f"Bonjour à toi")
@api.command("test")
def test(bot, msg, *args):
"""Test de module de fonction."""
bot.send(msg.to, f"arguments : {args}")
@api.channel("#glados")
def react_on_glados(bot, msg, *args):
"""Répète le dernier message envoyé sur #glados."""
if bot.history.get()[-1].author == msg.author:
def spam_on_glados(bot, msg):
"""Détecte les monologues sur #glados."""
if len(bot.history) > 2 and bot.history.get()[-2].author == msg.author:
bot.counter += 1
else:
bot.counter = 1

View File

@ -19,14 +19,18 @@ def command(name, desc=""):
def on(event, desc=""):
def decorator(func):
return Command(
name=func.__name__,
func=func,
events=[event],
desc=desc,
cmnd_type=0
)
def decorator(func_or_cmnd):
if isinstance(func_or_cmnd, Command):
func_or_cmnd.events.append(event)
return func_or_cmnd
else:
return Command(
name=func_or_cmnd.__name__,
func=func_or_cmnd,
events=[event],
desc=desc,
cmnd_type=0
)
return decorator
@ -151,7 +155,21 @@ class Bot:
for callback in self.callbacks.values():
if not False in [event(message) for event in callback.events]:
logging.info("matched %s", callback.name)
callback(message, *parse(message.text)[callback.cmnd_type:])
# @api.on
if callback.cmnd_type == 0:
callback(message)
# @api.command
if callback.cmnd_type == 1:
args = check_args(callback.func, *parse(message.text)[1:])
if isinstance(args, list):
callback(message, *args)
else:
self.send(
message.to,
"Erreur : les arguments donnés ne correspondent pas."
)
def send(self, target: str, message: str):
"""Send a message to the specified target (channel or user).
@ -163,7 +181,8 @@ class Bot:
message : str
The content of the message to send.
"""
self.irc.send(f"PRIVMSG {target} :{message}")
for line in message.splitlines():
self.irc.send(f"PRIVMSG {target} :{line}")
def add_command(self, command, add_to_help=False):
command.bot = self
@ -197,20 +216,21 @@ class Bot:
@command("aide")
def auto_help(bot, msg, *args):
def auto_help(bot, msg, fct_name: str=""):
"""Aide des commandes disponibles."""
if args and args[0] in bot.commands_help.keys():
cmnd = bot.commands_help[args[0]]
if fct_name and fct_name in bot.commands_help.keys():
cmnd = bot.commands_help[fct_name]
if cmnd.cmnd_type == 1:
bot.send(msg.to, f"Aide sur la commande : {bot.prefix}{args[0]}")
bot.send(msg.to, f"Aide sur la commande : {bot.prefix}{fct_name}")
else:
bot.send(msg.to, f"Aide sur la commande : {args[0]}")
bot.send(msg.to, f"Aide sur la commande : {fct_name}")
bot.send(msg.to, f" {bot.commands_help[args[0]].desc}")
for line in bot.commands_help[fct_name].desc.splitlines():
bot.send(msg.to, f" {line}")
else:
bot.send(msg.to, f"Liste des commandes ({PREFIX}aide <cmnd> pour plus d'info)")
for cmnd_name in bot.commands_help.keys():
bot.send(msg.to, f" - {cmnd.name}")
bot.send(msg.to, f" - {cmnd_name}")
def parse(message):
@ -224,3 +244,43 @@ def parse(message):
else:
args_to_return.append(match)
return args_to_return
def convert(data, new_type, default=None):
try:
return new_type(data)
except:
return default
def check_args(func, *input_args):
# args[0] = (type, is_optionnal)
defaults = getattr(func, "__defaults__")
if not defaults:
defaults = []
annotations = getattr(func, "__annotations__")
if not annotations:
return []
required_args = len(annotations) - len(defaults)
check_args = []
for index, arg_type in enumerate(annotations.values()):
if index + 1 > required_args:
check_args.append((arg_type, defaults[index - required_args]))
else:
check_args.append((arg_type, None))
if len(input_args) < required_args:
return None
converted_args = []
for index, arg in enumerate(check_args):
if len(input_args) > index:
converted_args.append(convert(input_args[index], *check_args[index]))
else:
converted_args.append(check_args[index][1])
return converted_args

49
irc_api/test.py Normal file
View File

@ -0,0 +1,49 @@
def convert(data, new_type, default=None):
try:
return new_type(data)
except:
return default
def check_args(bot, func, *input_args):
# args[0] = (type, is_optionnal)
defaults = getattr(func, "__defaults__")
if not defaults:
defaults = []
annotations = getattr(func, "__annotations__")
if not annotations:
return []
required_args = len(annotations) - len(defaults)
check_args = []
for index, arg_type in enumerate(annotations.values()):
if index + 1 > required_args:
check_args.append((arg_type, defaults[index - required_args]))
else:
check_args.append((arg_type, None))
if len(input_args) < required_args:
# bot.send("Erreur : argument manquant")
return
converted_args = []
for index, arg in enumerate(check_args):
if len(input_args) > index:
converted_args.append(convert(input_args[index], *check_args[index]))
else:
converted_args.append(check_args[index][1])
return converted_args
def foo(bot, msg, a: str, b: int=1):
return None
print(check_args(None, foo, "3"))
print(check_args(None, foo, "3", "5"))
print(check_args(None, foo, "3", "test"))
print(check_args(None, foo, "3", "5", "2", "5"))

View File

@ -13,7 +13,7 @@ import re
from irc_api import api
import glados_cmnds as gcmnds
import glados_cmnds as gv4_cmnds
import fun_cmnds as fcmnds
from secrets import USER, PASSWORD
@ -28,8 +28,8 @@ class MyBot(api.Bot):
glados = MyBot(
(USER, PASSWORD),
('irc.planet-casio.com', 6697),
["#general", "#glados"],
gcmnds, fcmnds,
["#glados"],
gv4_cmnds,
prefix="!",
)