Можно сделать самому.
Смотри, ключевая возможность в большинстве библиотек для ботов - это регистрация реакции бота на события. И чаще всего она выполняется декоратором, типа @bot.command в discord.py или его эквивалент в aiogram.
Но что такое декоратор? Если он не имеет параметров, то тогда
@some_decorator
def some_func():
pass
это то же самое, что и
def some_func():
pass
some_func = some_decorator(some_func)
Для декораторов с параметрами чуть-чуть сложнее
@some_decorator(params)
def some_func():
pass
превратится в
def some_func():
pass
wrapper = some_decorator(params)
some_func = wrapper(some_func)
Отсюда вывод. Декоратор - это функция, и его можно сохранять в переменные, вызывать и так далее.
Тогда можно сделать такой трюк: написать декоратор-прокси, который запоминает, что за метод мы декорируем, и чем. Примерно так:
def proxy(storage, *args, **kwargs):
def wrapper(func):
storage.append((func.__name__, args, kwargs))
return func
return wrapper
И применять его примерно так:
class MyCustomCog:
methods = []
def __init__(self, bot):
#задача конструктора - прочитать список отмеченных методов класса,
#и отдекорировать методы своего экземпляра класса (не одно и то же)
for fn, args, kwargs in self.methods:
#а тут вызываем декоратор вручную
#что там вместо bot.event? можно сделать несколько прокси, или добавить еще один параметр
decorator = bot.event(*args, **kwargs)
decorator(getattr(self, fn)) #теперь бот знает про наши обработчики событий
#декоратор-прокси запоминает все декорированые методы в список methods
#это можно реализовать и по другому, не суть. Главное, что мы запоминаем,
#с какими параметрами потом вызывать декоратор реального бота - всё, что после methods
@proxy(methods, "параметры", for="декоратора бота")
async def some_handler(self, params):
pass #обработчик того или иного события
Эту логику можно спрятать в базовый класс, и наследоваться от него, чтоб не повторяться по сто раз. Да и сам proxy() можно сделать методом этого базового класса.