Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

62 linhas
1.8 KiB

  1. import functools
  2. import typing
  3. from typing import Any, AsyncGenerator, Iterator
  4. import anyio
  5. try:
  6. import contextvars # Python 3.7+ only or via contextvars backport.
  7. except ImportError: # pragma: no cover
  8. contextvars = None # type: ignore
  9. T = typing.TypeVar("T")
  10. async def run_until_first_complete(*args: typing.Tuple[typing.Callable, dict]) -> None:
  11. async with anyio.create_task_group() as task_group:
  12. async def run(func: typing.Callable[[], typing.Coroutine]) -> None:
  13. await func()
  14. task_group.cancel_scope.cancel()
  15. for func, kwargs in args:
  16. task_group.start_soon(run, functools.partial(func, **kwargs))
  17. async def run_in_threadpool(
  18. func: typing.Callable[..., T], *args: typing.Any, **kwargs: typing.Any
  19. ) -> T:
  20. if contextvars is not None: # pragma: no cover
  21. # Ensure we run in the same context
  22. child = functools.partial(func, *args, **kwargs)
  23. context = contextvars.copy_context()
  24. func = context.run
  25. args = (child,)
  26. elif kwargs: # pragma: no cover
  27. # run_sync doesn't accept 'kwargs', so bind them in here
  28. func = functools.partial(func, **kwargs)
  29. return await anyio.to_thread.run_sync(func, *args)
  30. class _StopIteration(Exception):
  31. pass
  32. def _next(iterator: Iterator) -> Any:
  33. # We can't raise `StopIteration` from within the threadpool iterator
  34. # and catch it outside that context, so we coerce them into a different
  35. # exception type.
  36. try:
  37. return next(iterator)
  38. except StopIteration:
  39. raise _StopIteration
  40. async def iterate_in_threadpool(iterator: Iterator) -> AsyncGenerator:
  41. while True:
  42. try:
  43. yield await anyio.to_thread.run_sync(_next, iterator)
  44. except _StopIteration:
  45. break