mirror of
https://github.com/aiogram/aiogram.git
synced 2025-12-06 07:50:32 +00:00
Some checks failed
Tests / tests (macos-latest, 3.10) (push) Has been cancelled
Tests / tests (macos-latest, 3.11) (push) Has been cancelled
Tests / tests (macos-latest, 3.12) (push) Has been cancelled
Tests / tests (macos-latest, 3.13) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.10) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.13) (push) Has been cancelled
Tests / tests (windows-latest, 3.10) (push) Has been cancelled
Tests / tests (windows-latest, 3.11) (push) Has been cancelled
Tests / tests (windows-latest, 3.12) (push) Has been cancelled
Tests / tests (windows-latest, 3.13) (push) Has been cancelled
Tests / pypy-tests (macos-latest, pypy3.10) (push) Has been cancelled
Tests / pypy-tests (macos-latest, pypy3.11) (push) Has been cancelled
Tests / pypy-tests (ubuntu-latest, pypy3.10) (push) Has been cancelled
Tests / pypy-tests (ubuntu-latest, pypy3.11) (push) Has been cancelled
* Drop py3.9 and pypy3.9 Add pypy3.11 (testing) into `tests.yml` Remove py3.9 from matrix in `tests.yml` Refactor not auto-gen code to be compatible with py3.10+, droping ugly 3.9 annotation. Replace some `from typing` imports to `from collections.abc`, due to deprecation Add `from __future__ import annotations` and `if TYPE_CHECKING:` where possible Add some `noqa` to calm down Ruff in some places, if Ruff will be used as default linting+formatting tool in future Replace some relative imports to absolute Sort `__all__` tuples in `__init__.py` and some other `.py` files Sort `__slots__` tuples in classes Split raises into `msg` and `raise` (`EM101`, `EM102`) to not duplicate error message in the traceback Add `Self` from `typing_extenstion` where possible Resolve typing problem in `aiogram/filters/command.py:18` Concatenate nested `if` statements Convert `HandlerContainer` into a dataclass in `aiogram/fsm/scene.py` Bump tests docker-compose.yml `redis:6-alpine` -> `redis:8-alpine` Bump tests docker-compose.yml `mongo:7.0.6` -> `mongo:8.0.14` Bump pre-commit-config `black==24.4.2` -> `black==25.9.0` Bump pre-commit-config `ruff==0.5.1` -> `ruff==0.13.3` Update Makefile lint for ruff to show fixes Add `make outdated` into Makefile Use `pathlib` instead of `os.path` Bump `redis[hiredis]>=5.0.1,<5.3.0` -> `redis[hiredis]>=6.2.0,<7` Bump `cryptography>=43.0.0` -> `cryptography>=46.0.0` due to security reasons Bump `pytz~=2023.3` -> `pytz~=2025.2` Bump `pycryptodomex~=3.19.0` -> `pycryptodomex~=3.23.0` due to security reasons Bump linting and formatting tools * Add `1726.removal.rst` * Update aiogram/utils/dataclass.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update aiogram/filters/callback_data.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update 1726.removal.rst * Remove `outdated` from Makefile * Add `__slots__` to `HandlerContainer` * Remove unused imports * Add `@dataclass` with `slots=True` to `HandlerContainer` --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
141 lines
4.1 KiB
Python
141 lines
4.1 KiB
Python
import asyncio
|
|
import logging
|
|
import sys
|
|
from os import getenv
|
|
from typing import Any
|
|
|
|
from aiogram import Bot, Dispatcher, F, Router, html
|
|
from aiogram.client.default import DefaultBotProperties
|
|
from aiogram.enums import ParseMode
|
|
from aiogram.filters import Command, CommandStart
|
|
from aiogram.fsm.context import FSMContext
|
|
from aiogram.fsm.state import State, StatesGroup
|
|
from aiogram.types import (
|
|
KeyboardButton,
|
|
Message,
|
|
ReplyKeyboardMarkup,
|
|
ReplyKeyboardRemove,
|
|
)
|
|
|
|
TOKEN = getenv("BOT_TOKEN")
|
|
|
|
form_router = Router()
|
|
|
|
|
|
class Form(StatesGroup):
|
|
name = State()
|
|
like_bots = State()
|
|
language = State()
|
|
|
|
|
|
@form_router.message(CommandStart())
|
|
async def command_start(message: Message, state: FSMContext) -> None:
|
|
await state.set_state(Form.name)
|
|
await message.answer(
|
|
"Hi there! What's your name?",
|
|
reply_markup=ReplyKeyboardRemove(),
|
|
)
|
|
|
|
|
|
@form_router.message(Command("cancel"))
|
|
@form_router.message(F.text.casefold() == "cancel")
|
|
async def cancel_handler(message: Message, state: FSMContext) -> None:
|
|
"""
|
|
Allow user to cancel any action
|
|
"""
|
|
current_state = await state.get_state()
|
|
if current_state is None:
|
|
return
|
|
|
|
logging.info("Cancelling state %r", current_state)
|
|
await state.clear()
|
|
await message.answer(
|
|
"Cancelled.",
|
|
reply_markup=ReplyKeyboardRemove(),
|
|
)
|
|
|
|
|
|
@form_router.message(Form.name)
|
|
async def process_name(message: Message, state: FSMContext) -> None:
|
|
await state.update_data(name=message.text)
|
|
await state.set_state(Form.like_bots)
|
|
await message.answer(
|
|
f"Nice to meet you, {html.quote(message.text)}!\nDid you like to write bots?",
|
|
reply_markup=ReplyKeyboardMarkup(
|
|
keyboard=[
|
|
[
|
|
KeyboardButton(text="Yes"),
|
|
KeyboardButton(text="No"),
|
|
],
|
|
],
|
|
resize_keyboard=True,
|
|
),
|
|
)
|
|
|
|
|
|
@form_router.message(Form.like_bots, F.text.casefold() == "no")
|
|
async def process_dont_like_write_bots(message: Message, state: FSMContext) -> None:
|
|
data = await state.get_data()
|
|
await state.clear()
|
|
await message.answer(
|
|
"Not bad not terrible.\nSee you soon.",
|
|
reply_markup=ReplyKeyboardRemove(),
|
|
)
|
|
await show_summary(message=message, data=data, positive=False)
|
|
|
|
|
|
@form_router.message(Form.like_bots, F.text.casefold() == "yes")
|
|
async def process_like_write_bots(message: Message, state: FSMContext) -> None:
|
|
await state.set_state(Form.language)
|
|
|
|
await message.reply(
|
|
"Cool! I'm too!\nWhat programming language did you use for it?",
|
|
reply_markup=ReplyKeyboardRemove(),
|
|
)
|
|
|
|
|
|
@form_router.message(Form.like_bots)
|
|
async def process_unknown_write_bots(message: Message) -> None:
|
|
await message.reply("I don't understand you :(")
|
|
|
|
|
|
@form_router.message(Form.language)
|
|
async def process_language(message: Message, state: FSMContext) -> None:
|
|
data = await state.update_data(language=message.text)
|
|
await state.clear()
|
|
|
|
if message.text.casefold() == "python":
|
|
await message.reply(
|
|
"Python, you say? That's the language that makes my circuits light up! 😉",
|
|
)
|
|
|
|
await show_summary(message=message, data=data)
|
|
|
|
|
|
async def show_summary(message: Message, data: dict[str, Any], positive: bool = True) -> None:
|
|
name = data["name"]
|
|
language = data.get("language", "<something unexpected>")
|
|
text = f"I'll keep in mind that, {html.quote(name)}, "
|
|
text += (
|
|
f"you like to write bots with {html.quote(language)}."
|
|
if positive
|
|
else "you don't like to write bots, so sad..."
|
|
)
|
|
await message.answer(text=text, reply_markup=ReplyKeyboardRemove())
|
|
|
|
|
|
async def main() -> None:
|
|
# Initialize Bot instance with default bot properties which will be passed to all API calls
|
|
bot = Bot(token=TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
|
|
|
|
dp = Dispatcher()
|
|
|
|
dp.include_router(form_router)
|
|
|
|
# Start event dispatching
|
|
await dp.start_polling(bot)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
|
|
asyncio.run(main())
|