def aio_sleep(seconds: float = 0) -> t.Awaitable: """Return sleep coroutine.""" if trio and current_async_library() == 'trio': return trio.sleep(seconds) if curio and current_async_library() == 'curio': return curio.sleep(seconds) return asyncio.sleep(seconds)
def aio_event(): """Create async event.""" if trio and current_async_library() == 'trio': return trio.Event() if curio and current_async_library() == 'curio': return curio.Event() return asyncio.Event()
async def sleep(duration: float) -> None: if current_async_library() == 'trio': import trio await trio.sleep(duration) elif current_async_library() == 'asyncio': import asyncio await asyncio.sleep(duration) else: raise Exception("Invariant")
async def agen(label): assert sniffio.current_async_library() == label try: yield 1 finally: library = sniffio.current_async_library() try: await sys.modules[library].sleep(0) except trio.Cancelled: pass record.add((label, library))
def is_async_context() -> bool: """Returns ``True`` if currently in an async context, otherwise ``False``""" try: import sniffio except ImportError as e: raise ImportError( f"is_async_context / @awaitable unavailable - 'sniffio' not installed. Exc: {type(e)} {str(e)} " ) try: # Detect if we're in async context sniffio.current_async_library() return True except sniffio.AsyncLibraryNotFoundError: return False
def load(self): super().load() try: sniffio.current_async_library() except sniffio.AsyncLibraryNotFoundError: # In a synchronous context, we wrap asynchronous models # such that we can evaluate `.predict` # Otherwise, they will have to be awaited _model_dependencies = {} for model_name, m in self.model_dependencies.items(): if isinstance(m, AsyncModel): _model_dependencies[model_name] = WrappedAsyncModel(m) else: _model_dependencies[model_name] = m self.model_dependencies = ModelDependenciesMapping(_model_dependencies)
def _wrapper(*args, **kwargs): coro = m(*args, **kwargs) try: sniffio.current_async_library() except sniffio.AsyncLibraryNotFoundError: pass else: return coro result = None try: while True: result = coro.send(result) except StopIteration as si: return si.value
def backend(self) -> ConcurrencyBackend: if not hasattr(self, "_backend_implementation"): backend = sniffio.current_async_library() if backend not in ("asyncio", "trio"): raise RuntimeError(f"Unsupported concurrency backend {backend!r}") self._backend_implementation = lookup_backend(backend) return self._backend_implementation
def normalize_backend(name: str = "auto", *, async_mode: bool) -> str: if name == "auto": if not async_mode: backend = "sync" else: import sniffio async_library = sniffio.current_async_library() assert async_library == "asyncio" backend = async_library else: # pragma: no cover backend = name loaders_by_name = _get_backend_loaders() assert backend in loaders_by_name, "Unknown backend specifier: {backend!r}" loader = loaders_by_name[backend] if async_mode and not loader.is_async: # pragma: no cover raise ValueError( f"Backend {loader.name!r} needs to be run in sync mode") if not async_mode and loader.is_async: # pragma: no cover raise ValueError( f"Backend {loader.name!r} needs to be run in async mode") return backend
def _get_asynclib(): asynclib_name = sniffio.current_async_library() modulename = 'anyio._backends._' + asynclib_name try: return sys.modules[modulename] except KeyError: return import_module(modulename)
def __init__(self, obj, async_backend): # set to None now so we can know if we need to free it later # This should be at the top of __init__ so that __del__ doesn't raise # an unexpected AttributeError if something funky happens self.aio = None # this is not a public interface, let's make some assertions assert isinstance(obj, (pynng.Socket, pynng.Context)) # we need to choose the correct nng lib functions based on the type of # object we've been passed; but really, all the logic is identical if isinstance(obj, pynng.Socket): self._nng_obj = obj.socket self._lib_arecv = lib.nng_recv_aio self._lib_asend = lib.nng_send_aio else: self._nng_obj = obj.context self._lib_arecv = lib.nng_ctx_recv self._lib_asend = lib.nng_ctx_send self.obj = obj if async_backend is None: async_backend = sniffio.current_async_library() if async_backend not in self._aio_helper_map: raise ValueError( 'The async backend {} is not currently supported.' .format(async_backend) ) self.awaitable, self.cb_arg = self._aio_helper_map[async_backend](self) aio_p = ffi.new('nng_aio **') _aio_map[id(self.cb_arg)] = self.cb_arg idarg = id(self.cb_arg) as_void = ffi.cast('void *', idarg) lib.nng_aio_alloc(aio_p, lib._async_complete, as_void) self.aio = aio_p[0]
def sniff() -> str: """Attempt to determine the in-use asynchronous I/O library by using the ``sniffio`` module if it is available. Returns the name of the library, or raises AsyncLibraryNotFoundError if the library cannot be determined. """ # pylint: disable=import-outside-toplevel try: if _no_sniffio: raise ImportError import sniffio try: return sniffio.current_async_library() except sniffio.AsyncLibraryNotFoundError: raise AsyncLibraryNotFoundError("sniffio cannot determine " + "async library") except ImportError: import asyncio try: asyncio.get_running_loop() return "asyncio" except RuntimeError: raise AsyncLibraryNotFoundError("no async library detected")
def assertPassed(passed: float) -> Generator[None, None, None]: """ A context manager that checks the code executed in its context has taken the exact given amount of time on the event loop. Naturally, exact timing can only work on a test event loop using simulated time. """ try: from sniffio import current_async_library except ImportError: library = 'asyncio' else: library = current_async_library() if library == 'trio': import trio time = trio.current_time elif library == 'asyncio': time = asyncio.get_event_loop().time else: raise RuntimeError(f"Unsupported library {library!r}") begin = time() yield end = time() assert end - begin == passed
async def ensure_portal() -> None: """Ensure that the current async task is able to use :func:`greenback.await_`. If the current task has called :func:`ensure_portal` previously, calling it again is a no-op. Otherwise, :func:`ensure_portal` interposes a "coroutine shim" provided by `greenback` in between the event loop and the coroutine being used to run the task. For example, when running under Trio, `trio.lowlevel.Task.coro` is replaced with a wrapper around the coroutine it previously referred to. (The same thing happens under asyncio, but asyncio doesn't expose the coroutine field publicly, so some additional trickery is required in that case.) After installation of the coroutine shim, each task step passes through `greenback` on its way into and out of your code. At some performance cost, this effectively provides a **portal** that allows later calls to :func:`greenback.await_` in the same task to access an async environment, even if the function that calls :func:`await_` is a synchronous function. This function is a cancellation point and a schedule point (a checkpoint, in Trio terms) even if the calling task already had a portal set up. """ this_task = current_task() if this_task not in task_has_portal: bestow_portal(this_task) # Execute a checkpoint so that we're now running inside the shim coroutine. # This is necessary in case the caller immediately invokes greenback.await_() # without any further checkpoints. library = sniffio.current_async_library() await sys.modules[library].sleep(0)
def sniff(): """Attempt to determine the in-use asynchronous I/O library by using the ``sniffio`` module if it is available. Returns the name of the library, or raises AsyncLibraryNotFoundError if the library cannot be determined. """ try: if _no_sniffio: raise ImportError import sniffio try: return sniffio.current_async_library() except sniffio.AsyncLibraryNotFoundError: raise AsyncLibraryNotFoundError('sniffio cannot determine ' + 'async library') except ImportError: import asyncio try: asyncio.get_running_loop() return 'asyncio' except RuntimeError: raise AsyncLibraryNotFoundError('no async library detected') except AttributeError: # pragma: no cover # we have to check current_task on 3.6 if not asyncio.Task.current_task(): raise AsyncLibraryNotFoundError('no async library detected') return 'asyncio'
def normalize_backend(backend, async_mode): if backend is None: if not async_mode: backend = Backend(name="sync") else: import sniffio backend = Backend(name=sniffio.current_async_library()) elif not isinstance(backend, Backend): backend = Backend(name=backend) loaders_by_name = backend_directory() if backend.name not in loaders_by_name: raise ValueError("unknown backend specifier {}".format(backend.name)) loader = loaders_by_name[backend.name] if async_mode and not loader.is_async: raise ValueError("{} backend needs to be run in sync mode".format( loader.name)) if not async_mode and loader.is_async: raise ValueError("{} backend needs to be run in async mode".format( loader.name)) return backend
async def persist_delayed(timeout): if current_async_library() == 'trio': await trio.sleep(timeout) else: await asyncio.sleep(timeout) #print('PERSIST', state) state._appstate_shelve['state'] = state.as_dict() state._appstate_shelve.sync()
async def run_concurrently(*coroutines): if sniffio.current_async_library() == "trio": async with trio.open_nursery() as nursery: for coroutine in coroutines: nursery.start_soon(coroutine) else: coros = (coroutine() for coroutine in coroutines) await asyncio.gather(*coros)
async def __aenter__(self): assert self.parent.did_it == 0 self.parent.did_it = 1 if sys.version_info >= (3, 7): assert sniffio.current_async_library() == "asyncio" await asyncio.sleep(0.01, loop=self.loop) self.parent.did_it = 2 return self
def create_event() -> "Event": if sniffio.current_async_library() == "trio": import trio return trio.Event() else: import asyncio return asyncio.Event()
def get_cipher(stream): if sniffio.current_async_library() == "trio": return ( stream.stream.cipher() if isinstance(stream.stream, trio.SSLStream) else None ) else: return stream.stream_writer.get_extra_info("cipher", default=None)
def get_asynclib(asynclib_name: Optional[str] = None) -> Any: if asynclib_name is None: asynclib_name = sniffio.current_async_library() modulename = 'anyio._backends._' + asynclib_name try: return sys.modules[modulename] except KeyError: return import_module(modulename)
async def iter_trio(self): if sys.version_info >= (3, 7): assert sniffio.current_async_library() == "trio" await trio.sleep(0.01) yield 1 await trio.sleep(0.01) yield 2 await trio.sleep(0.01) self.flag |= 1
async def iter_asyncio(self, do_test=True): if do_test and sys.version_info >= (3, 7): assert sniffio.current_async_library() == "asyncio" await asyncio.sleep(0.01, loop=self.loop) yield 1 await asyncio.sleep(0.01, loop=self.loop) yield 2 await asyncio.sleep(0.01, loop=self.loop) self.flag |= 1
def call(self, f, *a, **kw): if not inspect.iscoroutinefunction(f): return f(*a, **kw) if current_async_library() == 'trio': if not getattr(state, '_nursery'): raise Exception('Provide state._nursery for async task to run.') state._nursery.start_soon(f) else: return asyncio.create_task(f())
async def run_asyncio_trio_iter(self, loop): sth = SomeThing(loop) n = 0 if sys.version_info >= (3, 7): assert sniffio.current_async_library() == "asyncio" async for x in trio_as_aio(sth.iter_trio()): n += 1 assert x == n assert n == 2 assert sth.flag == 1
async def _init_backend(self) -> None: if not (hasattr(self, "_backend")): backend = sniffio.current_async_library() if backend == "trio": from .trio import TrioBackend self._backend: AsyncNetworkBackend = TrioBackend() else: from .asyncio import AsyncIOBackend self._backend = AsyncIOBackend()
def _get_asynclib(): try: asynclib_name = sniffio.current_async_library() except sniffio.AsyncLibraryNotFoundError as exc: raise RuntimeError('Not running in any supported asynchronous event loop') from exc modulename = 'anyio._backends.' + asynclib_name try: return sys.modules[modulename] except KeyError: return import_module(modulename)
def _detect_running_asynclib() -> Optional[str]: # This function can be removed once https://github.com/python-trio/sniffio/pull/5 has been # merged try: return sniffio.current_async_library() except sniffio.AsyncLibraryNotFoundError: if 'curio' in sys.modules: from curio.meta import curio_running if curio_running(): return 'curio' return None
def current_task(): # anyio's TaskInfo comparisons are invalid after their associated native # task object is GC'd https://github.com/agronholm/anyio/issues/324 asynclib_name = sniffio.current_async_library() if asynclib_name == "trio": return trio.lowlevel.current_task() if asynclib_name == "asyncio": task = asyncio_current_task() if task is None: raise RuntimeError("must be called from a running task") # pragma: no cover return task raise RuntimeError(f"unsupported asynclib={asynclib_name}") # pragma: no cover
async def _connect(self): if sniffio.current_async_library() == "asyncio": loop = asyncio.get_event_loop() self._sub_trans, self._sub_prot, = await loop.subprocess_exec( partial(AsyncioMockServerProtocol, server=self), "../wago-firmware/wago", "-d", "-D", "-p0", "-c", "../wago-firmware/wago.sample.csv", stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=sys.stderr, ) return self._sub_prot elif sniffio.current_async_library() == "trio": import trio import subprocess self._sub_prot = await trio.open_process( [ "../wago-firmware/wago", "-d", "-D", "-p0", "-c", "../wago-firmware/wago.sample.csv", ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=sys.stderr, ) p = TrioMockServerProtocol(server=self) # pylint: disable=abstract-class-instantiated await self.task_group.spawn(p._recv_loop) return p else: raise RuntimeError("Not supported")