Search code examples
pythonbotstelegramtelegram-botpython-telegram-bot

Python Telegram Bot – How to pass in decorated callback functions to BaseHandlers?


I am having trouble trying to pass in a decorated callback function to any derivatives of BaseHandler.

I simplified the code below:

def sample_func(update: Update, context: ContextTypes.DEFAULT_TYPE):
    # return some boolean value here


async def sample_decorator(func):
    async def wrapper(*args, **kwargs):
        if sample_func(*args, **kwargs):
            await func()

    return wrapper


@sample_decorator
async def decorated_function(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text('Some text here.')


def bot_start():
    app = Application.builder().token(TOKEN).build()
    app.add_handler(CommandHandler('test', decorated_function))

    . . .

    app.run_polling(poll_interval=3)

I get that I'm passing in a coroutine object, but I can't think of a way to pass in a callable object while keeping the decorator. Simply wrapping the decorated_function wouldn't work either.


Solution

  • Note that

    @sample_decorator
    async def decorated_function(update: Update, context: ContextTypes.DEFAULT_TYPE):
        await update.message.reply_text('Some text here.')
    

    is basically equivalent to

    async def _helper_function(update: Update, context: ContextTypes.DEFAULT_TYPE):
        await update.message.reply_text('Some text here.')
    
    decorated_function = sample_decorator(_helper_function)
    

    So you want sample_decorator to return a coroutine function, but you don't need sample_decorator to itself be a coroutine function. Removing the async from the definition of sample_decorator should do the trick.