aiostep 0.1.0__tar.gz
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.
- aiostep-0.1.0/PKG-INFO +10 -0
- aiostep-0.1.0/README.md +0 -0
- aiostep-0.1.0/aiostep/__init__.py +24 -0
- aiostep-0.1.0/aiostep/steps.py +202 -0
- aiostep-0.1.0/aiostep.egg-info/PKG-INFO +10 -0
- aiostep-0.1.0/aiostep.egg-info/SOURCES.txt +10 -0
- aiostep-0.1.0/aiostep.egg-info/dependency_links.txt +1 -0
- aiostep-0.1.0/aiostep.egg-info/requires.txt +1 -0
- aiostep-0.1.0/aiostep.egg-info/top_level.txt +1 -0
- aiostep-0.1.0/pyproject.toml +3 -0
- aiostep-0.1.0/setup.cfg +4 -0
- aiostep-0.1.0/setup.py +21 -0
aiostep-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: aiostep
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python library to handle steps in aiogram framework.
|
|
5
|
+
Home-page: https://github.com/NasrollahYusefi/aiostep/
|
|
6
|
+
Author: Nasrollah Yusefi
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Requires-Dist: cachebox
|
aiostep-0.1.0/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A Python library to handle steps in aiogram framework.
|
|
3
|
+
"""
|
|
4
|
+
__author__ = "Nasrollah Yusefi"
|
|
5
|
+
__version__ = "0.1.0"
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"Listen",
|
|
9
|
+
"change_root_store",
|
|
10
|
+
"register_next_step",
|
|
11
|
+
"unregister_steps",
|
|
12
|
+
"wait_for",
|
|
13
|
+
"clear",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
from .steps import (
|
|
17
|
+
MetaStore as MetaStore,
|
|
18
|
+
Listen as Listen,
|
|
19
|
+
change_root_store as change_root_store,
|
|
20
|
+
register_next_step as register_next_step,
|
|
21
|
+
unregister_steps as unregister_steps,
|
|
22
|
+
wait_for as wait_for,
|
|
23
|
+
clear as clear
|
|
24
|
+
)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typing
|
|
3
|
+
import functools
|
|
4
|
+
import cachebox
|
|
5
|
+
|
|
6
|
+
from aiogram import BaseMiddleware
|
|
7
|
+
from aiogram.types import TelegramObject, Update
|
|
8
|
+
|
|
9
|
+
_MT = typing.Union[asyncio.Future, typing.Callable]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MetaStore:
|
|
13
|
+
async def set_item(self, key: int, value: _MT) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Stores key-value.
|
|
16
|
+
"""
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
|
|
19
|
+
async def pop_item(self, key: int) -> _MT:
|
|
20
|
+
"""
|
|
21
|
+
Gives stored key-value.
|
|
22
|
+
|
|
23
|
+
raise KeyError if not found.
|
|
24
|
+
"""
|
|
25
|
+
raise NotImplementedError
|
|
26
|
+
|
|
27
|
+
async def clear(self) -> typing.AsyncGenerator[_MT, None]:
|
|
28
|
+
"""
|
|
29
|
+
Gives and clears all stored key-value.
|
|
30
|
+
"""
|
|
31
|
+
raise NotImplementedError
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class _RootStore(MetaStore):
|
|
35
|
+
def __init__(self) -> None:
|
|
36
|
+
self.cache = cachebox.Cache(0)
|
|
37
|
+
|
|
38
|
+
async def set_item(self, key: int, value: _MT) -> None:
|
|
39
|
+
self.cache[key] = value
|
|
40
|
+
|
|
41
|
+
async def pop_item(self, key: int) -> _MT:
|
|
42
|
+
return self.cache.pop(key)
|
|
43
|
+
|
|
44
|
+
async def clear(self) -> typing.AsyncGenerator[_MT, None]:
|
|
45
|
+
for k in self.cache.keys():
|
|
46
|
+
yield self.cache.pop(k)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
root = _RootStore()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def change_root_store(store: MetaStore) -> None:
|
|
53
|
+
"""
|
|
54
|
+
changes root store.
|
|
55
|
+
"""
|
|
56
|
+
global root
|
|
57
|
+
root = store
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Listen(BaseMiddleware):
|
|
61
|
+
"""
|
|
62
|
+
aiogram middleware to listen for steps.
|
|
63
|
+
|
|
64
|
+
supported handlers:
|
|
65
|
+
- `MessageHandler`
|
|
66
|
+
- `CallbackQueryHandler`
|
|
67
|
+
- `ChatJoinRequestHandler`
|
|
68
|
+
- `ChatMemberUpdatedHandler`
|
|
69
|
+
- `ChosenInlineResultHandler`
|
|
70
|
+
- `EditedMessageHandler`
|
|
71
|
+
- `InlineQueryHandler`
|
|
72
|
+
|
|
73
|
+
Example::
|
|
74
|
+
|
|
75
|
+
dp = Dispatcher()
|
|
76
|
+
dp.message.outer_middleware(aiostep.Listen(callback_query=False))
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def __init__(self,
|
|
80
|
+
store: typing.Optional[MetaStore] = None,
|
|
81
|
+
callback_query: typing.Optional[bool] = None) -> None:
|
|
82
|
+
self.store = store or root
|
|
83
|
+
self.callback_query = callback_query
|
|
84
|
+
|
|
85
|
+
async def __call__(
|
|
86
|
+
self,
|
|
87
|
+
handler: typing.Callable[[TelegramObject, typing.Dict[str, typing.Any]], typing.Awaitable[typing.Any]],
|
|
88
|
+
event: TelegramObject,
|
|
89
|
+
data: typing.Dict[str, typing.Any]
|
|
90
|
+
) -> typing.Any:
|
|
91
|
+
|
|
92
|
+
fn = None
|
|
93
|
+
|
|
94
|
+
if self.callback_query:
|
|
95
|
+
chat_id = event.message.chat.id
|
|
96
|
+
else:
|
|
97
|
+
chat_id = event.chat.id
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
fn = await self.store.pop_item(event.from_user.id)
|
|
101
|
+
except (KeyError, AttributeError):
|
|
102
|
+
try:
|
|
103
|
+
fn = await self.store.pop_item(chat_id)
|
|
104
|
+
except (KeyError, AttributeError):
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
if fn is not None:
|
|
108
|
+
if isinstance(fn, asyncio.Future):
|
|
109
|
+
fn.set_result(event)
|
|
110
|
+
return
|
|
111
|
+
await fn(event)
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
return await handler(event, data)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
async def register_next_step(
|
|
118
|
+
user_id: int,
|
|
119
|
+
_next: typing.Any,
|
|
120
|
+
store: typing.Optional[MetaStore] = None,
|
|
121
|
+
*,
|
|
122
|
+
args: tuple = (),
|
|
123
|
+
kwargs: dict = {},
|
|
124
|
+
) -> None:
|
|
125
|
+
"""
|
|
126
|
+
register next step for user/chat.
|
|
127
|
+
|
|
128
|
+
Example::
|
|
129
|
+
|
|
130
|
+
async def ask_name(message: Message):
|
|
131
|
+
await message.reply("What is your name?")
|
|
132
|
+
await aiostep.register_next_step(message.from_user.id, ask_age)
|
|
133
|
+
|
|
134
|
+
async def tell_name(msg: Message):
|
|
135
|
+
await message.reply("Your name is: {msg.text}")
|
|
136
|
+
"""
|
|
137
|
+
if args or kwargs:
|
|
138
|
+
_next = functools.partial(_next, *args, **kwargs)
|
|
139
|
+
|
|
140
|
+
await (store or root).set_item(user_id, _next)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
async def unregister_steps(user_id: int, store: typing.Optional[MetaStore] = None) -> None:
|
|
144
|
+
"""
|
|
145
|
+
unregister steps for `user_id`.
|
|
146
|
+
|
|
147
|
+
if step is `asyncio.Future`, cancels that.
|
|
148
|
+
"""
|
|
149
|
+
try:
|
|
150
|
+
u = await (store or root).pop_item(user_id)
|
|
151
|
+
except KeyError:
|
|
152
|
+
return
|
|
153
|
+
else:
|
|
154
|
+
if isinstance(u, asyncio.Future):
|
|
155
|
+
u.cancel("cancelled")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
async def _wait_future(user_id: int, timeout: typing.Optional[float], store: MetaStore) -> Update:
|
|
159
|
+
fn = asyncio.get_event_loop().create_future()
|
|
160
|
+
|
|
161
|
+
await store.set_item(user_id, fn)
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
return await asyncio.wait_for(fn, timeout)
|
|
165
|
+
finally:
|
|
166
|
+
await unregister_steps(user_id, store)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
async def wait_for(
|
|
170
|
+
user_id: int,
|
|
171
|
+
timeout: typing.Optional[float] = None,
|
|
172
|
+
store: typing.Optional[MetaStore] = None
|
|
173
|
+
) -> Update:
|
|
174
|
+
"""
|
|
175
|
+
wait for update which comming from specific user_id.
|
|
176
|
+
|
|
177
|
+
raise TimeoutError if timed out.
|
|
178
|
+
|
|
179
|
+
Example::
|
|
180
|
+
|
|
181
|
+
async def echo_handler(message: Message):
|
|
182
|
+
await message.reply("Please type something:")
|
|
183
|
+
try:
|
|
184
|
+
response = await aiostep.wait_for(message.from_user.id, timeout=25)
|
|
185
|
+
except TimeoutError:
|
|
186
|
+
await message.reply('You took too long to answer.')
|
|
187
|
+
else:
|
|
188
|
+
await message.reply(f"You typed: {response.text}")
|
|
189
|
+
"""
|
|
190
|
+
try:
|
|
191
|
+
return await _wait_future(user_id, timeout, store or root)
|
|
192
|
+
except asyncio.TimeoutError:
|
|
193
|
+
raise TimeoutError
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
async def clear(store: typing.Optional[MetaStore] = None) -> None:
|
|
197
|
+
"""
|
|
198
|
+
Clears all registered key-value's.
|
|
199
|
+
"""
|
|
200
|
+
async for i in (store or root).clear(): # type: ignore
|
|
201
|
+
if isinstance(i, asyncio.Future):
|
|
202
|
+
i.cancel()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: aiostep
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python library to handle steps in aiogram framework.
|
|
5
|
+
Home-page: https://github.com/NasrollahYusefi/aiostep/
|
|
6
|
+
Author: Nasrollah Yusefi
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Requires-Dist: cachebox
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cachebox
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
aiostep
|
aiostep-0.1.0/setup.cfg
ADDED
aiostep-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
VERSION = "0.1.0"
|
|
4
|
+
|
|
5
|
+
setup(
|
|
6
|
+
name="aiostep",
|
|
7
|
+
version=VERSION,
|
|
8
|
+
description="A Python library to handle steps in aiogram framework.",
|
|
9
|
+
author="Nasrollah Yusefi",
|
|
10
|
+
url="https://github.com/NasrollahYusefi/aiostep/",
|
|
11
|
+
packages=["aiostep"],
|
|
12
|
+
install_requires=[
|
|
13
|
+
"cachebox"
|
|
14
|
+
],
|
|
15
|
+
license="MIT",
|
|
16
|
+
license_files=["LICENSE"],
|
|
17
|
+
classifiers=[
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
],
|
|
21
|
+
)
|