[Context] Implement LionContext

Need to append a Text to all bot replies to ask people to !vote
- Implement LionContext
- Implement Callback handler to enable Modules intercept cmdClient.Context.Utils() (attr calls)
This commit is contained in:
Harsha Raghu
2022-01-14 18:52:51 +05:30
parent a2fcdf075f
commit 437adf87e4
3 changed files with 98 additions and 9 deletions

48
bot/LionContext.py Normal file
View File

@@ -0,0 +1,48 @@
import datetime
import discord
from cmdClient import Context
from cmdClient.logger import log
reply_callbacks: list = [] # TODO Extend to all cmdClient.Context.Utils to give flexibility to modules
class LionContext(Context):
"""
Subclass to allow easy attachment of custom hooks and structure to contexts.
"""
def __init__(self, client, **kwargs):
super().__init__(client, **kwargs)
@classmethod
def util(self, util_func):
"""
Decorator to make a utility function available as a Context instance method
"""
log('added util_function: ' + util_func.__name__)
def util_fun_wrapper(*args, **kwargs):
[args, kwargs] = self.util_pre(util_func, *args, **kwargs)
return util_func(*args, **kwargs)
util_fun_wrapper.__name__ = util_func.__name__ # Hack
super().util(util_fun_wrapper)
@classmethod
def util_pre(self, util_func, *args, **kwargs):
if util_func.__name__ == 'reply':
for cb in reply_callbacks:
[args, kwargs] = cb(util_func, *args, **kwargs) # Nesting handlers. Note: args and kwargs are mutable
return [args, kwargs]
def register_reply_callback(func):
reply_callbacks.append(func)
def unregister_reply_callback(func):
reply_callbacks.remove(func)

View File

@@ -3,7 +3,7 @@ from cmdClient.cmdClient import cmdClient
from .config import conf from .config import conf
from .sharding import shard_number, shard_count from .sharding import shard_number, shard_count
from LionContext import LionContext
# Initialise client # Initialise client
owners = [int(owner) for owner in conf.bot.getlist('owners')] owners = [int(owner) for owner in conf.bot.getlist('owners')]
@@ -14,6 +14,7 @@ client = cmdClient(
owners=owners, owners=owners,
intents=intents, intents=intents,
shard_id=shard_number, shard_id=shard_number,
shard_count=shard_count shard_count=shard_count,
baseContext=LionContext
) )
client.conf = conf client.conf = conf

View File

@@ -1,8 +1,10 @@
import asyncio import asyncio
import discord import discord
from cmdClient import Context from LionContext import LionContext
from cmdClient.lib import UserCancelled, ResponseTimedOut from cmdClient.lib import UserCancelled, ResponseTimedOut
import datetime
from cmdClient import lib
from .lib import paginate_list from .lib import paginate_list
# TODO: Interactive locks # TODO: Interactive locks
@@ -19,7 +21,7 @@ async def discord_shield(coro):
pass pass
@Context.util @LionContext.util
async def cancellable(ctx, msg, add_reaction=True, cancel_message=None, timeout=300): async def cancellable(ctx, msg, add_reaction=True, cancel_message=None, timeout=300):
""" """
Add a cancellation reaction to the given message. Add a cancellation reaction to the given message.
@@ -62,7 +64,7 @@ async def cancellable(ctx, msg, add_reaction=True, cancel_message=None, timeout=
return task return task
@Context.util @LionContext.util
async def listen_for(ctx, allowed_input=None, timeout=120, lower=True, check=None): async def listen_for(ctx, allowed_input=None, timeout=120, lower=True, check=None):
""" """
Listen for a one of a particular set of input strings, Listen for a one of a particular set of input strings,
@@ -114,7 +116,7 @@ async def listen_for(ctx, allowed_input=None, timeout=120, lower=True, check=Non
return message return message
@Context.util @LionContext.util
async def selector(ctx, header, select_from, timeout=120, max_len=20): async def selector(ctx, header, select_from, timeout=120, max_len=20):
""" """
Interactive routine to prompt the `ctx.author` to select an item from a list. Interactive routine to prompt the `ctx.author` to select an item from a list.
@@ -214,7 +216,7 @@ async def selector(ctx, header, select_from, timeout=120, max_len=20):
return result return result
@Context.util @LionContext.util
async def pager(ctx, pages, locked=True, start_at=0, add_cancel=False, **kwargs): async def pager(ctx, pages, locked=True, start_at=0, add_cancel=False, **kwargs):
""" """
Shows the user each page from the provided list `pages` one at a time, Shows the user each page from the provided list `pages` one at a time,
@@ -371,7 +373,7 @@ async def _pager(ctx, out_msg, pages, locked, start_at, add_cancel, **kwargs):
pass pass
@Context.util @LionContext.util
async def input(ctx, msg="", timeout=120): async def input(ctx, msg="", timeout=120):
""" """
Listen for a response in the current channel, from ctx.author. Listen for a response in the current channel, from ctx.author.
@@ -413,7 +415,7 @@ async def input(ctx, msg="", timeout=120):
return result return result
@Context.util @LionContext.util
async def ask(ctx, msg, timeout=30, use_msg=None, del_on_timeout=False): async def ask(ctx, msg, timeout=30, use_msg=None, del_on_timeout=False):
""" """
Ask ctx.author a yes/no question. Ask ctx.author a yes/no question.
@@ -459,3 +461,41 @@ async def ask(ctx, msg, timeout=30, use_msg=None, del_on_timeout=False):
if result in ["n", "no"]: if result in ["n", "no"]:
return 0 return 0
return 1 return 1
# this reply() will be overide baseContext's reply with LionContext's, whcih can
# hook pre_execution of any util.
# Using this system, Module now have much power to change Context's utils
@LionContext.util
async def reply(ctx, content=None, allow_everyone=False, **kwargs):
"""
Helper function to reply in the current channel.
"""
if not allow_everyone:
if content:
content = lib.sterilise_content(content)
message = await ctx.ch.send(content=content, **kwargs)
ctx.sent_messages.append(message)
return message
# this reply() will be overide baseContext's reply
@LionContext.util
async def error_reply(ctx, error_str):
"""
Notify the user of a user level error.
Typically, this will occur in a red embed, posted in the command channel.
"""
embed = discord.Embed(
colour=discord.Colour.red(),
description=error_str,
timestamp=datetime.datetime.utcnow()
)
try:
message = await ctx.ch.send(embed=embed)
ctx.sent_messages.append(message)
return message
except discord.Forbidden:
message = await ctx.reply(error_str)
ctx.sent_messages.append(message)
return message