Skip to content

Commit 62bbbdd

Browse files
authored
Move call_soon_with_future / _invoke -> NetBackend base class (#3143)
1 parent ef3c959 commit 62bbbdd

3 files changed

Lines changed: 28 additions & 86 deletions

File tree

kafka/net/backend/abstract.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"""
5050
import abc
5151
import importlib
52+
import inspect
5253
from typing import Any, Callable, Optional, Protocol, Sequence, Tuple, runtime_checkable
5354

5455
import kafka.errors as Errors
@@ -207,10 +208,6 @@ def call_soon(self, task: Any) -> Any:
207208
deferred-handle box).
208209
"""
209210

210-
@abc.abstractmethod
211-
def call_soon_with_future(self, coro: Any, *args: Any) -> NetBackendFuture:
212-
"""Schedule ``coro`` and return a future that resolves with its result."""
213-
214211
@abc.abstractmethod
215212
def call_at(self, when: float, task: Any) -> Any:
216213
"""Schedule ``task`` to run at absolute monotonic time ``when``."""
@@ -334,6 +331,33 @@ def wait_for(self, future: Any, timeout_ms: Optional[float], raise_error: bool=T
334331
if raise_error:
335332
raise
336333

334+
async def _invoke(self, coro, *args):
335+
"""Invoke coro/awaitable/function and fully resolve the result."""
336+
if inspect.iscoroutinefunction(coro):
337+
result = await coro(*args)
338+
elif hasattr(coro, '__await__'):
339+
result = await coro
340+
else:
341+
result = coro(*args)
342+
if inspect.iscoroutine(result) or hasattr(result, '__await__'):
343+
result = await result
344+
while isinstance(result, NetBackendFuture):
345+
result = await result
346+
return result
347+
348+
def call_soon_with_future(self, coro: Any, *args: Any) -> NetBackendFuture:
349+
"""Schedule ``coro`` and return a future that resolves with its result."""
350+
if hasattr(coro, '__await__') and args:
351+
raise ValueError('initiated coroutine does not accept args')
352+
future = self.create_future()
353+
async def wrapper():
354+
try:
355+
future.success(await self._invoke(coro, *args))
356+
except BaseException as exc:
357+
future.failure(exc)
358+
self.call_soon(wrapper)
359+
return future
360+
337361

338362
# --- backend selection ----------------------------------------------------
339363

kafka/net/backend/asyncio_backend.py

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -286,57 +286,6 @@ def wakeup(self):
286286
def create_future(self):
287287
return AsyncioFuture(self._loop)
288288

289-
async def _resolve_future(self, fut):
290-
"""Await any kafka.future.Future (plain or AsyncioFuture) to its value."""
291-
if fut.is_done:
292-
if fut.exception is not None:
293-
raise fut.exception
294-
return fut.value
295-
aio = self._loop.create_future()
296-
297-
def _cb(_=None):
298-
if aio.done():
299-
return
300-
if fut.exception is not None:
301-
aio.set_exception(fut.exception)
302-
else:
303-
aio.set_result(fut.value)
304-
305-
fut.add_both(_cb)
306-
return await aio
307-
308-
async def _invoke(self, coro, *args):
309-
"""Invoke coro/awaitable/function and fully resolve the result.
310-
311-
Mirrors NetworkSelector._invoke, but bridges any trailing kafka Future
312-
through _resolve_future (a plain Future isn't awaitable under asyncio).
313-
"""
314-
if inspect.iscoroutinefunction(coro):
315-
result = await coro(*args)
316-
elif hasattr(coro, '__await__'):
317-
result = await coro
318-
else:
319-
result = coro(*args)
320-
if inspect.iscoroutine(result) or hasattr(result, '__await__'):
321-
result = await result
322-
while isinstance(result, Future):
323-
result = await self._resolve_future(result)
324-
return result
325-
326-
def call_soon_with_future(self, coro, *args):
327-
if hasattr(coro, '__await__') and args:
328-
raise ValueError('initiated coroutine does not accept args')
329-
future = AsyncioFuture(self._loop)
330-
331-
async def wrapper():
332-
try:
333-
future.success(await self._invoke(coro, *args))
334-
except BaseException as exc:
335-
future.failure(exc)
336-
337-
self.call_soon(wrapper)
338-
return future
339-
340289
# --- cross-thread bridge ---------------------------------------------
341290
def run(self, coro, *args, timeout_ms=None):
342291
if self._closed:

kafka/net/backend/selector.py

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -501,37 +501,6 @@ def call_soon(self, task):
501501
self.wakeup()
502502
return task
503503

504-
def call_soon_with_future(self, coro, *args):
505-
if hasattr(coro, '__await__'):
506-
if args:
507-
raise ValueError('initiated coroutine does not accept args')
508-
future = SelectorFuture() # returned to callers who await it
509-
async def wrapper():
510-
try:
511-
future.success(await self._invoke(coro, *args))
512-
except BaseException as exc:
513-
future.failure(exc)
514-
self.call_soon(wrapper)
515-
return future
516-
517-
async def _invoke(self, coro, *args):
518-
"""Invoke coro/awaitable/function and fully resolve the result.
519-
520-
If the result is itself a Future (e.g. send() returning an unresolved
521-
Future), it is awaited so callers receive the resolved value.
522-
"""
523-
if inspect.iscoroutinefunction(coro):
524-
result = await coro(*args)
525-
elif hasattr(coro, '__await__'):
526-
result = await coro
527-
else:
528-
result = coro(*args)
529-
if inspect.iscoroutine(result) or hasattr(result, '__await__'):
530-
result = await result
531-
while isinstance(result, Future):
532-
result = await result
533-
return result
534-
535504
def _unschedule(self, task):
536505
assert task.state is TaskState.SCHEDULED
537506
assert task.scheduled_at is not None

0 commit comments

Comments
 (0)