Skip to content

feat: added aio MessageBus 'loop' optional parameter#560

Closed
depaolim wants to merge 2 commits intoBluetooth-Devices:mainfrom
depaolim:messagebus-aio-loop
Closed

feat: added aio MessageBus 'loop' optional parameter#560
depaolim wants to merge 2 commits intoBluetooth-Devices:mainfrom
depaolim:messagebus-aio-loop

Conversation

@depaolim
Copy link

Added the optional loop parameter to asyncio's MessageBus object. If not specified, it uses the running_loop parameter as before. This can be useful for special cases where the programmer needs to execute operations in a specific loop of their choosing.

@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.32%. Comparing base (fa28774) to head (d04aa6b).
⚠️ Report is 11 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #560   +/-   ##
=======================================
  Coverage   85.31%   85.32%           
=======================================
  Files          28       28           
  Lines        3433     3435    +2     
  Branches      601      602    +1     
=======================================
+ Hits         2929     2931    +2     
  Misses        312      312           
  Partials      192      192           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq
Copy link

codspeed-hq bot commented Nov 19, 2025

CodSpeed Performance Report

Merging #560 will not alter performance

Comparing depaolim:messagebus-aio-loop (d04aa6b) with main (b9d8c0e)

Summary

✅ 6 untouched

@dlech
Copy link
Member

dlech commented Nov 19, 2025

Can you tell us more about the specific case?

We will need to add this paramter to the documentation comment as well. And it should have an explanation that discourages people from actually using the parameter. An example of an legitimate use case would help.

And we should add .. versionchanged: 3.2.0: ... with an explanation that this parameter was added.

@depaolim
Copy link
Author

Can you tell us more about the specific case?

We will need to add this paramter to the documentation comment as well. And it should have an explanation that discourages people from actually using the parameter. An example of an legitimate use case would help.

I think a common legitimate use case is when creating a multi-threaded application where different threads need their own event loops.
For example, imagine you have:

  • A main GUI thread (using tkinter, PyQt, or similar) with its own event loop
  • A background worker thread that needs to monitor D-Bus messages for system events (such as Bluetooth device connections)

In this scenario, you can't use asyncio.get_running_loop() in the worker thread because you need to explicitly create and manage a separate event loop for that thread.

If I'm missing something, please let me know.

@dlech
Copy link
Member

dlech commented Nov 19, 2025

I would expect that one would create the asyncio event loop first by calling asyncio.run() in the thread and then create the MessageBus object only after the asyncio loop is up and running.

@depaolim
Copy link
Author

I would expect that one would create the asyncio event loop first by calling asyncio.run() in the thread and then create the MessageBus object only after the asyncio loop is up and running.

You made a point. I double check my scenario and I'll be back with some news
Meanwhile I mark this PR as draft.
Thanks for your hints

@depaolim depaolim marked this pull request as draft November 19, 2025 16:02
@depaolim
Copy link
Author

Here I am, finally back. I’m submitting a few points of reflection; in any case, I really appreciate this repository, so I’ll trust your judgment on whether introducing this parameter is appropriate.

  1. Without the loop parameter, MessageBus would attempt to call asyncio.get_running_loop(), which may either fail or return the wrong loop in multi-threaded contexts where each thread manages its own event loop. In short—as the Zen of Python reminds us—explicit is better than implicit. :-)

  2. According to the documentation for asyncio.run (see: https://docs.python.org/3/library/asyncio-runner.html#asyncio.run), it “Execute coro in an asyncio event loop and return the result. [..] managing the asyncio event loop, finalizing asynchronous generators, and closing the executor.
    However, automatically closing the executor may not always be what the programmer intends.

  3. The pattern of explicitly passing a loop argument is already used within asyncio itself. For example, see asyncio.StreamReader.__init__:
    https://github.com/python/cpython/blob/202fce0dbde1da32d8abc2eb59ddfce6f6a3c9fa/Lib/asyncio/streams.py#L422

As I mentioned, I trust your judgment. I agree that the parameter isn’t strictly essential, so I’m also fine with closing the PR without merging.

@dlech
Copy link
Member

dlech commented Dec 12, 2025

  1. which may either fail

It would only fail if the run loop isn't running. So passing loop as an arg could have the same problem and just fail later.

  1. r return the wrong loop in multi-threaded contexts where each thread manages its own event loop

I'm not sure I understand this one. My understanding is that asyncio.get_running_loop() will return the current running loop of the current thread, if any. So it would always be the correct loop (assuming it is running).

2. However, automatically closing the executor may not always be what the programmer intends.

This would be a very rare exception. I would expect a thread used for D-Bus to be used only for that and not be using the executor for other things.

3. The pattern of explicitly passing a loop argument is already used within asyncio itself.

There are also a lot of cases where a loop argument was removed from various functions in Python 3.10 because it caused too many problems with people not using it correctly.


So basically, if we find a real-world use case where it is actually needed, then sure, we can add it. But otherwise I would be inclined to leave it the way it is so that people are not tempted to use it incorrectly.

@depaolim
Copy link
Author

So basically, if we find a real-world use case where it is actually needed, then sure, we can add it. But otherwise I would be inclined to leave it the way it is so that people are not tempted to use it incorrectly.

That's fine with me

@depaolim depaolim closed this Dec 12, 2025
@depaolim depaolim reopened this Dec 12, 2025
@depaolim
Copy link
Author

I'm sorry, I reopened it by mistake... Now I'm closing it again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments