aiogram_tool 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aiogram_tool/__init__.py +0 -0
- aiogram_tool/depend/__init__.py +10 -0
- aiogram_tool/depend/components/__init__.py +0 -0
- aiogram_tool/depend/components/filter.py +28 -0
- aiogram_tool/depend/components/middleware.py +36 -0
- aiogram_tool/depend/depend.py +103 -0
- aiogram_tool/depend/setup.py +34 -0
- aiogram_tool/depend/utils/__init__.py +0 -0
- aiogram_tool/depend/utils/inject.py +33 -0
- aiogram_tool/limit/__init__.py +7 -0
- aiogram_tool/limit/limit.py +87 -0
- aiogram_tool/limit/setup.py +27 -0
- aiogram_tool/limit/storage/__init__.py +7 -0
- aiogram_tool/limit/storage/abstract_storage.py +16 -0
- aiogram_tool/limit/storage/memory_storage.py +23 -0
- aiogram_tool/limit/storage/redis_storage.py +37 -0
- aiogram_tool-1.0.0.dist-info/LICENSE.md +21 -0
- aiogram_tool-1.0.0.dist-info/METADATA +52 -0
- aiogram_tool-1.0.0.dist-info/RECORD +20 -0
- aiogram_tool-1.0.0.dist-info/WHEEL +4 -0
aiogram_tool/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from aiogram.filters import Filter
|
|
4
|
+
from aiogram import Dispatcher
|
|
5
|
+
from aiogram.dispatcher.event.handler import HandlerObject
|
|
6
|
+
|
|
7
|
+
from ..depend import Depend
|
|
8
|
+
from ..utils.inject import inject_parametrs
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DependFilter(Filter):
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def __call__(self, *args: Any, **kwargs: dict[str, Any]) -> dict[str, Any]:
|
|
17
|
+
handler_object: HandlerObject = kwargs.get("handler")
|
|
18
|
+
dispatcher: Dispatcher = kwargs.get("dispatcher")
|
|
19
|
+
|
|
20
|
+
dependency_override: dict[str, Depend] = dispatcher.workflow_data.get("dependency_override", {})
|
|
21
|
+
|
|
22
|
+
kwargs.update({"event": args[0]})
|
|
23
|
+
depend_kwargs = await inject_parametrs(
|
|
24
|
+
callback=handler_object.callback,
|
|
25
|
+
dependency_override=dependency_override,
|
|
26
|
+
middleware_data=kwargs
|
|
27
|
+
)
|
|
28
|
+
return depend_kwargs
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import Any, Callable, Awaitable
|
|
2
|
+
|
|
3
|
+
from aiogram.dispatcher.middlewares.base import BaseMiddleware
|
|
4
|
+
from aiogram.types.base import TelegramObject
|
|
5
|
+
from aiogram import Dispatcher
|
|
6
|
+
from aiogram.dispatcher.event.handler import HandlerObject
|
|
7
|
+
|
|
8
|
+
from ..depend import Depend
|
|
9
|
+
from ..utils.inject import inject_parametrs
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DependMiddleware(BaseMiddleware):
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def __call__(
|
|
19
|
+
self,
|
|
20
|
+
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable],
|
|
21
|
+
event: TelegramObject,
|
|
22
|
+
data: dict[str, Any]
|
|
23
|
+
):
|
|
24
|
+
handler_object: HandlerObject = data.get("handler")
|
|
25
|
+
dispatcher: Dispatcher = data.get("dispatcher")
|
|
26
|
+
|
|
27
|
+
dependency_override: dict[str, Depend] = dispatcher.workflow_data.get("dependency_override", {})
|
|
28
|
+
|
|
29
|
+
data.update({"event": event})
|
|
30
|
+
inject = await inject_parametrs(
|
|
31
|
+
callback=handler_object.callback,
|
|
32
|
+
dependency_override=dependency_override,
|
|
33
|
+
middleware_data=data
|
|
34
|
+
)
|
|
35
|
+
data.update(inject)
|
|
36
|
+
return await handler(event, data)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
|
|
3
|
+
from contextlib import (
|
|
4
|
+
asynccontextmanager,
|
|
5
|
+
contextmanager
|
|
6
|
+
)
|
|
7
|
+
from typing import (
|
|
8
|
+
Callable,
|
|
9
|
+
Any,
|
|
10
|
+
_AnnotatedAlias
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Depend:
|
|
16
|
+
def __init__(self, obj: Callable) -> None:
|
|
17
|
+
self.obj = obj
|
|
18
|
+
self.isgenerator = False
|
|
19
|
+
self.isasync = False
|
|
20
|
+
self.obj_name = getattr(obj, "__name__", "")
|
|
21
|
+
self.arguments = {}
|
|
22
|
+
|
|
23
|
+
if isinstance(self.obj, type):
|
|
24
|
+
raise TypeError("dont valid type. Initialize class")
|
|
25
|
+
|
|
26
|
+
if not callable(self.obj):
|
|
27
|
+
raise TypeError("obj must be a callable")
|
|
28
|
+
|
|
29
|
+
if not inspect.isfunction(self.obj):
|
|
30
|
+
self.obj_name = self.obj.__class__.__name__
|
|
31
|
+
self.obj = getattr(self.obj, "__call__")
|
|
32
|
+
|
|
33
|
+
self.__explore_obj()
|
|
34
|
+
self.__explore_signature()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def __explore_obj(self) -> None:
|
|
38
|
+
if inspect.iscoroutinefunction(self.obj):
|
|
39
|
+
self.isasync = True
|
|
40
|
+
|
|
41
|
+
else:
|
|
42
|
+
if inspect.isasyncgenfunction(self.obj):
|
|
43
|
+
self.isgenerator = True
|
|
44
|
+
self.isasync = True
|
|
45
|
+
self.obj = asynccontextmanager(self.obj)
|
|
46
|
+
|
|
47
|
+
elif inspect.isgeneratorfunction(self.obj):
|
|
48
|
+
self.isgenerator = True
|
|
49
|
+
self.obj = contextmanager(self.obj)
|
|
50
|
+
|
|
51
|
+
else:
|
|
52
|
+
types = []
|
|
53
|
+
for closure in inspect.getclosurevars(self.obj):
|
|
54
|
+
if isinstance(closure, dict):
|
|
55
|
+
types.extend(list(closure.values()))
|
|
56
|
+
|
|
57
|
+
for type_ in types:
|
|
58
|
+
name = getattr(type_, "__name__", None)
|
|
59
|
+
if name == "_AsyncGeneratorContextManager":
|
|
60
|
+
self.isasync = True
|
|
61
|
+
self.isgenerator = True
|
|
62
|
+
|
|
63
|
+
elif name == "_GeneratorContextManager":
|
|
64
|
+
self.isgenerator = True
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def __explore_signature(self) -> None:
|
|
68
|
+
signature = inspect.signature(self.obj)
|
|
69
|
+
for key, annotation in signature.parameters.items():
|
|
70
|
+
default_value = annotation.default
|
|
71
|
+
|
|
72
|
+
if isinstance(annotation.annotation, _AnnotatedAlias):
|
|
73
|
+
types = getattr(annotation.annotation, "__metadata__")
|
|
74
|
+
for type_ in types:
|
|
75
|
+
if isinstance(type_, Depend):
|
|
76
|
+
self.arguments[key] = type_
|
|
77
|
+
|
|
78
|
+
elif isinstance(default_value, Depend):
|
|
79
|
+
self.arguments[key] = default_value
|
|
80
|
+
|
|
81
|
+
else:
|
|
82
|
+
self.arguments[key] = annotation.annotation
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
async def call(self, middleware_data: dict[str, Any]) -> Any:
|
|
86
|
+
kwargs = {}
|
|
87
|
+
for key, value in self.arguments.items():
|
|
88
|
+
if isinstance(value, Depend):
|
|
89
|
+
kwargs[key] = await value.call(middleware_data)
|
|
90
|
+
else:
|
|
91
|
+
kwargs[key] = middleware_data.get(key)
|
|
92
|
+
|
|
93
|
+
if self.isasync is False:
|
|
94
|
+
if self.isgenerator is True:
|
|
95
|
+
with self.obj(**kwargs) as value:
|
|
96
|
+
return value
|
|
97
|
+
return self.obj(**kwargs)
|
|
98
|
+
|
|
99
|
+
else:
|
|
100
|
+
if self.isgenerator is True:
|
|
101
|
+
async with self.obj(**kwargs) as asvalue:
|
|
102
|
+
return asvalue
|
|
103
|
+
return await self.obj(**kwargs)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from aiogram import Dispatcher
|
|
2
|
+
from aiogram.dispatcher.event.telegram import TelegramEventObserver
|
|
3
|
+
|
|
4
|
+
from .depend import Depend
|
|
5
|
+
from .components.middleware import DependMiddleware
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def setup_depend_tool(
|
|
12
|
+
dispatcher: Dispatcher,
|
|
13
|
+
dependency_override: dict[str, Depend] = {},
|
|
14
|
+
allowed_updates: list[str] = [],
|
|
15
|
+
middleware: bool = True,
|
|
16
|
+
) -> None:
|
|
17
|
+
if not isinstance(dispatcher, Dispatcher):
|
|
18
|
+
raise TypeError("dispatcher must be Dispatcher type")
|
|
19
|
+
|
|
20
|
+
if dependency_override:
|
|
21
|
+
for dep in dependency_override.values():
|
|
22
|
+
if not isinstance(dep, Depend):
|
|
23
|
+
raise TypeError(f"Invalid type in dependency_override {dep}")
|
|
24
|
+
|
|
25
|
+
if allowed_updates:
|
|
26
|
+
for allow in allowed_updates:
|
|
27
|
+
if allow not in dispatcher.observers:
|
|
28
|
+
raise TypeError(f"observer {allow} not exists")
|
|
29
|
+
|
|
30
|
+
if middleware is True:
|
|
31
|
+
for allow in dispatcher.resolve_used_update_types() or allowed_updates:
|
|
32
|
+
observer: TelegramEventObserver = getattr(dispatcher, allow)
|
|
33
|
+
observer.middleware(DependMiddleware())
|
|
34
|
+
dispatcher.__setitem__("dependency_override", dependency_override)
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable, _AnnotatedAlias
|
|
4
|
+
|
|
5
|
+
from ..depend import Depend
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
async def inject_parametrs(
|
|
10
|
+
callback: Callable,
|
|
11
|
+
middleware_data: dict[str, Any],
|
|
12
|
+
dependency_override: dict[str, Depend] = {},
|
|
13
|
+
) -> dict[str, Any]:
|
|
14
|
+
data = {}
|
|
15
|
+
signature = inspect.signature(callback)
|
|
16
|
+
for key, annotation in signature.parameters.items():
|
|
17
|
+
default_value = annotation.default
|
|
18
|
+
|
|
19
|
+
if isinstance(annotation.annotation, _AnnotatedAlias):
|
|
20
|
+
types = getattr(annotation.annotation, "__metadata__")
|
|
21
|
+
for type_ in types:
|
|
22
|
+
if isinstance(type_, Depend):
|
|
23
|
+
if type_.obj_name in dependency_override.keys():
|
|
24
|
+
data[key] = await dependency_override[type_.obj_name].call(middleware_data)
|
|
25
|
+
else:
|
|
26
|
+
data[key] = await type_.call(middleware_data)
|
|
27
|
+
|
|
28
|
+
elif isinstance(default_value, Depend):
|
|
29
|
+
if default_value.obj_name in dependency_override.keys():
|
|
30
|
+
data[key] = await dependency_override[default_value.obj_name].call(middleware_data)
|
|
31
|
+
else:
|
|
32
|
+
data[key] = await default_value.call(middleware_data)
|
|
33
|
+
return data
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
|
|
3
|
+
from typing import Callable, Awaitable
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
|
|
6
|
+
from aiogram import Dispatcher
|
|
7
|
+
from aiogram.filters import Filter
|
|
8
|
+
from aiogram.types.base import TelegramObject
|
|
9
|
+
from aiogram.dispatcher.event.handler import HandlerObject
|
|
10
|
+
|
|
11
|
+
from .storage.abstract_storage import AbstractStorage
|
|
12
|
+
from .storage import MemoryStorage
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Limit(Filter):
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
seconds: float = 0,
|
|
22
|
+
minutes: float = 0,
|
|
23
|
+
hours: float = 0,
|
|
24
|
+
days: float = 0,
|
|
25
|
+
all_users: bool = False,
|
|
26
|
+
storage: AbstractStorage | None = None,
|
|
27
|
+
answer_callback: Callable[[TelegramObject, timedelta, datetime], Awaitable] | None = None
|
|
28
|
+
) -> None:
|
|
29
|
+
if not isinstance(all_users, bool):
|
|
30
|
+
raise TypeError("all_users must be bool type")
|
|
31
|
+
|
|
32
|
+
if storage is not None:
|
|
33
|
+
if not issubclass(type(storage), AbstractStorage):
|
|
34
|
+
raise TypeError(f"Invalid type for storage")
|
|
35
|
+
|
|
36
|
+
if answer_callback is not None:
|
|
37
|
+
if not inspect.iscoroutinefunction(answer_callback):
|
|
38
|
+
raise TypeError(f"answer_callback must be croutine function")
|
|
39
|
+
|
|
40
|
+
# checks types
|
|
41
|
+
self.storage = storage
|
|
42
|
+
self.answer_callback = answer_callback
|
|
43
|
+
self.all_users = all_users
|
|
44
|
+
|
|
45
|
+
self.time = timedelta(
|
|
46
|
+
seconds=seconds,
|
|
47
|
+
minutes=minutes,
|
|
48
|
+
hours=hours,
|
|
49
|
+
days=days
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
async def __call__(
|
|
54
|
+
self,
|
|
55
|
+
message: TelegramObject,
|
|
56
|
+
dispatcher: Dispatcher,
|
|
57
|
+
handler: HandlerObject
|
|
58
|
+
) -> bool:
|
|
59
|
+
storage = dispatcher.workflow_data.get("storage", MemoryStorage())
|
|
60
|
+
answer_callback = dispatcher.workflow_data.get("answer_callback")
|
|
61
|
+
|
|
62
|
+
if self.storage is not None:
|
|
63
|
+
storage = self.storage
|
|
64
|
+
|
|
65
|
+
if self.answer_callback is not None:
|
|
66
|
+
answer_callback = self.answer_callback
|
|
67
|
+
|
|
68
|
+
query = str(message.from_user.id) + "@" + handler.callback.__name__
|
|
69
|
+
if self.all_users is True:
|
|
70
|
+
query = "users" + "@" + handler.callback.__name__
|
|
71
|
+
|
|
72
|
+
user_time = await storage.get(query)
|
|
73
|
+
if user_time is None:
|
|
74
|
+
await storage.update(query, datetime.utcnow() + self.time)
|
|
75
|
+
return True
|
|
76
|
+
|
|
77
|
+
if user_time >= datetime.utcnow():
|
|
78
|
+
time_last = user_time - datetime.utcnow()
|
|
79
|
+
if answer_callback is not None:
|
|
80
|
+
await answer_callback(message, self.time, time_last)
|
|
81
|
+
else:
|
|
82
|
+
await message.answer(f"Retry after {round(time_last.total_seconds(), 0)} seconds")
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
await storage.update(query, datetime.utcnow() + self.time)
|
|
86
|
+
return True
|
|
87
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
|
|
3
|
+
from typing import Callable, Awaitable
|
|
4
|
+
from aiogram.types import Message
|
|
5
|
+
from aiogram import Dispatcher
|
|
6
|
+
|
|
7
|
+
from datetime import datetime, timedelta
|
|
8
|
+
|
|
9
|
+
from .storage.abstract_storage import AbstractStorage
|
|
10
|
+
from .storage import MemoryStorage
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def setup_limit_tool(
|
|
15
|
+
dispatcher: Dispatcher,
|
|
16
|
+
storage: AbstractStorage = MemoryStorage(),
|
|
17
|
+
answer_callback: Callable[[Message, timedelta, datetime], Awaitable] | None = None
|
|
18
|
+
) -> None:
|
|
19
|
+
if not issubclass(type(storage), AbstractStorage):
|
|
20
|
+
raise TypeError(f"Invalid type for storage")
|
|
21
|
+
|
|
22
|
+
if answer_callback is not None:
|
|
23
|
+
if not inspect.iscoroutinefunction(answer_callback):
|
|
24
|
+
raise TypeError(f"answer_callback must be croutine function")
|
|
25
|
+
|
|
26
|
+
dispatcher.__setitem__("storage", storage)
|
|
27
|
+
dispatcher.__setitem__("answer_callback", answer_callback)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AbstractStorage(ABC):
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
async def get(self, name: str) -> datetime | None:
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
async def update(self, name: str, value: datetime) -> None:
|
|
16
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from .abstract_storage import AbstractStorage
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DataStorage:
|
|
8
|
+
data: dict[str, datetime] = {}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MemoryStorage(AbstractStorage):
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self.storage = DataStorage
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def get(self, name: str) -> datetime | None:
|
|
19
|
+
return self.storage.data.get(name)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async def update(self, name: str, value: datetime) -> None:
|
|
23
|
+
self.storage.data.update({name: value})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from redis.asyncio import Redis as AsyncRedis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from .abstract_storage import AbstractStorage
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RedisStorage(AbstractStorage):
|
|
13
|
+
def __init__(self, redis: AsyncRedis):
|
|
14
|
+
if not isinstance(redis, AsyncRedis):
|
|
15
|
+
raise TypeError("Invalid type for argument redis")
|
|
16
|
+
|
|
17
|
+
self.redis = redis
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def get(self, name: str) -> datetime | None:
|
|
21
|
+
async with self.redis as session:
|
|
22
|
+
data = await session.hget(name="limit_tool", key=name)
|
|
23
|
+
if data is None:
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
if isinstance(data, bytes):
|
|
27
|
+
data = data.decode()
|
|
28
|
+
return datetime.fromisoformat(data)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async def update(self, name: str, value: datetime) -> None:
|
|
32
|
+
async with self.redis as session:
|
|
33
|
+
await session.hset(
|
|
34
|
+
name="limit_tool",
|
|
35
|
+
key=name,
|
|
36
|
+
value=value.isoformat()
|
|
37
|
+
)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Dyadchenko Vladislav Sergeevich
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: aiogram_tool
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Tools which doing work with aiogram simple
|
|
5
|
+
License: LICENSE.md
|
|
6
|
+
Author: Vlad_shayzi1
|
|
7
|
+
Author-email: tecnomega@mail.ru
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Classifier: License :: Other/Proprietary License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Dist: aiogram (>=3.21.0,<4.0.0)
|
|
16
|
+
Requires-Dist: redis (>=6.2.0,<7.0.0)
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
## aiogram_tool
|
|
20
|
+
It's libriary with tools for aiogram.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# What kind of tools are these?
|
|
24
|
+
- [Dependency Injection](https://github.com/shayzi3/aiogram_tool/blob/master/examples/depend/default.py)
|
|
25
|
+
- [Rate limiter for handlers](https://github.com/shayzi3/aiogram_tool/blob/master/examples/limit/default.py)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
### Pip
|
|
31
|
+
```cmd
|
|
32
|
+
pip install aiogram_tool
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Poetry
|
|
36
|
+
```cmd
|
|
37
|
+
poetry add aiogram_tool
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## Documentation
|
|
42
|
+
|
|
43
|
+
- [RU](https://github.com/shayzi3/aiogram_tool/tree/master/docs/ru)
|
|
44
|
+
- [EN](https://github.com/shayzi3/aiogram_tool/tree/master/docs/en)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## Features `Depend`
|
|
48
|
+
|
|
49
|
+
- Depend without response for Router, handler
|
|
50
|
+
- Exit from depend before call handler
|
|
51
|
+
- use cache
|
|
52
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
aiogram_tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
aiogram_tool/depend/__init__.py,sha256=HJ0j-uJJ2eEiEHoxbUCykSZkuac159Qf_bYJergz61A,194
|
|
3
|
+
aiogram_tool/depend/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
aiogram_tool/depend/components/filter.py,sha256=6JeRhST5tgEMYMHJsxxEf8_hZzyfdqbODXacMSja7SQ,912
|
|
5
|
+
aiogram_tool/depend/components/middleware.py,sha256=SOBKi2n7FKT7K9ZSCzDgZAz6tSgbjIPt6nTwH2cFLSY,1167
|
|
6
|
+
aiogram_tool/depend/depend.py,sha256=Q2OmKzgTVsAEcY-_u_5Q8ZT_UaS0N_-Bj-wEBuFk0Ys,3880
|
|
7
|
+
aiogram_tool/depend/setup.py,sha256=cCTcHnN9REYoNJ-IFW3Im1LiAzO3lIshkvuONx2Z8e8,1245
|
|
8
|
+
aiogram_tool/depend/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
aiogram_tool/depend/utils/inject.py,sha256=eAuAgHyYXOBb-K4SsyNNm35QNPGJ5GnQ5E0uuGr3PVo,1331
|
|
10
|
+
aiogram_tool/limit/__init__.py,sha256=lCMjeHRUjoil8jsoI16TrVOfLOmiADppHAnxu8nu6ww,119
|
|
11
|
+
aiogram_tool/limit/limit.py,sha256=wmBDUMWk1rPuq9F54OeTmDY-OaMVeEzpcm0ErAh1A0I,3072
|
|
12
|
+
aiogram_tool/limit/setup.py,sha256=Sd7DwI3uTvlpON2ef3w7z2eMvGj97buzdwIrZlo-NDY,896
|
|
13
|
+
aiogram_tool/limit/storage/__init__.py,sha256=edM7He9oh9bqOh-P-dq2Nr1y5j_ysnAUTkhUwL-FbRo,124
|
|
14
|
+
aiogram_tool/limit/storage/abstract_storage.py,sha256=yvZ2TLkjkuUx8xT5r-kIkUw83UgGMX1DNW-xxCr02d0,370
|
|
15
|
+
aiogram_tool/limit/storage/memory_storage.py,sha256=J2XQVjp2ZFto_K5i3cW3uQAUuwM50A_QgP_4-X4ioHw,510
|
|
16
|
+
aiogram_tool/limit/storage/redis_storage.py,sha256=BGhP0m5b7BNF0mb1-JgYGk-JTPvIk3O6-OWDLpqOKTg,1104
|
|
17
|
+
aiogram_tool-1.0.0.dist-info/LICENSE.md,sha256=bl-bduptWJCYE_Hu0g1VQA7qkvN4RPJUuhuvpdlRP5Y,1107
|
|
18
|
+
aiogram_tool-1.0.0.dist-info/METADATA,sha256=tMM-wd4EfSm00p8A5SCK7M83jmYWMrkdAcT7073uThs,1316
|
|
19
|
+
aiogram_tool-1.0.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
|
20
|
+
aiogram_tool-1.0.0.dist-info/RECORD,,
|