once.py (812B)
1 from typing import Any 2 from asyncio import Future 3 from functools import wraps 4 from inspect import signature 5 6 7 def once(): 8 def decorator(f): 9 futs: dict[tuple[Any, ...], Future] = {} 10 sig = signature(f) 11 12 @wraps(f) 13 async def wrapped(*args, **kwargs): 14 bound_args = sig.bind(*args, **kwargs) 15 bound_args.apply_defaults() 16 key = tuple(bound_args.arguments.values()) 17 if key in futs: 18 return await futs[key] 19 futs[key] = Future() 20 try: 21 res = await f(*args, **kwargs) 22 futs[key].set_result(res) 23 return res 24 except BaseException as e: 25 futs[key].set_exception(e) 26 raise 27 28 return wrapped 29 30 return decorator