Как использовать пользовательские декораторы в python-socketio server?

#python #python-asyncio #flask-socketio #python-socketio

#python #python-asyncio #flask-socketio #python-socketio

Вопрос:

Я хотел бы использовать некоторые пользовательские декораторы в обработчиках событий, чтобы сделать работу с сеансами более удобной.

Вот мой обработчик событий без пользовательского декоратора:

 @sio.event
async def test(sid, data):
    async with sio.session(sid) as sess:
        room_id = sess["room_id"]
        print('test', room_id)
        await sio.emit("test", {'msg': 'msg'}, room=room_id)

 

Вот мое событие с пользовательским декоратором:

 import functools


async def sess_decorator(func):
    @functools.wraps(func)
    async def wrapper(sid, data, *args, **kwargs):
        async with sio.session(sid) as sess:
            return func(sid, data, sess, *args, **kwargs)
        logger.error(f'Failed to get sess.nsid: {sid}ndata: {data}')

    return wrapper


@sio.event
@sess_decorator
async def test(sid, data, sess):
     room_id = sess["room_id"]
     print('test', room_id)
     await sio.emit("test", {'msg': 'msg'}, room=room_id)

 

Проблема в том, что после применения @sess_decorator событие, похоже, вообще не срабатывает. И если я изменю порядок декораторов, он завершится ошибкой с последующей трассировкой перед вызовом моего декоратора:

 Traceback (most recent call last):
  File "/home/pata/.pyenv/versions/3.7.7/envs/cartel_env/lib/python3.7/site-packages/socketio/asyncio_server.py", line 476, in _handle_event_internal
    r = await server._trigger_event(data[0], namespace, sid, *data[1:])
  File "/home/pata/.pyenv/versions/3.7.7/envs/cartel_env/lib/python3.7/site-packages/socketio/asyncio_server.py", line 504, in _trigger_event
    ret = await self.handlers[namespace][event](*args)
TypeError: test() missing 1 required positional argument: 'sess'
 

Кажется, есть какая-то проблема с дизайном библиотеки? Есть ли какой-либо другой способ выполнить ту же логику?

Ответ №1:

У вас есть пара ошибок в том, как вы реализовали декоратор:

  • сам декоратор не должен быть асинхронной функцией
  • func аргумент — это исходная функция, которая является сопрограммой, поэтому ее следует ожидать

Декоратор с исправлениями выглядит следующим образом:

 def sess_decorator(func):
    @functools.wraps(func)
    async def wrapper(sid, data, *args, **kwargs):
        async with sio.session(sid) as sess:
            return await func(sid, data, sess, *args, **kwargs)
        logger.error(f'Failed to get sess.nsid: {sid}ndata: {data}')

    return wrapper
 

Комментарии:

1. Спасибо за ваш ответ и объяснение! Теперь это работает. Странно то, что python не дал никакой обратной трассировки.