Skip to content

Instantly share code, notes, and snippets.

@Vizonex
Created March 14, 2023 04:47
Show Gist options
  • Select an option

  • Save Vizonex/8c3042edb5ae55ceb2402c540226bb7e to your computer and use it in GitHub Desktop.

Select an option

Save Vizonex/8c3042edb5ae55ceb2402c540226bb7e to your computer and use it in GitHub Desktop.
A little Concept I made inspired by Fastapi and discord.py as well as other decorator objects There's other interesting miscellaneous class objects in my code as well that you can take a look at if you want...
# The MIT License (MIT)
#
# Copyright © 2023 Vizonex
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the “Software”), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# The above copyright notice and this permission notice shall
# be included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
from typing import (
TypeVar,
Any,
Callable,
Awaitable,
Dict,
Generator,
Sequence,
Generic,
Iterable,
AsyncIterable,
AsyncIterator,
Union,
Coroutine,
Iterable
)
# The only other required library , you'll have to do 'pip install aioitertools'
from aioitertools.itertools import iter as aiter, next as anext
import asyncio
CoroFunc = Callable[..., Awaitable[Any]]
T = TypeVar("T")
_T1 = TypeVar("_T1")
_S = TypeVar("_S",covariant=True)
class amap(Awaitable[Sequence[_S]], AsyncIterable[_S]):
"""Takes Coroutines in the function and does everything asynchronously"""
def __init__(self, func: Callable[...,Awaitable[_S]], aiterable: Union[AsyncIterable[T], Iterable[T], Sequence[T]]):
self.l = aiter(aiterable)
self.func = func
async def __aiter__(self) -> AsyncIterator[_S]:
async for i in self.l:
yield await self.func(i)
async def run_next(self) -> _S:
return await self.func(await self.l.__anext__())
async def __anext__(self) -> _S:
return await self.run_next()
async def __join__(self) -> list[_S]:
return [await self.func(j) async for j in self.l]
def __await__(self) -> Generator[Any, None, list[_S]]:
return self.__join__().__await__()
# TODO Vizonex Maybe write these out in Cython for a speedboost?
Limbo = Union[Coroutine[Any, Any , T], asyncio.Task[T], asyncio.Future[T]]
"""Used to Describe an object as being in a loading state..."""
class AsyncGroup(Generic[T]):
"""Different from amap , allows for objects that are already being tasked or in a couroutine to be handled in all sorts of ways"""
def __init__(self,coros:Union[Iterable[Limbo[T]], AsyncIterable[Limbo[T]]],err_safety:bool = False) -> None:
self.it = aiter(coros)
self.err_safety = err_safety
"""Allows for objects to be optionally yeilded safely by printing the error instead of quitting out..."""
async def __aiter__(self):
if self.err_safety:
async for i in self.it:
try:
yield await i
except Exception as e:
print(f"{e} : {e.args} ")
else:
async for i in self.it:
yield await i
async def __anext__(self):
# Not super readable but it works...
return await (await anext(self.it))
async def join(self):
"""Joins iterator of courtines into a list object"""
return [await i async for i in self.__aiter__()]
def __await__(self) -> Generator[Any, None, list[T]]:
"""await async group into a list of objects to return"""
return self.join().__await__()
@classmethod
def from_loose_tasks(cls,items:Iterable[Limbo[T]]):
"""Can be used from raw, made lists of coroutines to be turned into futures
that are all to be executed concurrently"""
return cls(asyncio.as_completed(asyncio.ensure_future(i) for i in items))
class EventGroup(Generic[T]):
"""inspired by discord.py allows for events to be called from a simple cache of coroutine functions
This can allow for multiple asynchonous objects to be attached to the same event"""
def __init__(self) -> None:
self.cache : Dict[T , set[CoroFunc]] = dict()
def __call__(self,key:T):
"""Wraps an asynchornous funciton the the cache"""
def decorator(func: CoroFunc):
if not asyncio.iscoroutinefunction(func):
raise TypeError("Function: '%s' must be an asynchronous function" % func.__name__)
if self.cache.get(key):
self.cache[key].add(func)
else:
self.cache[key] = {func}
return func
return decorator
def exec(self,name:T,*args,**kwargs):
"""Executes a group of wrapped events that are together"""
if self.cache.get(name):
return AsyncGroup.from_loose_tasks(f(*args,**kwargs) for f in self.cache[name])
class Event(Generic[T]):
"""Allows for events to be quickly executed this is different from an `EventGroup` because it can only
have one unique variable assigned to each of them"""
def __init__(self) -> None:
self.cache : Dict[T,CoroFunc] = {}
def __call__(self,key:T):
"""Wraps an asynchornous funciton the the cache"""
def decorator(func: CoroFunc):
if not asyncio.iscoroutinefunction(func):
raise TypeError("Function: '%s' must be an asynchronous function" % func.__name__)
# One at a time!
if self.cache.get(key):
raise AttributeError("Key : '%s' already has an assigned function called '%s'" % (str(key), func.__name__))
self.cache[key] = func
return func
return decorator
async def exec(self,key:T,*args,**kwargs):
"""Executes the event chosen as a callback , it will return nothing if the key isn't avalible"""
return await self.cache[key](*args, **kwargs) if self.cache.get(key) else None
@Vizonex

Vizonex commented Mar 14, 2023

Copy link
Copy Markdown
Author

You can use anything in my code as you wish Just Remember to read the MIT License

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment