Что нарушает протоколирование в AsyncWebsocketConsumer?

У меня есть проект Django, который использует Channels для связи через websocket, и я наткнулся на то, что, как мне кажется, может быть ошибкой, но я не уверен, поэтому я надеюсь, что кто-то, кто понимает это лучше, чем я, может помочь объяснить, что здесь происходит:

Сообщение об ошибке теста:

AssertionError: "INFO:websocket.camera_consumer:Doesn't work" not found in ['INFO:websocket.camera_consumer:Works']

Тест, который не удался:

class TestCameraConsumerTests(TransactionTestCase):
    async def test_fails(self):
        communicator = WebsocketCommunicator(TestConsumer.as_asgi(), '/ws/device')

        with self.assertLogs(f'websocket.camera_consumer', level=logging.INFO) as logs:
            await communicator.connect(timeout=10)

        await communicator.disconnect()
        self.assertIn(f"INFO:websocket.camera_consumer:Doesn't work", logs.output)

websocket.camera_consumer.py:

import logging
from channels.generic.websocket import AsyncWebsocketConsumer

def sync_function():
    pass

class TestConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await super().connect()

        logger = logging.getLogger(__name__)

        logger.info("Works")
        await sync_to_async(sync_function)()
        logger.info("Doesn't work")

Что я узнал за это время:

  • Перемещение вызова getLogger за пределы функции connect не исправляет ситуацию
  • .
  • Перемещение вызова super ниже вызова sync_to_async исправляет проблему
  • Удаление функции sync_to_async (и превращение sync_function в async) также исправляет ситуацию
  • .
  • Где-то в процессе вызова функции sync_to_async объект обработчика логгеров, который инжектирует assertLogs, удаляется, поэтому первое сообщение лога попадает в тест, а второе - нет
  • .
  • Я попытался проследить за вызовом sync_to_async, но не могу понять, как отслеживать объект логгера внутри цикла async (я все еще относительно новичок в коде async, поэтому не очень хорошо разбираюсь в том, как он работает под капотом).
Вернуться на верх