mode
mode copied to clipboard
Potential MethodQueue bug?
Checklist
- [X] I have included information about relevant versions
- [X] I have verified that the issue persists when using the
master
branch of Mode.
Steps to reproduce
- Define any simple async function
- Create a mode.threads.QueueServiceThread and call its start() method.
- Call the async function with service.
- Prepare a debugger with breakpoints at two locations:
-- The beginning of
MethodQueue
, currently line 331 ofmode/threads.py
-- Theif self._loop is None
block ofServiceBase
'sloop
@property
, currently line 146 ofmode/services.py
- Run with the debugger
- Observe first expected Breakpoint stop
- Resume execution
Expected behavior
The program should run to completion without stopping at the second breakpoint at all
Before proceeding to (7), notice that we have passed an explicit event loop argument. I do not expect to need to hit the second breakpoint before the program completes because the event loop is known at this point and I have no further Service initialization to do.
Actual behavior
Given that we have passed a loop argument explicitly to MethodQueue
, I would not expect to land in the second breakpoint, especially while the first breakpoint is still on the call stack. But on resuming after the first, expected breakpoint, we land in a second, unexpected stop, with MethodQueue
requesting the default event loop to satisfy its own None reference.
Reading the code carefully we can see that MethodQueue does not ever do anything with its EventLoop parameter--neither pass it to its own super.init() method, more to any of its child objects.
I imagine that this code should either not receive an EventLoop argument, or it should pass that argument to its own call to ServiceBase.init() before initializing its Queue and Event objects. I am not sure which solution would be preferred. Although the former seems more consistent with Python 3.8's deprecation of explicit EventLoop arguments, perhaps the latter would be more sensitive to compatibility with Python 3.6 and 3.7 for the time being.
Full traceback
Traceback (most recent call last):
__init__, threads.py:332
method_queue, threads.py:411
on_thread_started, threads.py:418
_serve, threads.py:252
_run, events.py:81
_run_once, base_events.py:1859
run_forever, base_events.py:570
run_until_complete, base_events.py:603
_start_thread, threads.py:211
run, threads.py:66
_bootstrap_inner, threading.py:932
_bootstrap, threading.py:890
Versions
- Python version 3.8.5
- Mode version 4.3.2
- Operating system MacOSX 10.13.6
Code block that implements (1) to (3)
import asyncio
from mode import QueueServiceThread
async def my_func(a: int) -> None:
print(a)
async def use_queue_service() -> None:
service: QueueServiceThread = QueueServiceThread()
await service.start();
await service.call_thread(my_func, 5)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(
use_queue_service()
)