feat(core): add use_asyncio kwarg to Zeroconf#1684
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1684 +/- ##
=======================================
Coverage 99.76% 99.76%
=======================================
Files 33 33
Lines 3407 3410 +3
Branches 463 464 +1
=======================================
+ Hits 3399 3402 +3
Misses 5 5
Partials 3 3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds an explicit use_asyncio: bool | None = None switch to zeroconf.Zeroconf to override the current auto-detection of a running asyncio event loop (notably to support forcing thread-based/blocking semantics in environments like Jupyter where a loop is always running).
Changes:
- Extend
Zeroconf.__init__withuse_asyncioand store it asself._use_asyncio. - Update
Zeroconf.start()to honoruse_asyncio(force thread, force loop + error, or auto-detect). - Add unit tests covering
use_asyncio=False,use_asyncio=Trueerror behavior, and default regression behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/zeroconf/_core.py |
Adds use_asyncio kwarg and consults it during startup to choose between attaching to a running loop vs starting the internal thread/loop. |
tests/test_core.py |
Adds tests validating the new use_asyncio behaviors and preserving the default auto-detect behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
PR Review — feat(core): add use_asyncio kwarg to ZeroconfSmall, well-scoped feature addition that solves a real Jupyter-style problem. The implementation correctly places the 🟢 Suggestions1. Collapse if/else into a ternary (`src/zeroconf/_core.py`, L232-235)Per @bdraco's review comment (id 3253356037), the four-line if/else in self.loop = None if self._use_asyncio is False else get_running_loop()It's equivalent and keeps the body of 2. Missing happy-path test for use_asyncio=True (`tests/test_core.py`, L175-185)The three new tests cover def test_use_asyncio_true_with_running_loop_attaches(self):
async def run() -> r.Zeroconf:
return r.Zeroconf(interfaces=["127.0.0.1"], use_asyncio=True)
loop = asyncio.new_event_loop()
zc: r.Zeroconf | None = None
try:
zc = loop.run_until_complete(run())
assert zc._loop_thread is None
assert zc.loop is loop
finally:
if zc is not None:
zc.close()
loop.close()3. Consider hoisting the check above apple_p2p validation (`src/zeroconf/_core.py`, L190-191)The Checklist
SummarySmall, well-scoped feature addition that solves a real Jupyter-style problem. The implementation correctly places the |
Rebase with requested adjustmentsBranch Changes applied
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
Rebase with requested adjustmentsBranch StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
145a77f to
42e7c27
Compare
Rebase with requested adjustmentsBranch Changes applied
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
42e7c27 to
369f533
Compare
Zeroconf currently auto-detects a running event loop and attaches to it; passing use_asyncio=False forces the historic thread-mode path even when a loop is running (e.g. Jupyter). use_asyncio=True requires a running loop and raises otherwise. None (default) preserves the existing behaviour. Closes python-zeroconf#1651
Rebase with requested adjustmentsBranch Changes applied
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
369f533 to
8c133a0
Compare
What
Add
use_asyncio: bool | None = NonetoZeroconf.__init__.Why
Zeroconfauto-detects a running event loop viaget_running_loop()and attaches to it. In environments like Jupyter that always have an event loop running to support top-levelawait, this makes it impossible to use the blocking thread-mode API for code that is otherwise sync. Issue #1651 asked for an explicit override.How
use_asyncio=None(default) → historic auto-detect behaviour, unchanged.use_asyncio=False→ ignore any running loop, always spawn the internal thread + loop.use_asyncio=True→ require a running loop; raiseRuntimeErrorif none is found (fast, explicit failure instead of silently launching a thread).The flag is stored as
self._use_asyncioand consulted instart()before callingget_running_loop(). No changes toAsyncZeroconf— it implicitly needs a loop and the existing behaviour is correct there.Testing
Three new unit tests in
tests/test_core.py:use_asyncio=Falsefrom inside a running loop → thread is started,zc.loop != loop.use_asyncio=Truewithout a running loop →RuntimeError.use_asyncio=Nonewithout a loop → thread is started (regression guard).poetry run pytest tests/test_core.py→ 24 passed, 1 skipped.Closes #1651
Quality Report
Changes: 2 files changed, 45 insertions(+), 1 deletion(-)
Code scan: clean
Tests: failed (timeout (120s))
Branch hygiene: clean
Generated by Kōan post-mission quality pipeline