async def lifespan_context(ctx: Any) -> AsyncGenerator[Any, None]: tortoise_context = asynccontextmanager( tortoise_lifespan(config=dict( apps=dict(payment=dict(models=["eventual_tortoise.relation"])), connections=dict(default=configuration.DB_DSN), use_tz=False, timezone="UTC", ), # generate_schemas=True, )) eventual_context = asynccontextmanager( eventual_concurrent_lifespan( eventual_registry, message_broker, event_receive_store, ( event_send_store_factory.event_body_send_stream, event_send_store_factory.event_body_stream, ), TortoiseEventSendStore, ConcurrentMessageDispatcher, )) async with tortoise_context(ctx): async with eventual_context(ctx): yield
async def test_matcher_mutex(): from nonebot.plugins.single_session import matcher_mutex, _running_matcher am = asynccontextmanager(matcher_mutex) event = make_fake_event()() event_1 = make_fake_event()() event_2 = make_fake_event(_session_id="test1")() event_3 = make_fake_event(_session_id=None)() async with am(event) as ctx: assert ctx == False assert not _running_matcher async with am(event) as ctx: async with am(event_1) as ctx_1: assert ctx == False assert ctx_1 == True assert not _running_matcher async with am(event) as ctx: async with am(event_2) as ctx_2: assert ctx == False assert ctx_2 == False assert not _running_matcher async with am(event_3) as ctx_3: assert ctx_3 == False assert not _running_matcher
async def run(auth: AcaPyAuth = Depends(acapy_auth)): roles = role if isinstance(role, List) else [role] if auth.role not in roles: raise HTTPException(403, "Unauthorized") async with asynccontextmanager(agent_selector)(auth) as x: yield x
def wrapper(func): # Handle async case. Func should be an async context manager if the # function was defined using `async def` rather than just `def` is_async = False if inspect.isasyncgenfunction(func): func = contextlib.asynccontextmanager(func) is_async = True @contextlib.asynccontextmanager async def wrapped(*args, **kwargs): async with func( *ContextManagedWrapperSource.remove_self_from_args( args), **kwargs, ) as source: yield source elif inspect.isgeneratorfunction(func): func = contextlib.contextmanager(func) @contextlib.contextmanager def wrapped(*args, **kwargs): with func( *ContextManagedWrapperSource.remove_self_from_args( args), **kwargs, ) as source: yield source else: raise FunctionMustBeGenerator(f"{func} does not 'yield'") # Wrap with functools wrapped = functools.wraps(func)(wrapped) # Create a new class whose name is the entry point name in camel case # with the suffix added. Whose parent class is # ContextManagedWrapperSource. # Create a new config class (@config) and set it as the CONFIG property # of the class we're creating. This will be used to configure the source # The properties of the config class will be taken from the arguments of # the function we are wrapping. # ContextManagedWrapperSource will call the WRAPPED function, which is # our func, and pass it the values of the properties of the config # class. # It will call it as an async context manager if IS_ASYNC is True. wrapped.source = entrypoint(entrypoint_name)(type( class_name, (ContextManagedWrapperSource, ), { "CONFIG": make_config_inspect(class_name + "Config", func), "WRAPPED": wrapped, "IS_ASYNC": is_async, }, )) return wrapped
def use_fixture(self, fixture_name: str, func: FixtureFunc) -> None: if fixture_name in Context.__annotations__: raise ValueError(f"Cannot use reserved name {fixture_name}") if fixture_name in (name for name, _ in self._fixtures): raise ValueError(f"Duplicate fixture name {fixture_name}") self._fixtures.append( (fixture_name, contextlib.asynccontextmanager(func)))
def wrap(*args, **kwargs): job, ex_manager = fun(*args, **kwargs) if inspect.isasyncgenfunction(job): if DD.HELPERS ^ DD.DEEP: print(f'## {jobname} is coroutine') return jobname, asynccontextmanager( job), ex_manager, reuse, True else: if DD.HELPERS ^ DD.DEEP: print(f'## {jobname} is not coroutine') return jobname, contextmanager(job), ex_manager, reuse, False
def doodad(fun: Generator): """ A doodad is a function that can be inserted in PGWare's asynchronous execution pipeline. It receives the pipeline's state as parameter, and **must** `yield` it at some point. The available fields of the State object that can be accessed are documented in the State's definition. **Usage:** A doodad can be defined by employing the `doodad` decorator. Example: import pgware as pgware @pgware.doodad def log_query(state): print(f"raw query: {state.query}") print(f"raw values: {state.values}") yield state Doodads need to be assigned to the PGWare object or connection context, by specifying at which stage you wish to insert the doodad: import pgware as pgware pgw = pgware.build(**config) # For all PGWare queries: pgw.add_doodad('execution', log_query) # Just for a single context: with pgw.get_connection() as conn: conn.add_doodad('execution', log_query) Available execution stages are (see README for more details): - connection - parsing - execution - result - errors **Definition:** **parameters**, **types**, **return** and **return types**:: - :param arg1: the function which will become the doodad - :type arg1: a generator function, optionnaly async - :return: the function which can be used as dooded - :rtype: a context manager, optionnaly async """ if inspect.isasyncgenfunction(fun): return asynccontextmanager(fun) else: return contextmanager(fun)
class AsyncResource(AsyncClient): """An `AsyncClient`_ which returns json content and has syntactic support for requests.""" client = property(AsyncClient.clone, doc="upcasted `AsyncClient`_") __getattr__ = AsyncClient.__truediv__ __getitem__ = AsyncClient.get # type: ignore content_type = Resource.content_type __call__ = Resource.__call__ async def request(self, method, path, **kwargs): """Send request with path and return processed content.""" response = await super().request(method, path, **kwargs) response.raise_for_status() if self.content_type(response) == 'json': return response.json() return response.text if response.charset_encoding else response.content async def updater(self, path='', **kwargs): response = await super().request('GET', path, **kwargs) response.raise_for_status() kwargs['headers'] = dict(kwargs.get('headers', {}), **validate(response)) yield await self.put(path, (yield response.json()), **kwargs) async def updating(self, path: str = '', **kwargs): updater = self.updater(path, **kwargs) json = await updater.__anext__() yield json await updater.asend(json) if hasattr(contextlib, 'asynccontextmanager'): # pragma: no branch updating = contextlib.asynccontextmanager(updating) updating.__doc__ = Resource.updating.__doc__ async def update(self, path='', callback=None, **json): """PATCH request with json params. :param callback: optionally update with GET and validated PUT. ``callback`` is called on the json result with keyword params, i.e., ``dict`` correctly implements the simple update case. """ if callback is None: return await self.patch(path, json) updater = self.updater(path) return await updater.asend(callback(await updater.__anext__(), **json)) async def authorize(self, path: str = '', **kwargs) -> dict: """Acquire oauth access token and set ``auth``.""" method = 'GET' if {'json', 'data'}.isdisjoint(kwargs) else 'POST' result = await self.request(method, path, **kwargs) self._attrs['auth'] = self.auth = TokenAuth( {result['token_type']: result['access_token']}) return result
class AsyncResource(AsyncClient): """An `AsyncClient`_ which returns json content and has syntactic support for requests.""" client = property(AsyncClient.clone, doc="upcasted `AsyncClient`_") __getattr__ = AsyncClient.__truediv__ __getitem__ = AsyncClient.get content_type = Resource.content_type __call__ = Resource.__call__ @inherit_doc(Resource) async def request(self, method, path, **kwargs): response = await super().request(method, path, **kwargs) response.raise_for_status() if self.content_type(response) == 'json': return response.json() return response.text if response.charset_encoding else response.content async def updater(self, path='', **kwargs): response = await super().request('GET', path, **kwargs) response.raise_for_status() kwargs['headers'] = dict(kwargs.get('headers', {}), **validate(response)) yield await self.put(path, (yield response.json()), **kwargs) async def updating(self, path='', **kwargs): updater = self.updater(path, **kwargs) json = await updater.__anext__() yield json await updater.asend(json) if hasattr(contextlib, 'asynccontextmanager'): # pragma: no branch updating = contextlib.asynccontextmanager(updating) updating.__doc__ = Resource.updating.__doc__ @inherit_doc(Resource) async def update(self, path='', callback=None, **json): if callback is None: return await self.patch(path, json) updater = self.updater(path) return await updater.asend(callback(await updater.__anext__(), **json)) @inherit_doc(Resource) async def authorize(self, path='', **kwargs): method = 'GET' if {'json', 'data'}.isdisjoint(kwargs) else 'POST' result = await self.request(method, path, **kwargs) self._attrs['auth'] = self.auth = TokenAuth({result['token_type']: result['access_token']}) return result
async def _solve( self, stack: Optional[AsyncExitStack] = None, dependency_cache: Optional[T_DependencyCache] = None, **kwargs: Any, ) -> Any: use_cache: bool = self.extra["use_cache"] dependency_cache = {} if dependency_cache is None else dependency_cache sub_dependent: Dependent = self.extra["dependent"] sub_dependent.call = cast(Callable[..., Any], sub_dependent.call) call = sub_dependent.call # solve sub dependency with current cache sub_values = await sub_dependent.solve( stack=stack, dependency_cache=dependency_cache, **kwargs, ) # run dependency function task: asyncio.Task[Any] if use_cache and call in dependency_cache: solved = await dependency_cache[call] elif is_gen_callable(call) or is_async_gen_callable(call): assert isinstance( stack, AsyncExitStack ), "Generator dependency should be called in context" if is_gen_callable(call): cm = run_sync_ctx_manager(contextmanager(call)(**sub_values)) else: cm = asynccontextmanager(call)(**sub_values) task = asyncio.create_task(stack.enter_async_context(cm)) dependency_cache[call] = task solved = await task elif is_coroutine_callable(call): task = asyncio.create_task(call(**sub_values)) dependency_cache[call] = task solved = await task else: task = asyncio.create_task(run_sync(call)(**sub_values)) dependency_cache[call] = task solved = await task return solved
def __init__( self, routes: typing.Sequence[BaseRoute] = None, redirect_slashes: bool = True, default: ASGIApp = None, on_startup: typing.Sequence[typing.Callable] = None, on_shutdown: typing.Sequence[typing.Callable] = None, lifespan: typing.Callable[[typing.Any], typing.AsyncContextManager] = None, ) -> None: self.routes = [] if routes is None else list(routes) self.redirect_slashes = redirect_slashes self.default = self.not_found if default is None else default self.on_startup = [] if on_startup is None else list(on_startup) self.on_shutdown = [] if on_shutdown is None else list(on_shutdown) if lifespan is None: self.lifespan_context: typing.Callable[ [typing.Any], typing.AsyncContextManager] = _DefaultLifespan(self) elif inspect.isasyncgenfunction(lifespan): warnings.warn( "async generator function lifespans are deprecated, " "use an @contextlib.asynccontextmanager function instead", DeprecationWarning, ) self.lifespan_context = asynccontextmanager( lifespan, # type: ignore[arg-type] ) elif inspect.isgeneratorfunction(lifespan): warnings.warn( "generator function lifespans are deprecated, " "use an @contextlib.asynccontextmanager function instead", DeprecationWarning, ) self.lifespan_context = _wrap_gen_lifespan_context( lifespan, # type: ignore[arg-type] ) else: self.lifespan_context = lifespan
def __init__( self, method: Callable[[Any], AsyncIterator[_Rsrc]], ) -> None: self._context_manager = asynccontextmanager(method)
import asyncio import contextlib from uuid import uuid4 from fastapi_users.manager import UserNotExists from sqlalchemy import select from secret_wiki.api.auth import get_user_manager from secret_wiki.db import get_async_session, get_user_db from secret_wiki.models.wiki import Page, Section, SectionPermission, Wiki from secret_wiki.schemas import PermissionLevel, UserShellCreate get_async_session_context = contextlib.asynccontextmanager(get_async_session) get_user_db_context = contextlib.asynccontextmanager(get_user_db) get_user_manager_context = contextlib.asynccontextmanager(get_user_manager) async def create_user(name: str): email = f"{name}@example.com" async with get_async_session_context() as db: async with get_user_db_context(db) as user_db: async with get_user_manager_context(user_db) as user_manager: try: user = await user_manager.get_by_email(email) except UserNotExists: user = await user_manager.create( UserShellCreate( email=email, password=name, is_active=True, is_superuser=name == "admin",
def generate_method_generic(query: Query, detail: AbstractDriverDetail, hook: QueryHook) -> Callable[..., Any]: func_def = query.func_def returns = func_def.returns get_cursor = asynccontextmanager(detail.yield_cursor) if returns is None: async def method_returning_none(db: Any, *args: Any, **kwargs: Any) -> None: async with get_cursor(db) as cur: prepared_args = prepare_args_as_dict(func_def, args, kwargs) await cur.execute(hook(query.text, prepared_args), prepared_args) return method_returning_none elif returns.outer_format == ReturnValueOuterFormat.ITERATOR: async def method_returning_iterator(db: Any, *args: Any, **kwargs: Any) -> AsyncIterator[Any]: assert(returns is not None) # mypy bug async with get_cursor(db) as cur: prepared_args = prepare_args_as_dict(func_def, args, kwargs) await cur.execute(hook(query.text, prepared_args), prepared_args) names = [desc[0] for desc in cur.description] process_row = generate_row_processor(returns.inner_format, names) async for row in cur: yield process_row(row) return method_returning_iterator elif returns.outer_format == ReturnValueOuterFormat.LIST: async def method_returning_list(db: Any, *args: Any, **kwargs: Any) -> List[Any]: assert(returns is not None) # mypy bug async with get_cursor(db) as cur: prepared_args = prepare_args_as_dict(func_def, args, kwargs) await cur.execute(hook(query.text, prepared_args), prepared_args) names = [desc[0] for desc in cur.description] process_row = generate_row_processor(returns.inner_format, names) return [process_row(row) async for row in cur] return method_returning_list elif returns.outer_format == ReturnValueOuterFormat.SINGLE: async def method_returning_single(db: Any, *args: Any, **kwargs: Any) -> Any: assert(returns is not None) # mypy bug async with get_cursor(db) as cur: prepared_args = prepare_args_as_dict(func_def, args, kwargs) await cur.execute(hook(query.text, prepared_args), prepared_args) names = [desc[0] for desc in cur.description] process_row = generate_row_processor(returns.inner_format, names) return process_row(await cur.fetchone()) return method_returning_single elif returns.outer_format == ReturnValueOuterFormat.DICT: async def method_returning_dict(db: Any, *args: Any, **kwargs: Any) -> Any: assert(returns is not None) # mypy bug async with get_cursor(db) as cur: prepared_args = prepare_args_as_dict(func_def, args, kwargs) await cur.execute(hook(query.text, prepared_args), prepared_args) names = [desc[0] for desc in cur.description] if isinstance(returns.outer_dict_by, int): keyidx = returns.outer_dict_by else: try: keyidx = names.index(returns.outer_dict_by) except ValueError: raise KeyError(f'key column {returns.outer_dict_by} not found') if keyidx >= len(names): raise IndexError(f'key column index {keyidx} is out of range') if returns.remove_key_column: trimmed_names = names[0:keyidx] + names[keyidx + 1:] process_row = generate_row_processor(returns.inner_format, trimmed_names) return { row[keyidx]: process_row(row[0:keyidx] + row[keyidx + 1:]) async for row in cur } else: process_row = generate_row_processor(returns.inner_format, names) return { row[keyidx]: process_row(row) async for row in cur } return method_returning_dict else: raise NotImplementedError(f"unsupported outer return type format '{returns.outer_format}'") # pragma: no cover
def doc_reader_proxy(method_name): async def proxy(self, *args, **kwargs): async with self.read_transaction() as t: yield getattr(t, method_name)(*args, **kwargs) return contextlib.asynccontextmanager(proxy)
def test_sniff_options(): def check(obj, *expected): __tracebackhide__ = True assert sniff_options(obj) == set(expected) def boring(): # pragma: no cover pass check(boring) class Basic: # pragma: no cover def a(self): pass @classmethod def b(self): pass @staticmethod def c(self): pass @classmethod async def classasync(self): pass check(Basic.__dict__["a"]) check(Basic.__dict__["b"], "classmethod") check(Basic.__dict__["c"], "staticmethod") check(Basic.__dict__["classasync"], "classmethod", "async") class Abstract(abc.ABC): # pragma: no cover @abc.abstractmethod def abmeth(self): pass @staticmethod @abc.abstractmethod def abstatic(self): pass @staticmethod @abc.abstractmethod async def abstaticasync(self): pass check(Abstract.__dict__["abmeth"], "abstractmethod") check(Abstract.__dict__["abstatic"], "abstractmethod", "staticmethod") check(Abstract.__dict__["abstaticasync"], "abstractmethod", "staticmethod", "async") async def async_fn(): # pragma: no cover pass check(async_fn, "async") def gen(): # pragma: no cover yield check(gen, "for") if have_async_generator: @async_generator async def agen(): # pragma: no cover await yield_() check(agen, "async-for") if "agen_native" in globals(): check(agen_native, "async-for") @contextmanager def cm(): # pragma: no cover yield check(cm, "with") if have_contextmanager2: @contextmanager2 def cm2(): # pragma: no cover yield check(cm2, "with") def manual_cm(): # pragma: no cover pass manual_cm.__returns_contextmanager__ = True check(manual_cm, "with") def manual_acm(): # pragma: no cover pass manual_acm.__returns_acontextmanager__ = True check(manual_acm, "async-with") if have_async_generator: @async_generator async def acm_gen(): # pragma: no cover await yield_() @wraps(acm_gen) def acm_wrapped(): # pragma: no cover pass acm_wrapped.__returns_acontextmanager__ = True check(acm_wrapped, "async-with") if have_asynccontextmanager: acm = asynccontextmanager(agen_native) check(acm, "async-with") # A chain with complex overrides. We ignore the intermediate generator and # async function, because the outermost one is a contextmanager -- but we # still pick up the staticmethod at the end of the chain. @staticmethod def messy0(): # pragma: no cover pass async def messy1(): # pragma: no cover pass messy1.__wrapped__ = messy0 def messy2(): # pragma: no cover yield messy2.__wrapped__ = messy1 def messy3(): # pragma: no cover pass messy3.__wrapped__ = messy2 messy3.__returns_contextmanager__ = True check(messy3, "with", "staticmethod")
async def admin_agent_selector(auth: AcaPyAuth = Depends(acapy_auth)): if not auth.role.is_admin: raise HTTPException(403, "Unauthorized") async with asynccontextmanager(agent_selector)(auth) as x: yield x
from contextlib import contextmanager CM_CODES.add(contextmanager(None).__code__) # type: ignore try: from contextlib2 import contextmanager as contextmanager2 except ImportError: pass else: CM_CODES.add(contextmanager2(None).__code__) # type: ignore try: from contextlib import asynccontextmanager except ImportError: pass else: ACM_CODES.add(asynccontextmanager(None).__code__) # type: ignore extended_function_option_spec = { "async": directives.flag, "decorator": directives.flag, "with": directives.unchanged, "async-with": directives.unchanged, "for": directives.unchanged, "async-for": directives.unchanged, } extended_method_option_spec = { **extended_function_option_spec, "abstractmethod": directives.flag, "staticmethod": directives.flag, "classmethod": directives.flag,
from woolgatherer.utils.settings import Settings _database: databases.Database = databases.Database(Settings.dsn) async def open_connection_pool(): """ Initialize the db connection pool """ await _database.connect() async def close_connection_pool(): """ Close the db connection pool """ await _database.disconnect() async def get_db(): """ A generator which yields a database. It can be used as a dependency for routes. """ try: transaction = await _database.transaction() yield _database except: # pylint: disable=bare-except await transaction.rollback() else: await transaction.commit() get_async_db = asynccontextmanager(get_db)
def create_event( name: str, signature: Union[Callable[[Any], Awaitable], inspect.Signature], *, module: Optional[str] = None, ) -> Event: """ Create an event programmatically from a name and function signature. Args: name: The name of the event to be created. signature: The method signature of on event handlers of the event. module: The module that defined the event. When `None`, inferred via the `inspect` module. """ if _events.get(name, None): raise ValueError(f"Event '{name}' has already been created") def _default_context_manager() -> AsyncContextManager: # Simply yield to the on event handler async def fn(self) -> None: yield return contextlib.asynccontextmanager(fn) if callable(signature): if inspect.isasyncgenfunction(signature): # We have an async generator function defining setup/teardown activities, wrap into a context manager # This is useful for shared behaviors like startup delays, settlement times, etc. on_handler_context_manager = contextlib.asynccontextmanager( signature) elif not inspect.iscoroutinefunction(signature): raise ValueError( f"events must be async: add `async` prefix to your function declaration and await as necessary ({signature})" ) else: # Sanity check callables that don't yield are stubs # We expect the last line to be 'pass' or '...' for stub code try: lines = inspect.getsourcelines(signature) last = lines[0][-1] if not last.strip() in ("pass", "..."): raise ValueError( "function body of event declaration must be an async generator or a stub using `...` or `pass` keywords" ) # use the default since our input doesn't yield on_handler_context_manager = _default_context_manager() except OSError: from servo.logging import logger logger.warning( f"unable to inspect event declaration for '{name}': dropping event body and proceeding" ) on_handler_context_manager = _default_context_manager() else: # Signatures are opaque from introspection on_handler_context_manager = _default_context_manager() signature = (signature if isinstance(signature, inspect.Signature) else inspect.Signature.from_callable(signature)) if list( filter( lambda param: param.kind == inspect.Parameter.VAR_POSITIONAL, signature.parameters.values(), )): raise TypeError( f"Invalid signature: events cannot declare variable positional arguments (e.g. *args)" ) # Get the module from the calling stack frame if module is None: localns = inspect.currentframe().f_back.f_locals module = localns.get("__module__", None) event = Event( name=name, signature=signature, module=module, on_handler_context_manager=on_handler_context_manager, ) _events[name] = event return event
def update_event(self, inp=-1): self.set_output_val(0, contextlib.asynccontextmanager(self.input(0)))
def _default_context_manager() -> AsyncContextManager: # Simply yield to the on event handler async def fn(self) -> None: yield return contextlib.asynccontextmanager(fn)
from common import SETTINGS engine = create_async_engine(SETTINGS.database_url, pool_pre_ping=True, future=True) SessionLocal = sessionmaker( engine, expire_on_commit=False, autoflush=False, autocommit=False, class_=AsyncSession, future=True, ) async def get_db() -> AsyncGenerator: """ Open a new session to the database """ try: async with SessionLocal() as session: yield session finally: await session.close() # Required since FastAPI cannot use context managers as dependencies # Relevant issue: https://github.com/tiangolo/fastapi/issues/2212 db_context: Callable[ [], AsyncContextManager[AsyncSession]] = asynccontextmanager(get_db)
from contextlib import asynccontextmanager from typing import AsyncGenerator from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine from sqlalchemy.orm import sessionmaker from .config import config engine = create_async_engine( config("DATABASE_URL"), connect_args={"check_same_thread": False} ) SessionLocal = sessionmaker( bind=engine, class_=AsyncSession, expire_on_commit=False, autocommit=False, autoflush=False, ) async def get_db() -> AsyncGenerator[AsyncSession, None]: async with SessionLocal() as session: yield session db_context = asynccontextmanager(get_db)