aiogram-input
Await the next user message in aiogram bots — with Dispatcher-scoped setup, handler DI, and pluggable storage.
Works alongside aiogram FSM: only matching waits consume messages; everything else passes through.
Features
- One-time
setup_input(dp)on the Dispatcher InputWaiterinjected into handlers asinput(same idea asFSMContext)- Timeouts, filters, and safe overwrite of in-flight waits
InputStorageprotocol +MemoryInputStorage(Redis-ready boundary)- Typed package (
py.typed)
Install
pip install aiogram-input
# or
uv add aiogram-input
Quick start
from aiogram import Bot, Dispatcher, F
from aiogram.filters import Command
from aiogram.types import Message
from aiogram_input import InputWaiter, MemoryInputStorage, setup_input
bot = Bot("TOKEN")
dp = Dispatcher()
setup_input(dp, storage=MemoryInputStorage())
@dp.message(Command("ask"))
async def ask(message: Message, input: InputWaiter):
await message.answer("Send your name")
reply = await input.wait(
chat_id=message.chat.id,
timeout=30,
filter=F.from_user.id == message.from_user.id,
)
if reply is None:
return await message.answer("Timed out")
await message.answer(f"Hello, {reply.text}")
Register routers as usual after setup_input(dp) — you do not construct a waiter per router.
Migration from 3.x → 4.0
Breaking change: InputManager is removed.
# 3.x
from aiogram_input import InputManager
asker = InputManager(dp) # or InputManager(router)
response = await asker.input(chat_id, timeout=20, filter=...)
# 4.0
from aiogram_input import InputWaiter, setup_input
setup_input(dp) # once, on Dispatcher only
@dp.message(Command("ask"))
async def ask(message: Message, input: InputWaiter):
response = await input.wait(message.chat.id, timeout=20, filter=...)
| 3.x | 4.0 |
|---|---|
InputManager(target) |
setup_input(dp, storage=...) |
asker.input(...) |
input.wait(...) |
| Setup on Router or Dispatcher | Dispatcher only |
| Built-in dict storage | MemoryInputStorage / custom InputStorage |
Examples
Confirm before action
@dp.message(Command("delete"))
async def delete_command(message: Message, input: InputWaiter):
await message.answer("Delete your data? (yes/no)")
response = await input.wait(message.chat.id, timeout=20)
if response is None:
return await message.answer("Timeout. Canceled.")
if (response.text or "").lower().strip() in {"yes", "y"}:
await message.answer("Deleted.")
else:
await message.answer("Canceled.")
Per-user filter in groups
@dp.message(Command("register"))
async def register(message: Message, input: InputWaiter):
await message.answer("Enter your email:")
response = await input.wait(
message.chat.id,
timeout=40,
filter=F.from_user.id == message.from_user.id,
)
if response is None:
return await message.answer("Timed out.")
await message.answer(f"Saved: {response.text}")
Multi-step form
@dp.message(Command("form"))
async def form(message: Message, input: InputWaiter):
chat_id = message.chat.id
await message.answer("Name?")
name = await input.wait(chat_id, timeout=30)
if not name:
return await message.answer("Timeout on name.")
await message.answer("Email?")
email = await input.wait(chat_id, timeout=30)
if not email:
return await message.answer("Timeout on email.")
await message.answer(f"Done\nName: {name.text}\nEmail: {email.text}")
Storage
from aiogram_input import InputStorage, MemoryInputStorage, setup_input
setup_input(dp, storage=MemoryInputStorage())
InputStorage stores only wait markers (safe to back with Redis later). Futures stay in-process via an internal registry.
Develop
uv sync --group dev
uv run pytest
uv build
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aiogram_input-4.0.0.tar.gz.
File metadata
- Download URL: aiogram_input-4.0.0.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd6693794741ce338ce1079106d530f302432fda5b1e9872f4c0a63e671c42f1
|
|
| MD5 |
4b903c7e14263772ea08de867ee7422e
|
|
| BLAKE2b-256 |
1764ebea79a5879d800c46d241d334bcbf9743b7f8bbf18d7092521a66bd2ea5
|
File details
Details for the file aiogram_input-4.0.0-py3-none-any.whl.
File metadata
- Download URL: aiogram_input-4.0.0-py3-none-any.whl
- Upload date:
- Size: 10.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de4cbb9a73fac036f804ded334ff9258a2244fa5fd5d1538e465649ee8107c48
|
|
| MD5 |
d2275a16f6972d3b77ebaef588ab82b8
|
|
| BLAKE2b-256 |
aa924944437e74f987f5bd70c3826f17dc86b4bbe5eb09b68fbe3f18f6e2f2d9
|