diff --git a/.gitignore b/.gitignore
index d90ae67..4a77807 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,6 @@ myvenv
.DS_Store
*.log
__pycache__/
+debug_kb.py
+handliers_test.py
+share_2.py
diff --git a/README.md b/README.md
index 457859b..78fcdec 100644
--- a/README.md
+++ b/README.md
@@ -63,10 +63,11 @@ python3 -m pip install -r req.txt
После того как вы установите зависимости необходимо будет настроить конфигурационный файл.
-Для этого вам нужно зайти в ```config.py``` и вписать токен своего бота
+Для этого вам нужно зайти в ```config.py``` и вписать токен своего бота и ID администратора
```
TOKEN='XXX:YYY'
+ADMIN_ID=XXXXXXXXX
```
Теперь нам осталось только запустить бот:
diff --git a/app/handliers.py b/app/handliers.py
index 10c522a..2bf63cd 100644
--- a/app/handliers.py
+++ b/app/handliers.py
@@ -1,10 +1,16 @@
import asyncio
-from aiogram import F, Router
-from aiogram.filters import CommandStart, Command
+from aiogram import F, Router, Bot
+from aiogram.filters import CommandStart, Command, CommandObject
from aiogram.types import Message, CallbackQuery
from aiogram.enums import ParseMode
+from aiogram.fsm.state import State, StatesGroup
+from aiogram.fsm.context import FSMContext
import app.keyboard as kb
+import app.debug_kb as debug_kb
import sqlite3
+import app.share
+from random import randint
+from config import ADMIN_ID, TOKEN
router = Router()
@@ -22,8 +28,45 @@ async def cmd_start(message: Message):
cur.execute(insert_user, val)
+ cur.execute("SELECT * FROM users")
+ #print(cur.fetchall())
base.commit()
base.close()
- await message.answer("тестовый ответ")
\ No newline at end of file
+ await message.answer("тестовый ответ")
+
+@router.message(Command("echo"))
+async def echo(message: Message):
+ """Повторяет сообщение пользователя."""
+ await message.reply(message.text)
+
+# @router.message(Command("test"))
+# async def echo(message: Message):
+
+# await message.answer("")
+
+# await message.reply(message.text)
+
+@router.message(Command("shareold"))
+async def share(message: Message, bot: Bot):
+ if message.from_user.id == ADMIN_ID:
+ base = sqlite3.connect('users.db')
+
+ cur = base.cursor()
+
+ cur.execute("SELECT id FROM users")
+
+ users_id = cur.fetchall()
+
+ for users in users_id:
+ user = users[0]
+ await bot.send_message(user, 'тестовая рассылка')
+ print(user)
+
+ base.commit()
+
+ base.close()
+ else:
+ await message.answer("вы не администратор")
+
diff --git a/app/keyboard.py b/app/keyboard.py
index e69de29..80d69c8 100644
--- a/app/keyboard.py
+++ b/app/keyboard.py
@@ -0,0 +1,23 @@
+from aiogram.types import (
+ ReplyKeyboardMarkup,
+ KeyboardButton,
+ InlineKeyboardButton,
+ InlineKeyboardMarkup
+)
+from aiogram.utils.keyboard import ReplyKeyboardBuilder
+
+# # тестовая клавиатура, может быть потом удалена
+# test_kb = ReplyKeyboardMarkup(keyboard=
+# [
+# [
+# KeyboardButton(text='кнопка1'),
+# KeyboardButton(text="кнопка2")
+# ]
+# [
+# KeyboardButton(text="test")
+# ],
+# ],
+# resize_keyboard=True,
+# one_time_keyboard=True,
+# input_field_placeholder='тестовый ввод',
+# selective=True)
\ No newline at end of file
diff --git a/app/share.py b/app/share.py
new file mode 100644
index 0000000..e8a6e27
--- /dev/null
+++ b/app/share.py
@@ -0,0 +1,104 @@
+import asyncio
+from aiogram import F, Router, Bot
+from aiogram.filters import CommandStart, Command, CommandObject
+from aiogram.types import ContentType
+from aiogram.types import Message, CallbackQuery
+from aiogram.types import ReplyKeyboardRemove, InputMediaPhoto
+from aiogram.enums import ParseMode
+from aiogram.fsm.state import State, StatesGroup
+from aiogram.fsm.context import FSMContext
+import app.share_kb as share_kb
+import sqlite3
+from random import randint
+from config import ADMIN_ID, TOKEN
+
+share_router = Router()
+
+class Share(StatesGroup):
+ share_begin = State()
+ share_msg = State()
+
+async def send_media(bot: Bot, chat_id: int, message: Message):
+ """Функция для точной пересылки сообщения без изменений"""
+ if message.photo:
+ await bot.send_photo(
+ chat_id=chat_id,
+ photo=message.photo[-1].file_id,
+ caption=message.caption
+ )
+ elif message.video:
+ await bot.send_video(
+ chat_id=chat_id,
+ video=message.video.file_id,
+ caption=message.caption
+ )
+ elif message.document:
+ await bot.send_document(
+ chat_id=chat_id,
+ document=message.document.file_id,
+ caption=message.caption
+ )
+ elif message.text:
+ await bot.send_message(
+ chat_id=chat_id,
+ text=message.text
+ )
+
+@share_router.message(Command('share'))
+async def start_share(message: Message, state: FSMContext):
+ if message.from_user.id == ADMIN_ID:
+ await message.answer("🤔вы уверены что хотите начать рассылку?", reply_markup=share_kb.share_starting)
+ else:
+ await message.answer("⛔вы не являетесь администратором")
+
+@share_router.callback_query(F.data == 'share_cancel')
+async def share_cancel_cmd(callback: CallbackQuery, state: FSMContext):
+ await callback.answer(show_alert=False)
+ await callback.message.edit_text('❌рассылка не была начата',
+ reply_markup=None)
+ await state.clear()
+
+
+@share_router.callback_query(F.data == 'share_starting')
+async def share_start_cmd(callback: CallbackQuery, state: FSMContext):
+ await callback.answer(show_alert=False)
+ await callback.message.edit_text(
+ '✉️отправьте сообщение для рассылки\n\nучтите что можно ' \
+ 'приложить только один медиафайл',
+ reply_markup=None)
+ await state.set_state(Share.share_begin)
+
+@share_router.message(Share.share_begin)
+async def share_begin_cmd(message: Message, state: FSMContext, bot: Bot):
+ await state.update_data(share_msg=message)
+ await message.answer("🤔вы уверены что хотите разослать сообщение?",
+ reply_markup=share_kb.share_send)
+ await state.set_state(Share.share_msg)
+
+@share_router.callback_query(F.data == 'share_starting_send')
+async def share_send_cmd(callback: CallbackQuery, state: FSMContext, bot: Bot):
+ await callback.answer(show_alert=False)
+
+ data = await state.get_data()
+ share_msg = data.get('share_msg')
+
+ if not share_msg:
+ await callback.message.edit_text('❌Ошибка: сообщение для рассылки не найдено')
+ await state.clear()
+ return
+
+ base = sqlite3.connect('users.db')
+ cur = base.cursor()
+ cur.execute("SELECT id FROM users")
+ users_id = cur.fetchall()
+
+ await callback.message.edit_text('🔄Рассылаю сообщение...', reply_markup=None)
+ await asyncio.sleep(0.1) # Небольшая задержка перед началом рассылки
+
+ for user_id, in users_id:
+ if user_id != ADMIN_ID:
+ await send_media(bot, user_id, share_msg)
+
+ base.close()
+ await callback.message.edit_text('🎉Сообщение успешно разослано', reply_markup=None)
+ await state.clear()
\ No newline at end of file
diff --git a/app/share_kb.py b/app/share_kb.py
new file mode 100644
index 0000000..2f7ab0c
--- /dev/null
+++ b/app/share_kb.py
@@ -0,0 +1,19 @@
+from aiogram.types import (
+ ReplyKeyboardMarkup,
+ KeyboardButton,
+ InlineKeyboardButton,
+ InlineKeyboardMarkup,
+ ReplyKeyboardRemove
+)
+from aiogram.utils.keyboard import ReplyKeyboardBuilder, InlineKeyboardBuilder
+from aiogram.filters.callback_data import CallbackData
+
+share_starting = InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text='да✅', callback_data='share_starting'),
+ InlineKeyboardButton(text='нет❌', callback_data='share_cancel')]
+], resize_keyboard=True, input_field_placeholder='выберите действие')
+
+share_send = InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text='да✅', callback_data='share_starting_send'),
+ InlineKeyboardButton(text='нет❌', callback_data='share_cancel')]
+], resize_keyboard=True, input_field_placeholder='выберите действие')
diff --git a/bot.py b/bot.py
index 0b3f522..8be54d0 100644
--- a/bot.py
+++ b/bot.py
@@ -3,17 +3,17 @@ import logging
from aiogram import F, Router, Dispatcher, Bot
from aiogram.types import Message, CallbackQuery, User
from aiogram.filters import CommandStart, Command
-from aiogram.fsm.state import State, StatesGroup
-from aiogram.fsm.context import FSMContext
from aiogram.enums import ParseMode
-from config import TOKEN
+from config import TOKEN, ADMIN_ID
from app.handliers import router
-
-bot = Bot(token=TOKEN)
+from app.share import share_router
+bot = Bot(token=TOKEN, ParseMode="HTML")
dp = Dispatcher()
async def main():
dp.include_router(router)
+ dp.include_router(share_router)
+ await bot.delete_webhook(drop_pending_updates=True)
await dp.start_polling(bot)
if __name__ == '__main__':
diff --git a/config.py b/config.py
index 3aec734..58df515 100644
--- a/config.py
+++ b/config.py
@@ -1 +1,2 @@
-TOKEN=''
\ No newline at end of file
+TOKEN=''
+ADMIN_ID=123456789
\ No newline at end of file
diff --git a/myenv/.gitignore b/myenv/.gitignore
new file mode 100644
index 0000000..1051815
--- /dev/null
+++ b/myenv/.gitignore
@@ -0,0 +1,11 @@
+# Created by venv; see https://docs.python.org/3/library/venv.html
+share_2.py
+__pychahe__
+myenv
+debug_kb.py
+handliers_test.py
+share_2.py
+__pychahe__
+myenv
+debug_kb.py
+handliers_test.py
diff --git a/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/INSTALLER b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/METADATA b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/METADATA
new file mode 100644
index 0000000..942d74c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/METADATA
@@ -0,0 +1,318 @@
+Metadata-Version: 2.3
+Name: aiofiles
+Version: 24.1.0
+Summary: File support for asyncio.
+Project-URL: Changelog, https://github.com/Tinche/aiofiles#history
+Project-URL: Bug Tracker, https://github.com/Tinche/aiofiles/issues
+Project-URL: repository, https://github.com/Tinche/aiofiles
+Author-email: Tin Tvrtkovic
+License: Apache-2.0
+License-File: LICENSE
+License-File: NOTICE
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Framework :: AsyncIO
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Requires-Python: >=3.8
+Description-Content-Type: text/markdown
+
+# aiofiles: file support for asyncio
+
+[](https://pypi.python.org/pypi/aiofiles)
+[](https://github.com/Tinche/aiofiles/actions)
+[](https://github.com/Tinche/aiofiles/actions/workflows/main.yml)
+[](https://github.com/Tinche/aiofiles)
+[](https://github.com/psf/black)
+
+**aiofiles** is an Apache2 licensed library, written in Python, for handling local
+disk files in asyncio applications.
+
+Ordinary local file IO is blocking, and cannot easily and portably be made
+asynchronous. This means doing file IO may interfere with asyncio applications,
+which shouldn't block the executing thread. aiofiles helps with this by
+introducing asynchronous versions of files that support delegating operations to
+a separate thread pool.
+
+```python
+async with aiofiles.open('filename', mode='r') as f:
+ contents = await f.read()
+print(contents)
+'My file contents'
+```
+
+Asynchronous iteration is also supported.
+
+```python
+async with aiofiles.open('filename') as f:
+ async for line in f:
+ ...
+```
+
+Asynchronous interface to tempfile module.
+
+```python
+async with aiofiles.tempfile.TemporaryFile('wb') as f:
+ await f.write(b'Hello, World!')
+```
+
+## Features
+
+- a file API very similar to Python's standard, blocking API
+- support for buffered and unbuffered binary files, and buffered text files
+- support for `async`/`await` ([PEP 492](https://peps.python.org/pep-0492/)) constructs
+- async interface to tempfile module
+
+## Installation
+
+To install aiofiles, simply:
+
+```bash
+$ pip install aiofiles
+```
+
+## Usage
+
+Files are opened using the `aiofiles.open()` coroutine, which in addition to
+mirroring the builtin `open` accepts optional `loop` and `executor`
+arguments. If `loop` is absent, the default loop will be used, as per the
+set asyncio policy. If `executor` is not specified, the default event loop
+executor will be used.
+
+In case of success, an asynchronous file object is returned with an
+API identical to an ordinary file, except the following methods are coroutines
+and delegate to an executor:
+
+- `close`
+- `flush`
+- `isatty`
+- `read`
+- `readall`
+- `read1`
+- `readinto`
+- `readline`
+- `readlines`
+- `seek`
+- `seekable`
+- `tell`
+- `truncate`
+- `writable`
+- `write`
+- `writelines`
+
+In case of failure, one of the usual exceptions will be raised.
+
+`aiofiles.stdin`, `aiofiles.stdout`, `aiofiles.stderr`,
+`aiofiles.stdin_bytes`, `aiofiles.stdout_bytes`, and
+`aiofiles.stderr_bytes` provide async access to `sys.stdin`,
+`sys.stdout`, `sys.stderr`, and their corresponding `.buffer` properties.
+
+The `aiofiles.os` module contains executor-enabled coroutine versions of
+several useful `os` functions that deal with files:
+
+- `stat`
+- `statvfs`
+- `sendfile`
+- `rename`
+- `renames`
+- `replace`
+- `remove`
+- `unlink`
+- `mkdir`
+- `makedirs`
+- `rmdir`
+- `removedirs`
+- `link`
+- `symlink`
+- `readlink`
+- `listdir`
+- `scandir`
+- `access`
+- `getcwd`
+- `path.abspath`
+- `path.exists`
+- `path.isfile`
+- `path.isdir`
+- `path.islink`
+- `path.ismount`
+- `path.getsize`
+- `path.getatime`
+- `path.getctime`
+- `path.samefile`
+- `path.sameopenfile`
+
+### Tempfile
+
+**aiofiles.tempfile** implements the following interfaces:
+
+- TemporaryFile
+- NamedTemporaryFile
+- SpooledTemporaryFile
+- TemporaryDirectory
+
+Results return wrapped with a context manager allowing use with async with and async for.
+
+```python
+async with aiofiles.tempfile.NamedTemporaryFile('wb+') as f:
+ await f.write(b'Line1\n Line2')
+ await f.seek(0)
+ async for line in f:
+ print(line)
+
+async with aiofiles.tempfile.TemporaryDirectory() as d:
+ filename = os.path.join(d, "file.ext")
+```
+
+### Writing tests for aiofiles
+
+Real file IO can be mocked by patching `aiofiles.threadpool.sync_open`
+as desired. The return type also needs to be registered with the
+`aiofiles.threadpool.wrap` dispatcher:
+
+```python
+aiofiles.threadpool.wrap.register(mock.MagicMock)(
+ lambda *args, **kwargs: aiofiles.threadpool.AsyncBufferedIOBase(*args, **kwargs)
+)
+
+async def test_stuff():
+ write_data = 'data'
+ read_file_chunks = [
+ b'file chunks 1',
+ b'file chunks 2',
+ b'file chunks 3',
+ b'',
+ ]
+ file_chunks_iter = iter(read_file_chunks)
+
+ mock_file_stream = mock.MagicMock(
+ read=lambda *args, **kwargs: next(file_chunks_iter)
+ )
+
+ with mock.patch('aiofiles.threadpool.sync_open', return_value=mock_file_stream) as mock_open:
+ async with aiofiles.open('filename', 'w') as f:
+ await f.write(write_data)
+ assert f.read() == b'file chunks 1'
+
+ mock_file_stream.write.assert_called_once_with(write_data)
+```
+
+### History
+
+#### 24.1.0 (2024-06-24)
+
+- Import `os.link` conditionally to fix importing on android.
+ [#175](https://github.com/Tinche/aiofiles/issues/175)
+- Remove spurious items from `aiofiles.os.__all__` when running on Windows.
+- Switch to more modern async idioms: Remove types.coroutine and make AiofilesContextManager an awaitable instead a coroutine.
+- Add `aiofiles.os.path.abspath` and `aiofiles.os.getcwd`.
+ [#174](https://github.com/Tinche/aiofiles/issues/181)
+- _aiofiles_ is now tested on Python 3.13 too.
+ [#184](https://github.com/Tinche/aiofiles/pull/184)
+- Dropped Python 3.7 support. If you require it, use version 23.2.1.
+
+#### 23.2.1 (2023-08-09)
+
+- Import `os.statvfs` conditionally to fix importing on non-UNIX systems.
+ [#171](https://github.com/Tinche/aiofiles/issues/171) [#172](https://github.com/Tinche/aiofiles/pull/172)
+- aiofiles is now also tested on Windows.
+
+#### 23.2.0 (2023-08-09)
+
+- aiofiles is now tested on Python 3.12 too.
+ [#166](https://github.com/Tinche/aiofiles/issues/166) [#168](https://github.com/Tinche/aiofiles/pull/168)
+- On Python 3.12, `aiofiles.tempfile.NamedTemporaryFile` now accepts a `delete_on_close` argument, just like the stdlib version.
+- On Python 3.12, `aiofiles.tempfile.NamedTemporaryFile` no longer exposes a `delete` attribute, just like the stdlib version.
+- Added `aiofiles.os.statvfs` and `aiofiles.os.path.ismount`.
+ [#162](https://github.com/Tinche/aiofiles/pull/162)
+- Use [PDM](https://pdm.fming.dev/latest/) instead of Poetry.
+ [#169](https://github.com/Tinche/aiofiles/pull/169)
+
+#### 23.1.0 (2023-02-09)
+
+- Added `aiofiles.os.access`.
+ [#146](https://github.com/Tinche/aiofiles/pull/146)
+- Removed `aiofiles.tempfile.temptypes.AsyncSpooledTemporaryFile.softspace`.
+ [#151](https://github.com/Tinche/aiofiles/pull/151)
+- Added `aiofiles.stdin`, `aiofiles.stdin_bytes`, and other stdio streams.
+ [#154](https://github.com/Tinche/aiofiles/pull/154)
+- Transition to `asyncio.get_running_loop` (vs `asyncio.get_event_loop`) internally.
+
+#### 22.1.0 (2022-09-04)
+
+- Added `aiofiles.os.path.islink`.
+ [#126](https://github.com/Tinche/aiofiles/pull/126)
+- Added `aiofiles.os.readlink`.
+ [#125](https://github.com/Tinche/aiofiles/pull/125)
+- Added `aiofiles.os.symlink`.
+ [#124](https://github.com/Tinche/aiofiles/pull/124)
+- Added `aiofiles.os.unlink`.
+ [#123](https://github.com/Tinche/aiofiles/pull/123)
+- Added `aiofiles.os.link`.
+ [#121](https://github.com/Tinche/aiofiles/pull/121)
+- Added `aiofiles.os.renames`.
+ [#120](https://github.com/Tinche/aiofiles/pull/120)
+- Added `aiofiles.os.{listdir, scandir}`.
+ [#143](https://github.com/Tinche/aiofiles/pull/143)
+- Switched to CalVer.
+- Dropped Python 3.6 support. If you require it, use version 0.8.0.
+- aiofiles is now tested on Python 3.11.
+
+#### 0.8.0 (2021-11-27)
+
+- aiofiles is now tested on Python 3.10.
+- Added `aiofiles.os.replace`.
+ [#107](https://github.com/Tinche/aiofiles/pull/107)
+- Added `aiofiles.os.{makedirs, removedirs}`.
+- Added `aiofiles.os.path.{exists, isfile, isdir, getsize, getatime, getctime, samefile, sameopenfile}`.
+ [#63](https://github.com/Tinche/aiofiles/pull/63)
+- Added `suffix`, `prefix`, `dir` args to `aiofiles.tempfile.TemporaryDirectory`.
+ [#116](https://github.com/Tinche/aiofiles/pull/116)
+
+#### 0.7.0 (2021-05-17)
+
+- Added the `aiofiles.tempfile` module for async temporary files.
+ [#56](https://github.com/Tinche/aiofiles/pull/56)
+- Switched to Poetry and GitHub actions.
+- Dropped 3.5 support.
+
+#### 0.6.0 (2020-10-27)
+
+- `aiofiles` is now tested on ppc64le.
+- Added `name` and `mode` properties to async file objects.
+ [#82](https://github.com/Tinche/aiofiles/pull/82)
+- Fixed a DeprecationWarning internally.
+ [#75](https://github.com/Tinche/aiofiles/pull/75)
+- Python 3.9 support and tests.
+
+#### 0.5.0 (2020-04-12)
+
+- Python 3.8 support. Code base modernization (using `async/await` instead of `asyncio.coroutine`/`yield from`).
+- Added `aiofiles.os.remove`, `aiofiles.os.rename`, `aiofiles.os.mkdir`, `aiofiles.os.rmdir`.
+ [#62](https://github.com/Tinche/aiofiles/pull/62)
+
+#### 0.4.0 (2018-08-11)
+
+- Python 3.7 support.
+- Removed Python 3.3/3.4 support. If you use these versions, stick to aiofiles 0.3.x.
+
+#### 0.3.2 (2017-09-23)
+
+- The LICENSE is now included in the sdist.
+ [#31](https://github.com/Tinche/aiofiles/pull/31)
+
+#### 0.3.1 (2017-03-10)
+
+- Introduced a changelog.
+- `aiofiles.os.sendfile` will now work if the standard `os` module contains a `sendfile` function.
+
+### Contributing
+
+Contributions are very welcome. Tests can be run with `tox`, please ensure
+the coverage at least stays the same before you submit a pull request.
diff --git a/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/RECORD b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/RECORD
new file mode 100644
index 0000000..0e43e01
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/RECORD
@@ -0,0 +1,26 @@
+aiofiles-24.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+aiofiles-24.1.0.dist-info/METADATA,sha256=CvUJx21XclgI1Lp5Bt_4AyJesRYg0xCSx4exJZVmaSA,10708
+aiofiles-24.1.0.dist-info/RECORD,,
+aiofiles-24.1.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
+aiofiles-24.1.0.dist-info/licenses/LICENSE,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325
+aiofiles-24.1.0.dist-info/licenses/NOTICE,sha256=EExY0dRQvWR0wJ2LZLwBgnM6YKw9jCU-M0zegpRSD_E,55
+aiofiles/__init__.py,sha256=1iAMJQyJtX3LGIS0AoFTJeO1aJ_RK2jpBSBhg0VoIrE,344
+aiofiles/__pycache__/__init__.cpython-313.pyc,,
+aiofiles/__pycache__/base.cpython-313.pyc,,
+aiofiles/__pycache__/os.cpython-313.pyc,,
+aiofiles/__pycache__/ospath.cpython-313.pyc,,
+aiofiles/base.py,sha256=zo0FgkCqZ5aosjvxqIvDf2t-RFg1Lc6X8P6rZ56p6fQ,1784
+aiofiles/os.py,sha256=0DrsG-eH4h7xRzglv9pIWsQuzqe7ZhVYw5FQS18fIys,1153
+aiofiles/ospath.py,sha256=WaYelz_k6ykAFRLStr4bqYIfCVQ-5GGzIqIizykbY2Q,794
+aiofiles/tempfile/__init__.py,sha256=hFSNTOjOUv371Ozdfy6FIxeln46Nm3xOVh4ZR3Q94V0,10244
+aiofiles/tempfile/__pycache__/__init__.cpython-313.pyc,,
+aiofiles/tempfile/__pycache__/temptypes.cpython-313.pyc,,
+aiofiles/tempfile/temptypes.py,sha256=ddEvNjMLVlr7WUILCe6ypTqw77yREeIonTk16Uw_NVs,2093
+aiofiles/threadpool/__init__.py,sha256=kt0hwwx3bLiYtnA1SORhW8mJ6z4W9Xr7MbY80UIJJrI,3133
+aiofiles/threadpool/__pycache__/__init__.cpython-313.pyc,,
+aiofiles/threadpool/__pycache__/binary.cpython-313.pyc,,
+aiofiles/threadpool/__pycache__/text.cpython-313.pyc,,
+aiofiles/threadpool/__pycache__/utils.cpython-313.pyc,,
+aiofiles/threadpool/binary.py,sha256=hp-km9VCRu0MLz_wAEUfbCz7OL7xtn9iGAawabpnp5U,2315
+aiofiles/threadpool/text.py,sha256=fNmpw2PEkj0BZSldipJXAgZqVGLxALcfOMiuDQ54Eas,1223
+aiofiles/threadpool/utils.py,sha256=B59dSZwO_WZs2dFFycKeA91iD2Xq2nNw1EFF8YMBI5k,1868
diff --git a/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/WHEEL b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/WHEEL
new file mode 100644
index 0000000..cdd68a4
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/WHEEL
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: hatchling 1.25.0
+Root-Is-Purelib: true
+Tag: py3-none-any
diff --git a/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/licenses/LICENSE b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/licenses/LICENSE
new file mode 100644
index 0000000..e06d208
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/licenses/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/licenses/NOTICE b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/licenses/NOTICE
new file mode 100644
index 0000000..d134f28
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles-24.1.0.dist-info/licenses/NOTICE
@@ -0,0 +1,2 @@
+Asyncio support for files
+Copyright 2016 Tin Tvrtkovic
diff --git a/myenv/Lib/site-packages/aiofiles/__init__.py b/myenv/Lib/site-packages/aiofiles/__init__.py
new file mode 100644
index 0000000..9e75111
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/__init__.py
@@ -0,0 +1,22 @@
+"""Utilities for asyncio-friendly file handling."""
+from .threadpool import (
+ open,
+ stdin,
+ stdout,
+ stderr,
+ stdin_bytes,
+ stdout_bytes,
+ stderr_bytes,
+)
+from . import tempfile
+
+__all__ = [
+ "open",
+ "tempfile",
+ "stdin",
+ "stdout",
+ "stderr",
+ "stdin_bytes",
+ "stdout_bytes",
+ "stderr_bytes",
+]
diff --git a/myenv/Lib/site-packages/aiofiles/base.py b/myenv/Lib/site-packages/aiofiles/base.py
new file mode 100644
index 0000000..64f7d6b
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/base.py
@@ -0,0 +1,69 @@
+"""Various base classes."""
+from collections.abc import Awaitable
+from contextlib import AbstractAsyncContextManager
+from asyncio import get_running_loop
+
+
+class AsyncBase:
+ def __init__(self, file, loop, executor):
+ self._file = file
+ self._executor = executor
+ self._ref_loop = loop
+
+ @property
+ def _loop(self):
+ return self._ref_loop or get_running_loop()
+
+ def __aiter__(self):
+ """We are our own iterator."""
+ return self
+
+ def __repr__(self):
+ return super().__repr__() + " wrapping " + repr(self._file)
+
+ async def __anext__(self):
+ """Simulate normal file iteration."""
+ line = await self.readline()
+ if line:
+ return line
+ else:
+ raise StopAsyncIteration
+
+
+class AsyncIndirectBase(AsyncBase):
+ def __init__(self, name, loop, executor, indirect):
+ self._indirect = indirect
+ self._name = name
+ super().__init__(None, loop, executor)
+
+ @property
+ def _file(self):
+ return self._indirect()
+
+ @_file.setter
+ def _file(self, v):
+ pass # discard writes
+
+
+class AiofilesContextManager(Awaitable, AbstractAsyncContextManager):
+ """An adjusted async context manager for aiofiles."""
+
+ __slots__ = ("_coro", "_obj")
+
+ def __init__(self, coro):
+ self._coro = coro
+ self._obj = None
+
+ def __await__(self):
+ if self._obj is None:
+ self._obj = yield from self._coro.__await__()
+ return self._obj
+
+ async def __aenter__(self):
+ return await self
+
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
+ await get_running_loop().run_in_executor(
+ None, self._obj._file.__exit__, exc_type, exc_val, exc_tb
+ )
+ self._obj = None
diff --git a/myenv/Lib/site-packages/aiofiles/os.py b/myenv/Lib/site-packages/aiofiles/os.py
new file mode 100644
index 0000000..92243fa
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/os.py
@@ -0,0 +1,58 @@
+"""Async executor versions of file functions from the os module."""
+
+import os
+
+from . import ospath as path
+from .ospath import wrap
+
+__all__ = [
+ "path",
+ "stat",
+ "rename",
+ "renames",
+ "replace",
+ "remove",
+ "unlink",
+ "mkdir",
+ "makedirs",
+ "rmdir",
+ "removedirs",
+ "symlink",
+ "readlink",
+ "listdir",
+ "scandir",
+ "access",
+ "wrap",
+ "getcwd",
+]
+if hasattr(os, "link"):
+ __all__ += ["link"]
+if hasattr(os, "sendfile"):
+ __all__ += ["sendfile"]
+if hasattr(os, "statvfs"):
+ __all__ += ["statvfs"]
+
+
+stat = wrap(os.stat)
+rename = wrap(os.rename)
+renames = wrap(os.renames)
+replace = wrap(os.replace)
+remove = wrap(os.remove)
+unlink = wrap(os.unlink)
+mkdir = wrap(os.mkdir)
+makedirs = wrap(os.makedirs)
+rmdir = wrap(os.rmdir)
+removedirs = wrap(os.removedirs)
+symlink = wrap(os.symlink)
+readlink = wrap(os.readlink)
+listdir = wrap(os.listdir)
+scandir = wrap(os.scandir)
+access = wrap(os.access)
+getcwd = wrap(os.getcwd)
+
+if hasattr(os, "link"):
+ link = wrap(os.link)
+if hasattr(os, "sendfile"):
+ sendfile = wrap(os.sendfile)
+if hasattr(os, "statvfs"):
+ statvfs = wrap(os.statvfs)
diff --git a/myenv/Lib/site-packages/aiofiles/ospath.py b/myenv/Lib/site-packages/aiofiles/ospath.py
new file mode 100644
index 0000000..387d68d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/ospath.py
@@ -0,0 +1,30 @@
+"""Async executor versions of file functions from the os.path module."""
+
+import asyncio
+from functools import partial, wraps
+from os import path
+
+
+def wrap(func):
+ @wraps(func)
+ async def run(*args, loop=None, executor=None, **kwargs):
+ if loop is None:
+ loop = asyncio.get_running_loop()
+ pfunc = partial(func, *args, **kwargs)
+ return await loop.run_in_executor(executor, pfunc)
+
+ return run
+
+
+exists = wrap(path.exists)
+isfile = wrap(path.isfile)
+isdir = wrap(path.isdir)
+islink = wrap(path.islink)
+ismount = wrap(path.ismount)
+getsize = wrap(path.getsize)
+getmtime = wrap(path.getmtime)
+getatime = wrap(path.getatime)
+getctime = wrap(path.getctime)
+samefile = wrap(path.samefile)
+sameopenfile = wrap(path.sameopenfile)
+abspath = wrap(path.abspath)
diff --git a/myenv/Lib/site-packages/aiofiles/tempfile/__init__.py b/myenv/Lib/site-packages/aiofiles/tempfile/__init__.py
new file mode 100644
index 0000000..75d10b6
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/tempfile/__init__.py
@@ -0,0 +1,357 @@
+import asyncio
+from functools import partial, singledispatch
+from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOBase
+from tempfile import NamedTemporaryFile as syncNamedTemporaryFile
+from tempfile import SpooledTemporaryFile as syncSpooledTemporaryFile
+from tempfile import TemporaryDirectory as syncTemporaryDirectory
+from tempfile import TemporaryFile as syncTemporaryFile
+from tempfile import _TemporaryFileWrapper as syncTemporaryFileWrapper
+
+from ..base import AiofilesContextManager
+from ..threadpool.binary import AsyncBufferedIOBase, AsyncBufferedReader, AsyncFileIO
+from ..threadpool.text import AsyncTextIOWrapper
+from .temptypes import AsyncSpooledTemporaryFile, AsyncTemporaryDirectory
+import sys
+
+__all__ = [
+ "NamedTemporaryFile",
+ "TemporaryFile",
+ "SpooledTemporaryFile",
+ "TemporaryDirectory",
+]
+
+
+# ================================================================
+# Public methods for async open and return of temp file/directory
+# objects with async interface
+# ================================================================
+if sys.version_info >= (3, 12):
+
+ def NamedTemporaryFile(
+ mode="w+b",
+ buffering=-1,
+ encoding=None,
+ newline=None,
+ suffix=None,
+ prefix=None,
+ dir=None,
+ delete=True,
+ delete_on_close=True,
+ loop=None,
+ executor=None,
+ ):
+ """Async open a named temporary file"""
+ return AiofilesContextManager(
+ _temporary_file(
+ named=True,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ delete=delete,
+ delete_on_close=delete_on_close,
+ loop=loop,
+ executor=executor,
+ )
+ )
+
+else:
+
+ def NamedTemporaryFile(
+ mode="w+b",
+ buffering=-1,
+ encoding=None,
+ newline=None,
+ suffix=None,
+ prefix=None,
+ dir=None,
+ delete=True,
+ loop=None,
+ executor=None,
+ ):
+ """Async open a named temporary file"""
+ return AiofilesContextManager(
+ _temporary_file(
+ named=True,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ delete=delete,
+ loop=loop,
+ executor=executor,
+ )
+ )
+
+
+def TemporaryFile(
+ mode="w+b",
+ buffering=-1,
+ encoding=None,
+ newline=None,
+ suffix=None,
+ prefix=None,
+ dir=None,
+ loop=None,
+ executor=None,
+):
+ """Async open an unnamed temporary file"""
+ return AiofilesContextManager(
+ _temporary_file(
+ named=False,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ loop=loop,
+ executor=executor,
+ )
+ )
+
+
+def SpooledTemporaryFile(
+ max_size=0,
+ mode="w+b",
+ buffering=-1,
+ encoding=None,
+ newline=None,
+ suffix=None,
+ prefix=None,
+ dir=None,
+ loop=None,
+ executor=None,
+):
+ """Async open a spooled temporary file"""
+ return AiofilesContextManager(
+ _spooled_temporary_file(
+ max_size=max_size,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ loop=loop,
+ executor=executor,
+ )
+ )
+
+
+def TemporaryDirectory(suffix=None, prefix=None, dir=None, loop=None, executor=None):
+ """Async open a temporary directory"""
+ return AiofilesContextManagerTempDir(
+ _temporary_directory(
+ suffix=suffix, prefix=prefix, dir=dir, loop=loop, executor=executor
+ )
+ )
+
+
+# =========================================================
+# Internal coroutines to open new temp files/directories
+# =========================================================
+if sys.version_info >= (3, 12):
+
+ async def _temporary_file(
+ named=True,
+ mode="w+b",
+ buffering=-1,
+ encoding=None,
+ newline=None,
+ suffix=None,
+ prefix=None,
+ dir=None,
+ delete=True,
+ delete_on_close=True,
+ loop=None,
+ executor=None,
+ max_size=0,
+ ):
+ """Async method to open a temporary file with async interface"""
+ if loop is None:
+ loop = asyncio.get_running_loop()
+
+ if named:
+ cb = partial(
+ syncNamedTemporaryFile,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ delete=delete,
+ delete_on_close=delete_on_close,
+ )
+ else:
+ cb = partial(
+ syncTemporaryFile,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ )
+
+ f = await loop.run_in_executor(executor, cb)
+
+ # Wrap based on type of underlying IO object
+ if type(f) is syncTemporaryFileWrapper:
+ # _TemporaryFileWrapper was used (named files)
+ result = wrap(f.file, f, loop=loop, executor=executor)
+ result._closer = f._closer
+ return result
+ else:
+ # IO object was returned directly without wrapper
+ return wrap(f, f, loop=loop, executor=executor)
+
+else:
+
+ async def _temporary_file(
+ named=True,
+ mode="w+b",
+ buffering=-1,
+ encoding=None,
+ newline=None,
+ suffix=None,
+ prefix=None,
+ dir=None,
+ delete=True,
+ loop=None,
+ executor=None,
+ max_size=0,
+ ):
+ """Async method to open a temporary file with async interface"""
+ if loop is None:
+ loop = asyncio.get_running_loop()
+
+ if named:
+ cb = partial(
+ syncNamedTemporaryFile,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ delete=delete,
+ )
+ else:
+ cb = partial(
+ syncTemporaryFile,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ )
+
+ f = await loop.run_in_executor(executor, cb)
+
+ # Wrap based on type of underlying IO object
+ if type(f) is syncTemporaryFileWrapper:
+ # _TemporaryFileWrapper was used (named files)
+ result = wrap(f.file, f, loop=loop, executor=executor)
+ # add delete property
+ result.delete = f.delete
+ return result
+ else:
+ # IO object was returned directly without wrapper
+ return wrap(f, f, loop=loop, executor=executor)
+
+
+async def _spooled_temporary_file(
+ max_size=0,
+ mode="w+b",
+ buffering=-1,
+ encoding=None,
+ newline=None,
+ suffix=None,
+ prefix=None,
+ dir=None,
+ loop=None,
+ executor=None,
+):
+ """Open a spooled temporary file with async interface"""
+ if loop is None:
+ loop = asyncio.get_running_loop()
+
+ cb = partial(
+ syncSpooledTemporaryFile,
+ max_size=max_size,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ newline=newline,
+ suffix=suffix,
+ prefix=prefix,
+ dir=dir,
+ )
+
+ f = await loop.run_in_executor(executor, cb)
+
+ # Single interface provided by SpooledTemporaryFile for all modes
+ return AsyncSpooledTemporaryFile(f, loop=loop, executor=executor)
+
+
+async def _temporary_directory(
+ suffix=None, prefix=None, dir=None, loop=None, executor=None
+):
+ """Async method to open a temporary directory with async interface"""
+ if loop is None:
+ loop = asyncio.get_running_loop()
+
+ cb = partial(syncTemporaryDirectory, suffix, prefix, dir)
+ f = await loop.run_in_executor(executor, cb)
+
+ return AsyncTemporaryDirectory(f, loop=loop, executor=executor)
+
+
+class AiofilesContextManagerTempDir(AiofilesContextManager):
+ """With returns the directory location, not the object (matching sync lib)"""
+
+ async def __aenter__(self):
+ self._obj = await self._coro
+ return self._obj.name
+
+
+@singledispatch
+def wrap(base_io_obj, file, *, loop=None, executor=None):
+ """Wrap the object with interface based on type of underlying IO"""
+ raise TypeError("Unsupported IO type: {}".format(base_io_obj))
+
+
+@wrap.register(TextIOBase)
+def _(base_io_obj, file, *, loop=None, executor=None):
+ return AsyncTextIOWrapper(file, loop=loop, executor=executor)
+
+
+@wrap.register(BufferedWriter)
+def _(base_io_obj, file, *, loop=None, executor=None):
+ return AsyncBufferedIOBase(file, loop=loop, executor=executor)
+
+
+@wrap.register(BufferedReader)
+@wrap.register(BufferedRandom)
+def _(base_io_obj, file, *, loop=None, executor=None):
+ return AsyncBufferedReader(file, loop=loop, executor=executor)
+
+
+@wrap.register(FileIO)
+def _(base_io_obj, file, *, loop=None, executor=None):
+ return AsyncFileIO(file, loop=loop, executor=executor)
diff --git a/myenv/Lib/site-packages/aiofiles/tempfile/temptypes.py b/myenv/Lib/site-packages/aiofiles/tempfile/temptypes.py
new file mode 100644
index 0000000..dccee6c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/tempfile/temptypes.py
@@ -0,0 +1,69 @@
+"""Async wrappers for spooled temp files and temp directory objects"""
+from functools import partial
+
+from ..base import AsyncBase
+from ..threadpool.utils import (
+ cond_delegate_to_executor,
+ delegate_to_executor,
+ proxy_property_directly,
+)
+
+
+@delegate_to_executor("fileno", "rollover")
+@cond_delegate_to_executor(
+ "close",
+ "flush",
+ "isatty",
+ "read",
+ "readline",
+ "readlines",
+ "seek",
+ "tell",
+ "truncate",
+)
+@proxy_property_directly("closed", "encoding", "mode", "name", "newlines")
+class AsyncSpooledTemporaryFile(AsyncBase):
+ """Async wrapper for SpooledTemporaryFile class"""
+
+ async def _check(self):
+ if self._file._rolled:
+ return
+ max_size = self._file._max_size
+ if max_size and self._file.tell() > max_size:
+ await self.rollover()
+
+ async def write(self, s):
+ """Implementation to anticipate rollover"""
+ if self._file._rolled:
+ cb = partial(self._file.write, s)
+ return await self._loop.run_in_executor(self._executor, cb)
+ else:
+ file = self._file._file # reference underlying base IO object
+ rv = file.write(s)
+ await self._check()
+ return rv
+
+ async def writelines(self, iterable):
+ """Implementation to anticipate rollover"""
+ if self._file._rolled:
+ cb = partial(self._file.writelines, iterable)
+ return await self._loop.run_in_executor(self._executor, cb)
+ else:
+ file = self._file._file # reference underlying base IO object
+ rv = file.writelines(iterable)
+ await self._check()
+ return rv
+
+
+@delegate_to_executor("cleanup")
+@proxy_property_directly("name")
+class AsyncTemporaryDirectory:
+ """Async wrapper for TemporaryDirectory class"""
+
+ def __init__(self, file, loop, executor):
+ self._file = file
+ self._loop = loop
+ self._executor = executor
+
+ async def close(self):
+ await self.cleanup()
diff --git a/myenv/Lib/site-packages/aiofiles/threadpool/__init__.py b/myenv/Lib/site-packages/aiofiles/threadpool/__init__.py
new file mode 100644
index 0000000..e543283
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/threadpool/__init__.py
@@ -0,0 +1,139 @@
+"""Handle files using a thread pool executor."""
+import asyncio
+import sys
+from functools import partial, singledispatch
+from io import (
+ BufferedIOBase,
+ BufferedRandom,
+ BufferedReader,
+ BufferedWriter,
+ FileIO,
+ TextIOBase,
+)
+
+from ..base import AiofilesContextManager
+from .binary import (
+ AsyncBufferedIOBase,
+ AsyncBufferedReader,
+ AsyncFileIO,
+ AsyncIndirectBufferedIOBase,
+)
+from .text import AsyncTextIndirectIOWrapper, AsyncTextIOWrapper
+
+sync_open = open
+
+__all__ = (
+ "open",
+ "stdin",
+ "stdout",
+ "stderr",
+ "stdin_bytes",
+ "stdout_bytes",
+ "stderr_bytes",
+)
+
+
+def open(
+ file,
+ mode="r",
+ buffering=-1,
+ encoding=None,
+ errors=None,
+ newline=None,
+ closefd=True,
+ opener=None,
+ *,
+ loop=None,
+ executor=None,
+):
+ return AiofilesContextManager(
+ _open(
+ file,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ errors=errors,
+ newline=newline,
+ closefd=closefd,
+ opener=opener,
+ loop=loop,
+ executor=executor,
+ )
+ )
+
+
+async def _open(
+ file,
+ mode="r",
+ buffering=-1,
+ encoding=None,
+ errors=None,
+ newline=None,
+ closefd=True,
+ opener=None,
+ *,
+ loop=None,
+ executor=None,
+):
+ """Open an asyncio file."""
+ if loop is None:
+ loop = asyncio.get_running_loop()
+ cb = partial(
+ sync_open,
+ file,
+ mode=mode,
+ buffering=buffering,
+ encoding=encoding,
+ errors=errors,
+ newline=newline,
+ closefd=closefd,
+ opener=opener,
+ )
+ f = await loop.run_in_executor(executor, cb)
+
+ return wrap(f, loop=loop, executor=executor)
+
+
+@singledispatch
+def wrap(file, *, loop=None, executor=None):
+ raise TypeError("Unsupported io type: {}.".format(file))
+
+
+@wrap.register(TextIOBase)
+def _(file, *, loop=None, executor=None):
+ return AsyncTextIOWrapper(file, loop=loop, executor=executor)
+
+
+@wrap.register(BufferedWriter)
+@wrap.register(BufferedIOBase)
+def _(file, *, loop=None, executor=None):
+ return AsyncBufferedIOBase(file, loop=loop, executor=executor)
+
+
+@wrap.register(BufferedReader)
+@wrap.register(BufferedRandom)
+def _(file, *, loop=None, executor=None):
+ return AsyncBufferedReader(file, loop=loop, executor=executor)
+
+
+@wrap.register(FileIO)
+def _(file, *, loop=None, executor=None):
+ return AsyncFileIO(file, loop=loop, executor=executor)
+
+
+stdin = AsyncTextIndirectIOWrapper("sys.stdin", None, None, indirect=lambda: sys.stdin)
+stdout = AsyncTextIndirectIOWrapper(
+ "sys.stdout", None, None, indirect=lambda: sys.stdout
+)
+stderr = AsyncTextIndirectIOWrapper(
+ "sys.stderr", None, None, indirect=lambda: sys.stderr
+)
+stdin_bytes = AsyncIndirectBufferedIOBase(
+ "sys.stdin.buffer", None, None, indirect=lambda: sys.stdin.buffer
+)
+stdout_bytes = AsyncIndirectBufferedIOBase(
+ "sys.stdout.buffer", None, None, indirect=lambda: sys.stdout.buffer
+)
+stderr_bytes = AsyncIndirectBufferedIOBase(
+ "sys.stderr.buffer", None, None, indirect=lambda: sys.stderr.buffer
+)
diff --git a/myenv/Lib/site-packages/aiofiles/threadpool/binary.py b/myenv/Lib/site-packages/aiofiles/threadpool/binary.py
new file mode 100644
index 0000000..63fcaff
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/threadpool/binary.py
@@ -0,0 +1,104 @@
+from ..base import AsyncBase, AsyncIndirectBase
+from .utils import delegate_to_executor, proxy_method_directly, proxy_property_directly
+
+
+@delegate_to_executor(
+ "close",
+ "flush",
+ "isatty",
+ "read",
+ "read1",
+ "readinto",
+ "readline",
+ "readlines",
+ "seek",
+ "seekable",
+ "tell",
+ "truncate",
+ "writable",
+ "write",
+ "writelines",
+)
+@proxy_method_directly("detach", "fileno", "readable")
+@proxy_property_directly("closed", "raw", "name", "mode")
+class AsyncBufferedIOBase(AsyncBase):
+ """The asyncio executor version of io.BufferedWriter and BufferedIOBase."""
+
+
+@delegate_to_executor("peek")
+class AsyncBufferedReader(AsyncBufferedIOBase):
+ """The asyncio executor version of io.BufferedReader and Random."""
+
+
+@delegate_to_executor(
+ "close",
+ "flush",
+ "isatty",
+ "read",
+ "readall",
+ "readinto",
+ "readline",
+ "readlines",
+ "seek",
+ "seekable",
+ "tell",
+ "truncate",
+ "writable",
+ "write",
+ "writelines",
+)
+@proxy_method_directly("fileno", "readable")
+@proxy_property_directly("closed", "name", "mode")
+class AsyncFileIO(AsyncBase):
+ """The asyncio executor version of io.FileIO."""
+
+
+@delegate_to_executor(
+ "close",
+ "flush",
+ "isatty",
+ "read",
+ "read1",
+ "readinto",
+ "readline",
+ "readlines",
+ "seek",
+ "seekable",
+ "tell",
+ "truncate",
+ "writable",
+ "write",
+ "writelines",
+)
+@proxy_method_directly("detach", "fileno", "readable")
+@proxy_property_directly("closed", "raw", "name", "mode")
+class AsyncIndirectBufferedIOBase(AsyncIndirectBase):
+ """The indirect asyncio executor version of io.BufferedWriter and BufferedIOBase."""
+
+
+@delegate_to_executor("peek")
+class AsyncIndirectBufferedReader(AsyncIndirectBufferedIOBase):
+ """The indirect asyncio executor version of io.BufferedReader and Random."""
+
+
+@delegate_to_executor(
+ "close",
+ "flush",
+ "isatty",
+ "read",
+ "readall",
+ "readinto",
+ "readline",
+ "readlines",
+ "seek",
+ "seekable",
+ "tell",
+ "truncate",
+ "writable",
+ "write",
+ "writelines",
+)
+@proxy_method_directly("fileno", "readable")
+@proxy_property_directly("closed", "name", "mode")
+class AsyncIndirectFileIO(AsyncIndirectBase):
+ """The indirect asyncio executor version of io.FileIO."""
diff --git a/myenv/Lib/site-packages/aiofiles/threadpool/text.py b/myenv/Lib/site-packages/aiofiles/threadpool/text.py
new file mode 100644
index 0000000..0e62590
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/threadpool/text.py
@@ -0,0 +1,64 @@
+from ..base import AsyncBase, AsyncIndirectBase
+from .utils import delegate_to_executor, proxy_method_directly, proxy_property_directly
+
+
+@delegate_to_executor(
+ "close",
+ "flush",
+ "isatty",
+ "read",
+ "readable",
+ "readline",
+ "readlines",
+ "seek",
+ "seekable",
+ "tell",
+ "truncate",
+ "write",
+ "writable",
+ "writelines",
+)
+@proxy_method_directly("detach", "fileno", "readable")
+@proxy_property_directly(
+ "buffer",
+ "closed",
+ "encoding",
+ "errors",
+ "line_buffering",
+ "newlines",
+ "name",
+ "mode",
+)
+class AsyncTextIOWrapper(AsyncBase):
+ """The asyncio executor version of io.TextIOWrapper."""
+
+
+@delegate_to_executor(
+ "close",
+ "flush",
+ "isatty",
+ "read",
+ "readable",
+ "readline",
+ "readlines",
+ "seek",
+ "seekable",
+ "tell",
+ "truncate",
+ "write",
+ "writable",
+ "writelines",
+)
+@proxy_method_directly("detach", "fileno", "readable")
+@proxy_property_directly(
+ "buffer",
+ "closed",
+ "encoding",
+ "errors",
+ "line_buffering",
+ "newlines",
+ "name",
+ "mode",
+)
+class AsyncTextIndirectIOWrapper(AsyncIndirectBase):
+ """The indirect asyncio executor version of io.TextIOWrapper."""
diff --git a/myenv/Lib/site-packages/aiofiles/threadpool/utils.py b/myenv/Lib/site-packages/aiofiles/threadpool/utils.py
new file mode 100644
index 0000000..5fd3bb9
--- /dev/null
+++ b/myenv/Lib/site-packages/aiofiles/threadpool/utils.py
@@ -0,0 +1,72 @@
+import functools
+
+
+def delegate_to_executor(*attrs):
+ def cls_builder(cls):
+ for attr_name in attrs:
+ setattr(cls, attr_name, _make_delegate_method(attr_name))
+ return cls
+
+ return cls_builder
+
+
+def proxy_method_directly(*attrs):
+ def cls_builder(cls):
+ for attr_name in attrs:
+ setattr(cls, attr_name, _make_proxy_method(attr_name))
+ return cls
+
+ return cls_builder
+
+
+def proxy_property_directly(*attrs):
+ def cls_builder(cls):
+ for attr_name in attrs:
+ setattr(cls, attr_name, _make_proxy_property(attr_name))
+ return cls
+
+ return cls_builder
+
+
+def cond_delegate_to_executor(*attrs):
+ def cls_builder(cls):
+ for attr_name in attrs:
+ setattr(cls, attr_name, _make_cond_delegate_method(attr_name))
+ return cls
+
+ return cls_builder
+
+
+def _make_delegate_method(attr_name):
+ async def method(self, *args, **kwargs):
+ cb = functools.partial(getattr(self._file, attr_name), *args, **kwargs)
+ return await self._loop.run_in_executor(self._executor, cb)
+
+ return method
+
+
+def _make_proxy_method(attr_name):
+ def method(self, *args, **kwargs):
+ return getattr(self._file, attr_name)(*args, **kwargs)
+
+ return method
+
+
+def _make_proxy_property(attr_name):
+ def proxy_property(self):
+ return getattr(self._file, attr_name)
+
+ return property(proxy_property)
+
+
+def _make_cond_delegate_method(attr_name):
+ """For spooled temp files, delegate only if rolled to file object"""
+
+ async def method(self, *args, **kwargs):
+ if self._file._rolled:
+ cb = functools.partial(getattr(self._file, attr_name), *args, **kwargs)
+ return await self._loop.run_in_executor(self._executor, cb)
+ else:
+ return getattr(self._file, attr_name)(*args, **kwargs)
+
+ return method
diff --git a/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/INSTALLER b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/METADATA b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/METADATA
new file mode 100644
index 0000000..c60c7d3
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/METADATA
@@ -0,0 +1,164 @@
+Metadata-Version: 2.4
+Name: aiogram
+Version: 3.20.0.post0
+Summary: Modern and fully asynchronous framework for Telegram Bot API
+Project-URL: Homepage, https://aiogram.dev/
+Project-URL: Documentation, https://docs.aiogram.dev/
+Project-URL: Repository, https://github.com/aiogram/aiogram/
+Author-email: Alex Root Junior
+Maintainer-email: Alex Root Junior
+License-Expression: MIT
+License-File: LICENSE
+Keywords: api,asyncio,bot,framework,telegram,wrapper
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Framework :: AsyncIO
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Communications :: Chat
+Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Typing :: Typed
+Requires-Python: >=3.9
+Requires-Dist: aiofiles<24.2,>=23.2.1
+Requires-Dist: aiohttp<3.12,>=3.9.0
+Requires-Dist: certifi>=2023.7.22
+Requires-Dist: magic-filter<1.1,>=1.0.12
+Requires-Dist: pydantic<2.12,>=2.4.1
+Requires-Dist: typing-extensions<=5.0,>=4.7.0
+Provides-Extra: cli
+Requires-Dist: aiogram-cli<2.0.0,>=1.1.0; extra == 'cli'
+Provides-Extra: dev
+Requires-Dist: black~=24.4.2; extra == 'dev'
+Requires-Dist: isort~=5.13.2; extra == 'dev'
+Requires-Dist: motor-types~=1.0.0b4; extra == 'dev'
+Requires-Dist: mypy~=1.10.0; extra == 'dev'
+Requires-Dist: packaging~=24.1; extra == 'dev'
+Requires-Dist: pre-commit~=3.5; extra == 'dev'
+Requires-Dist: ruff~=0.5.1; extra == 'dev'
+Requires-Dist: toml~=0.10.2; extra == 'dev'
+Provides-Extra: docs
+Requires-Dist: furo~=2024.8.6; extra == 'docs'
+Requires-Dist: markdown-include~=0.8.1; extra == 'docs'
+Requires-Dist: pygments~=2.18.0; extra == 'docs'
+Requires-Dist: pymdown-extensions~=10.3; extra == 'docs'
+Requires-Dist: sphinx-autobuild~=2024.9.3; extra == 'docs'
+Requires-Dist: sphinx-copybutton~=0.5.2; extra == 'docs'
+Requires-Dist: sphinx-intl~=2.2.0; extra == 'docs'
+Requires-Dist: sphinx-substitution-extensions~=2024.8.6; extra == 'docs'
+Requires-Dist: sphinxcontrib-towncrier~=0.4.0a0; extra == 'docs'
+Requires-Dist: sphinx~=8.0.2; extra == 'docs'
+Requires-Dist: towncrier~=24.8.0; extra == 'docs'
+Provides-Extra: fast
+Requires-Dist: aiodns>=3.0.0; extra == 'fast'
+Requires-Dist: uvloop>=0.17.0; ((sys_platform == 'darwin' or sys_platform == 'linux') and platform_python_implementation != 'PyPy' and python_version < '3.13') and extra == 'fast'
+Requires-Dist: uvloop>=0.21.0; ((sys_platform == 'darwin' or sys_platform == 'linux') and platform_python_implementation != 'PyPy' and python_version >= '3.13') and extra == 'fast'
+Provides-Extra: i18n
+Requires-Dist: babel~=2.13.0; extra == 'i18n'
+Provides-Extra: mongo
+Requires-Dist: motor<3.7.0,>=3.3.2; extra == 'mongo'
+Provides-Extra: proxy
+Requires-Dist: aiohttp-socks~=0.8.3; extra == 'proxy'
+Provides-Extra: redis
+Requires-Dist: redis[hiredis]<5.3.0,>=5.0.1; extra == 'redis'
+Provides-Extra: test
+Requires-Dist: aresponses~=2.1.6; extra == 'test'
+Requires-Dist: pycryptodomex~=3.19.0; extra == 'test'
+Requires-Dist: pytest-aiohttp~=1.0.5; extra == 'test'
+Requires-Dist: pytest-asyncio~=0.21.1; extra == 'test'
+Requires-Dist: pytest-cov~=4.1.0; extra == 'test'
+Requires-Dist: pytest-html~=4.0.2; extra == 'test'
+Requires-Dist: pytest-lazy-fixture~=0.6.3; extra == 'test'
+Requires-Dist: pytest-mock~=3.12.0; extra == 'test'
+Requires-Dist: pytest-mypy~=0.10.3; extra == 'test'
+Requires-Dist: pytest~=7.4.2; extra == 'test'
+Requires-Dist: pytz~=2023.3; extra == 'test'
+Description-Content-Type: text/x-rst
+
+#######
+aiogram
+#######
+
+.. image:: https://img.shields.io/pypi/l/aiogram.svg?style=flat-square
+ :target: https://opensource.org/licenses/MIT
+ :alt: MIT License
+
+.. image:: https://img.shields.io/pypi/status/aiogram.svg?style=flat-square
+ :target: https://pypi.python.org/pypi/aiogram
+ :alt: PyPi status
+
+.. image:: https://img.shields.io/pypi/v/aiogram.svg?style=flat-square
+ :target: https://pypi.python.org/pypi/aiogram
+ :alt: PyPi Package Version
+
+.. image:: https://img.shields.io/pypi/dm/aiogram.svg?style=flat-square
+ :target: https://pypi.python.org/pypi/aiogram
+ :alt: Downloads
+
+.. image:: https://img.shields.io/pypi/pyversions/aiogram.svg?style=flat-square
+ :target: https://pypi.python.org/pypi/aiogram
+ :alt: Supported python versions
+
+.. image:: https://img.shields.io/badge/dynamic/json?color=blue&logo=telegram&label=Telegram%20Bot%20API&query=%24.api.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Faiogram%2Faiogram%2Fdev-3.x%2F.butcher%2Fschema%2Fschema.json&style=flat-square
+ :target: https://core.telegram.org/bots/api
+ :alt: Telegram Bot API
+
+.. image:: https://img.shields.io/github/actions/workflow/status/aiogram/aiogram/tests.yml?branch=dev-3.x&style=flat-square
+ :target: https://github.com/aiogram/aiogram/actions
+ :alt: Tests
+
+.. image:: https://img.shields.io/codecov/c/github/aiogram/aiogram?style=flat-square
+ :target: https://app.codecov.io/gh/aiogram/aiogram
+ :alt: Codecov
+
+**aiogram** is a modern and fully asynchronous framework for
+`Telegram Bot API `_ written in Python 3.8+ using
+`asyncio `_ and
+`aiohttp `_.
+
+Make your bots faster and more powerful!
+
+Documentation:
+ - 🇺🇸 `English `_
+ - 🇺🇦 `Ukrainian `_
+
+
+Features
+========
+
+- Asynchronous (`asyncio docs `_, :pep:`492`)
+- Has type hints (:pep:`484`) and can be used with `mypy `_
+- Supports `PyPy `_
+- Supports `Telegram Bot API 9.0 `_ and gets fast updates to the latest versions of the Bot API
+- Telegram Bot API integration code was `autogenerated `_ and can be easily re-generated when API gets updated
+- Updates router (Blueprints)
+- Has Finite State Machine
+- Uses powerful `magic filters `_
+- Middlewares (incoming updates and API calls)
+- Provides `Replies into Webhook `_
+- Integrated I18n/L10n support with GNU Gettext (or Fluent)
+
+
+.. warning::
+
+ It is strongly advised that you have prior experience working
+ with `asyncio `_
+ before beginning to use **aiogram**.
+
+ If you have any questions, you can visit our community chats on Telegram:
+
+ - 🇺🇸 `@aiogram `_
+ - 🇺🇦 `@aiogramua `_
+ - 🇺🇿 `@aiogram_uz `_
+ - 🇰🇿 `@aiogram_kz `_
+ - 🇷🇺 `@aiogram_ru `_
+ - 🇮🇷 `@aiogram_fa `_
+ - 🇮🇹 `@aiogram_it `_
+ - 🇧🇷 `@aiogram_br `_
diff --git a/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/RECORD b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/RECORD
new file mode 100644
index 0000000..7c3991d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/RECORD
@@ -0,0 +1,1167 @@
+aiogram-3.20.0.post0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+aiogram-3.20.0.post0.dist-info/METADATA,sha256=bH3Vf7OcheAZS4qACYo1G_CfyBpf3blQMr-e3tY9-Zs,7585
+aiogram-3.20.0.post0.dist-info/RECORD,,
+aiogram-3.20.0.post0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram-3.20.0.post0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
+aiogram-3.20.0.post0.dist-info/licenses/LICENSE,sha256=kTEqDVZ6fYSuFKAER9NvxX60epaWBKI_h-xGsoiU6Iw,1070
+aiogram/__init__.py,sha256=hzEKX_gFXmp5n4GXZEU80SJep1_FAH9owAnFTqd9nK0,948
+aiogram/__meta__.py,sha256=MCeerxm_jiB1kbi20eyVy386PIM-uJ09nNo9Rn7MKoM,53
+aiogram/__pycache__/__init__.cpython-313.pyc,,
+aiogram/__pycache__/__meta__.cpython-313.pyc,,
+aiogram/__pycache__/exceptions.cpython-313.pyc,,
+aiogram/__pycache__/loggers.cpython-313.pyc,,
+aiogram/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/client/__pycache__/__init__.cpython-313.pyc,,
+aiogram/client/__pycache__/bot.cpython-313.pyc,,
+aiogram/client/__pycache__/context_controller.cpython-313.pyc,,
+aiogram/client/__pycache__/default.cpython-313.pyc,,
+aiogram/client/__pycache__/telegram.cpython-313.pyc,,
+aiogram/client/bot.py,sha256=ZS1COp5U-mwOtClrpVJ_-WTnLpCTTFh3na40MRNUg8I,301766
+aiogram/client/context_controller.py,sha256=rAminUBsB3K5FDyj-WQopkD1e94c7GrGVXNyaqPbXZ0,761
+aiogram/client/default.py,sha256=98HtXQNhnv1ywzwQlOeM3IglX7DP993UV0bMIuzQpX4,2601
+aiogram/client/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/client/session/__pycache__/__init__.cpython-313.pyc,,
+aiogram/client/session/__pycache__/aiohttp.cpython-313.pyc,,
+aiogram/client/session/__pycache__/base.cpython-313.pyc,,
+aiogram/client/session/aiohttp.py,sha256=-j2b13CFRtb-KLvVur9hj65ETbcvP3erGvNnhjRjC8g,7132
+aiogram/client/session/base.py,sha256=e3n5NrwL6L-pFhLetTgBg76uLJDxDP6jQqyxPgjtI_0,8335
+aiogram/client/session/middlewares/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/client/session/middlewares/__pycache__/__init__.cpython-313.pyc,,
+aiogram/client/session/middlewares/__pycache__/base.cpython-313.pyc,,
+aiogram/client/session/middlewares/__pycache__/manager.cpython-313.pyc,,
+aiogram/client/session/middlewares/__pycache__/request_logging.cpython-313.pyc,,
+aiogram/client/session/middlewares/base.py,sha256=ck8-iOnaYO2FHb3Yjq6E_TZwiPMg8w8THOXqyHDLjro,1394
+aiogram/client/session/middlewares/manager.py,sha256=c1CS6S_UvxYVAfCq6MZ4Laet6sxReEmQ915XltTJR5o,1903
+aiogram/client/session/middlewares/request_logging.py,sha256=_nUsciMnQeTZ-_nJw3A3NNBlGWzGqKMqYw2oJqJw3s8,1183
+aiogram/client/telegram.py,sha256=mKRJlNjWBMLyY1E28abLrr63s_L6kQCajtfm_-G9UBc,3093
+aiogram/dispatcher/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/dispatcher/__pycache__/__init__.cpython-313.pyc,,
+aiogram/dispatcher/__pycache__/dispatcher.cpython-313.pyc,,
+aiogram/dispatcher/__pycache__/flags.cpython-313.pyc,,
+aiogram/dispatcher/__pycache__/router.cpython-313.pyc,,
+aiogram/dispatcher/dispatcher.py,sha256=xLaAJj_a9VcjsG_gySpDoS0e94c-mr82ms85ELrd268,25365
+aiogram/dispatcher/event/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/dispatcher/event/__pycache__/__init__.cpython-313.pyc,,
+aiogram/dispatcher/event/__pycache__/bases.cpython-313.pyc,,
+aiogram/dispatcher/event/__pycache__/event.cpython-313.pyc,,
+aiogram/dispatcher/event/__pycache__/handler.cpython-313.pyc,,
+aiogram/dispatcher/event/__pycache__/telegram.cpython-313.pyc,,
+aiogram/dispatcher/event/bases.py,sha256=Piod0CEyGvBOwEuE7e70JMQal4XFilFD3NMinR2bEyE,871
+aiogram/dispatcher/event/event.py,sha256=YXOroGX5Mj-5w6Jgl9oPf-muIp6ijeWjNJ3hEr2mA68,1352
+aiogram/dispatcher/event/handler.py,sha256=FBaCVn_ZE095wk6XRcDL-mrulV9BBiXMeHzZrS3DZbQ,3488
+aiogram/dispatcher/event/telegram.py,sha256=hMY9TulAbD6nhNnoPOk1KhRa3SjzSP1xovNS6zT-bkU,4757
+aiogram/dispatcher/flags.py,sha256=vEevCfweZKDCEW2tA5E3UbqMH-TjDBI0ujf7ktzsx9o,3479
+aiogram/dispatcher/middlewares/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/dispatcher/middlewares/__pycache__/__init__.cpython-313.pyc,,
+aiogram/dispatcher/middlewares/__pycache__/base.cpython-313.pyc,,
+aiogram/dispatcher/middlewares/__pycache__/data.cpython-313.pyc,,
+aiogram/dispatcher/middlewares/__pycache__/error.cpython-313.pyc,,
+aiogram/dispatcher/middlewares/__pycache__/manager.cpython-313.pyc,,
+aiogram/dispatcher/middlewares/__pycache__/user_context.cpython-313.pyc,,
+aiogram/dispatcher/middlewares/base.py,sha256=czbD9IDLoHb6pf6HisRGyG8pAQMLbC4R5k-iuTIWSNU,784
+aiogram/dispatcher/middlewares/data.py,sha256=CJDhPh-jtjlADKn6V9aZb8XuFE_scv0sZGzJH7HurJ4,2904
+aiogram/dispatcher/middlewares/error.py,sha256=xDfQxTo9PT1qXvE35OGesDi7WydeQeB4zgT07eXM5G4,1119
+aiogram/dispatcher/middlewares/manager.py,sha256=-ivUdff-Addpd_s_AlDA4RaVsMJmzgWwvt2DIqITnBw,2166
+aiogram/dispatcher/middlewares/user_context.py,sha256=QKD5eDq1MkQRU3mNeTwwdgc6KZo9Ik_P4x-tf9u_vvg,7260
+aiogram/dispatcher/router.py,sha256=mvFBRbleGea-TfZG496N1Fv33kg01HEG0v4pjrQbcUE,10703
+aiogram/enums/__init__.py,sha256=M_0c6T0Cm-BbHa7NfOXOQjs6T2hw50XJlxbnE31zAsg,2493
+aiogram/enums/__pycache__/__init__.cpython-313.pyc,,
+aiogram/enums/__pycache__/bot_command_scope_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/chat_action.cpython-313.pyc,,
+aiogram/enums/__pycache__/chat_boost_source_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/chat_member_status.cpython-313.pyc,,
+aiogram/enums/__pycache__/chat_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/content_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/currency.cpython-313.pyc,,
+aiogram/enums/__pycache__/dice_emoji.cpython-313.pyc,,
+aiogram/enums/__pycache__/encrypted_passport_element.cpython-313.pyc,,
+aiogram/enums/__pycache__/inline_query_result_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/input_media_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/input_paid_media_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/input_profile_photo_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/input_story_content_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/keyboard_button_poll_type_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/mask_position_point.cpython-313.pyc,,
+aiogram/enums/__pycache__/menu_button_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/message_entity_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/message_origin_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/owned_gift_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/paid_media_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/parse_mode.cpython-313.pyc,,
+aiogram/enums/__pycache__/passport_element_error_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/poll_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/reaction_type_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/revenue_withdrawal_state_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/sticker_format.cpython-313.pyc,,
+aiogram/enums/__pycache__/sticker_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/story_area_type_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/topic_icon_color.cpython-313.pyc,,
+aiogram/enums/__pycache__/transaction_partner_type.cpython-313.pyc,,
+aiogram/enums/__pycache__/transaction_partner_user_transaction_type_enum.cpython-313.pyc,,
+aiogram/enums/__pycache__/update_type.cpython-313.pyc,,
+aiogram/enums/bot_command_scope_type.py,sha256=aPn5UKE6AN5BpK9kTH1ffJzG3qUOWFu5lyZOifMu5so,477
+aiogram/enums/chat_action.py,sha256=KKItRU_RQuNzFMrAtc67Pn0aT4rZuuynpH6-yXfBhRY,972
+aiogram/enums/chat_boost_source_type.py,sha256=80MfT0G_9-uv-7MsTs0lZjtJiA7EaUmqYd5b3vH6JtU,277
+aiogram/enums/chat_member_status.py,sha256=OLr5ZfkZocicy1t5i30g7ufR8kujBPHENzR5UHnsDpc,334
+aiogram/enums/chat_type.py,sha256=1Oi1TYITumT8jZritu1fgHNKDvK9otlAhPm4soyBKQQ,280
+aiogram/enums/content_type.py,sha256=59-a7Osoig7DU5zHZDCk3u2fJBhLaHPzeZbgy4rrjMA,2423
+aiogram/enums/currency.py,sha256=P5S_e7Y3wYmODiaK_8Fz0MHVwJXkt1P9Y3gd2SGo1iU,1563
+aiogram/enums/dice_emoji.py,sha256=9KlOPTQlgt-6d3myDEWWUTB9H8BrE_LRaOZvBM2ceWs,303
+aiogram/enums/encrypted_passport_element.py,sha256=m0-tAF9myf6FwPbsuJgj4AYvywzLMzzltUgrqWgGVws,704
+aiogram/enums/inline_query_result_type.py,sha256=HGNN5aOg_jZbE4NNfHs21M-xK5cj2rBar4-C77T73YI,465
+aiogram/enums/input_media_type.py,sha256=BfCDkzFOjrzJSo2syY2lq3E3JP8AdlGemp7qMnAupw0,291
+aiogram/enums/input_paid_media_type.py,sha256=KoqJo7AelAiY8pmS1mRBuQLz97hedWFImEEVFnEoMmY,247
+aiogram/enums/input_profile_photo_type.py,sha256=hkmIjmjAdHBC-_AW6W8KECNLbV9x7XjrqcZDU8WDgoA,247
+aiogram/enums/input_story_content_type.py,sha256=UD2NyVdIoFCD_bCps2BX6h9hrERcv3uZStzxcsBmzro,251
+aiogram/enums/keyboard_button_poll_type_type.py,sha256=vPjequaOO5zySi7hiQjyVIfQl-jhtpgCGHYMR7DOYWY,324
+aiogram/enums/mask_position_point.py,sha256=lhlx8U-9gtGn_LPiSOHWBe1u8YTLZCERs5x8DRmUubM,290
+aiogram/enums/menu_button_type.py,sha256=4FDz7HKaVtfBlvXObCOVAUmyQQvRsyPi0Vu_Kc-HbDs,264
+aiogram/enums/message_entity_type.py,sha256=00ioN4bPLNUYvCL_nJzp7rNUPhIqNOqoWY3PjiC4ob8,703
+aiogram/enums/message_origin_type.py,sha256=qWHgXPzpuhsTcLx-huqNS1l36JSwqbsCY70_d20nreM,279
+aiogram/enums/owned_gift_type.py,sha256=-t3IR93LjFkoi_qalgVtjSOdPppCy0Y9Kp4dn2MbJ1Q,220
+aiogram/enums/paid_media_type.py,sha256=FrGQyXq9bimIb8_b0hpuqYG4mWVruoBYkSC6drd7hw4,261
+aiogram/enums/parse_mode.py,sha256=t5F3LaNLsUOaNQuYlQseWt36suA-oRgr_uScGEU8TKU,234
+aiogram/enums/passport_element_error_type.py,sha256=HCcvvc8DDUNRD-mdFgFqMEFlr_4pa5Us5_U6pO2wXsc,471
+aiogram/enums/poll_type.py,sha256=DluT-wQcOGqBgQimYLlO6OlTIIYnnbtHOmY9pjqVToo,200
+aiogram/enums/reaction_type_type.py,sha256=hNCHqf9dVAWkgRgNBH50KSFsc7h9OKOwTcuGy7yh42M,251
+aiogram/enums/revenue_withdrawal_state_type.py,sha256=ZVw59f9-RYG00TJdSHnZo_LTbdR_J8RmkhDCV4C8AFg,290
+aiogram/enums/sticker_format.py,sha256=UmbwulTvkG7TFwS2twsblqiBj89jeEWY-y7P7Ah2qgo,235
+aiogram/enums/sticker_type.py,sha256=XonGtnasf3tXwoD2DVRx5E16rHCE5VqgAFSfcFMIAGU,278
+aiogram/enums/story_area_type_type.py,sha256=CU1653JBO6mZBqQzUeQqRXhzuWbPdswihxyiwjpIRWg,337
+aiogram/enums/topic_icon_color.py,sha256=q-DilvJsgVmz5VafMOxj1BKJcMoHzpRrbatTPE4inxk,399
+aiogram/enums/transaction_partner_type.py,sha256=wIX729zFM_qynnsf5aqerk4p-kBD5lD3WS8FnqRfnuE,401
+aiogram/enums/transaction_partner_user_transaction_type_enum.py,sha256=WujrQsR-tsBK-tNOJDNtSDp2MxZ22ynJfMoA-L4IoZA,479
+aiogram/enums/update_type.py,sha256=t0xz16mEz1FiX0mihM0pu6A9AQ252ZM8JxvhiBJsfuY,1136
+aiogram/exceptions.py,sha256=Y6wDVG2fyoczPn15U5epm_nnTx8eTC3CgX19SzyiqOE,5153
+aiogram/filters/__init__.py,sha256=w7mWuJOIpLDZyUt1eznzMeF-o1UrstHQ-OYbBHHG6ek,1031
+aiogram/filters/__pycache__/__init__.cpython-313.pyc,,
+aiogram/filters/__pycache__/base.cpython-313.pyc,,
+aiogram/filters/__pycache__/callback_data.cpython-313.pyc,,
+aiogram/filters/__pycache__/chat_member_updated.cpython-313.pyc,,
+aiogram/filters/__pycache__/command.cpython-313.pyc,,
+aiogram/filters/__pycache__/exception.cpython-313.pyc,,
+aiogram/filters/__pycache__/logic.cpython-313.pyc,,
+aiogram/filters/__pycache__/magic_data.cpython-313.pyc,,
+aiogram/filters/__pycache__/state.cpython-313.pyc,,
+aiogram/filters/base.py,sha256=6mCB2nSjqskDDl9mKCZ3SghhwQ1jryaSTd5PvWii3bM,2005
+aiogram/filters/callback_data.py,sha256=oz6gmPYn88gCBXKK43-B73dQ8etWzTaE4VGB8OfPYXM,6356
+aiogram/filters/chat_member_updated.py,sha256=3VsiMYLK6L7AfLS7RQRWwjXThWGN7gj4NAYnR0Wdr8I,7484
+aiogram/filters/command.py,sha256=IXb54dwKHLz-Jaq2_HHn2si7r5iAr9pYW3sSxD8szCk,9957
+aiogram/filters/exception.py,sha256=HbJIOVrXHh0_LkID6b-yn8Xow-llmLqKYmK0_tqB4YA,1488
+aiogram/filters/logic.py,sha256=2M-fYY8m1ybX00wFn_8toRHj5alTfy4T6zkIkYrQZbM,2174
+aiogram/filters/magic_data.py,sha256=Y07K9NLDXpXV0EuFR7GR7Yq4SzCYaD3XJsvDH-6JFkQ,718
+aiogram/filters/state.py,sha256=A4GuSAo5KPdSZMetCC9crrfbJ-yghLunJUVYkOdBPTI,1448
+aiogram/fsm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/fsm/__pycache__/__init__.cpython-313.pyc,,
+aiogram/fsm/__pycache__/context.cpython-313.pyc,,
+aiogram/fsm/__pycache__/middleware.cpython-313.pyc,,
+aiogram/fsm/__pycache__/scene.cpython-313.pyc,,
+aiogram/fsm/__pycache__/state.cpython-313.pyc,,
+aiogram/fsm/__pycache__/strategy.cpython-313.pyc,,
+aiogram/fsm/context.py,sha256=LC6KZoiVQNDmag9jTlCOoBQQ73pobx7E-ovcO_f9tjc,1427
+aiogram/fsm/middleware.py,sha256=4MsKWzr93tzLTmv3dph3pKhznuX9EGsrhBhCb6mhzPo,3755
+aiogram/fsm/scene.py,sha256=VOGFTFkfK4hXWWpxyxroU23x37ILORyFuqtnhbt2SeA,33272
+aiogram/fsm/state.py,sha256=T0sPq1_JV5Jq1jVKu67bUQ0-y9Kqsk3hGpj7PgjpacQ,5640
+aiogram/fsm/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/fsm/storage/__pycache__/__init__.cpython-313.pyc,,
+aiogram/fsm/storage/__pycache__/base.cpython-313.pyc,,
+aiogram/fsm/storage/__pycache__/memory.cpython-313.pyc,,
+aiogram/fsm/storage/__pycache__/mongo.cpython-313.pyc,,
+aiogram/fsm/storage/__pycache__/redis.cpython-313.pyc,,
+aiogram/fsm/storage/base.py,sha256=1duD0gW2ikXhFW_Ag3g4Bzr6O0h_lW0hcs1vjYy6hpI,5939
+aiogram/fsm/storage/memory.py,sha256=E-cSr5I5gLmE8tGmUd9RrghxOXKerlIPkb0izRjg8U0,2612
+aiogram/fsm/storage/mongo.py,sha256=xGvz9rLr6ji8BhumZb1FTvQ5RvmlGquhLAPe1-vi9ms,4880
+aiogram/fsm/storage/redis.py,sha256=7ZyaB-AMNEITjdYVn24Bha28_MIFRPX41mn5_0sEtiY,5322
+aiogram/fsm/strategy.py,sha256=RUDc6kMae9ZFbyC1bdbAIRz6GoeaIHFzXCXRu8p3Kn0,1147
+aiogram/handlers/__init__.py,sha256=XVErtJHhSmg4ytiDTP9J5pQY0RwBN1TsjT5v-Ls7RE4,800
+aiogram/handlers/__pycache__/__init__.cpython-313.pyc,,
+aiogram/handlers/__pycache__/base.cpython-313.pyc,,
+aiogram/handlers/__pycache__/callback_query.cpython-313.pyc,,
+aiogram/handlers/__pycache__/chat_member.cpython-313.pyc,,
+aiogram/handlers/__pycache__/chosen_inline_result.cpython-313.pyc,,
+aiogram/handlers/__pycache__/error.cpython-313.pyc,,
+aiogram/handlers/__pycache__/inline_query.cpython-313.pyc,,
+aiogram/handlers/__pycache__/message.cpython-313.pyc,,
+aiogram/handlers/__pycache__/poll.cpython-313.pyc,,
+aiogram/handlers/__pycache__/pre_checkout_query.cpython-313.pyc,,
+aiogram/handlers/__pycache__/shipping_query.cpython-313.pyc,,
+aiogram/handlers/base.py,sha256=SKLNknDSxAItRHwPMJanOPFztWakJQCun4myH9TBNik,1097
+aiogram/handlers/callback_query.py,sha256=Ufz3dpue809iUWaXP_cBmaZLEvlI1l3JdjkqN3UoHOs,1027
+aiogram/handlers/chat_member.py,sha256=TCr1m47duHFUpL92W56ok0hF1k0NN3Yk88-1zzEsYmw,322
+aiogram/handlers/chosen_inline_result.py,sha256=NjAPc5EgBb8V4p3WVpcPNPd8b1OApymvBN-I75EYMQo,410
+aiogram/handlers/error.py,sha256=86pedHPBgYxXYwrW00s0cadf_lRP6TeHEG0goJ6zNJk,352
+aiogram/handlers/inline_query.py,sha256=sOkT3uMuvamMnSTxct-cdQFng6GBqaOlSNV4aHUbVPQ,381
+aiogram/handlers/message.py,sha256=I6R4TJ8V6bbGVppmxmGSxIkCzeN9JMn1CDojywWrt50,721
+aiogram/handlers/poll.py,sha256=Bn075JIux1lNPjKWH3woV_OzMcvPgPvtkgp4W22mUX8,396
+aiogram/handlers/pre_checkout_query.py,sha256=ZO0iZFVwRz4CtBWIVLds8JoHhMPqCahz6lwOfR4dEkg,321
+aiogram/handlers/shipping_query.py,sha256=ku14YRYvddTbHeKoIwb2oDpfrpsetFC1m2BwIsNwoAs,314
+aiogram/loggers.py,sha256=3MCGSmwgXXsWbgtSaTc6bPSwVOIe8FkQZglc0QLVvsY,257
+aiogram/methods/__init__.py,sha256=Rm-de46tpAblRAeA26hrKkPddoTIA2toV0F8iOxvf2M,11855
+aiogram/methods/__pycache__/__init__.cpython-313.pyc,,
+aiogram/methods/__pycache__/add_sticker_to_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/answer_callback_query.cpython-313.pyc,,
+aiogram/methods/__pycache__/answer_inline_query.cpython-313.pyc,,
+aiogram/methods/__pycache__/answer_pre_checkout_query.cpython-313.pyc,,
+aiogram/methods/__pycache__/answer_shipping_query.cpython-313.pyc,,
+aiogram/methods/__pycache__/answer_web_app_query.cpython-313.pyc,,
+aiogram/methods/__pycache__/approve_chat_join_request.cpython-313.pyc,,
+aiogram/methods/__pycache__/ban_chat_member.cpython-313.pyc,,
+aiogram/methods/__pycache__/ban_chat_sender_chat.cpython-313.pyc,,
+aiogram/methods/__pycache__/base.cpython-313.pyc,,
+aiogram/methods/__pycache__/close.cpython-313.pyc,,
+aiogram/methods/__pycache__/close_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/close_general_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/convert_gift_to_stars.cpython-313.pyc,,
+aiogram/methods/__pycache__/copy_message.cpython-313.pyc,,
+aiogram/methods/__pycache__/copy_messages.cpython-313.pyc,,
+aiogram/methods/__pycache__/create_chat_invite_link.cpython-313.pyc,,
+aiogram/methods/__pycache__/create_chat_subscription_invite_link.cpython-313.pyc,,
+aiogram/methods/__pycache__/create_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/create_invoice_link.cpython-313.pyc,,
+aiogram/methods/__pycache__/create_new_sticker_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/decline_chat_join_request.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_business_messages.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_chat_photo.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_chat_sticker_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_message.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_messages.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_my_commands.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_sticker_from_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_sticker_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_story.cpython-313.pyc,,
+aiogram/methods/__pycache__/delete_webhook.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_chat_invite_link.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_chat_subscription_invite_link.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_general_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_message_caption.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_message_live_location.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_message_media.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_message_reply_markup.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_message_text.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_story.cpython-313.pyc,,
+aiogram/methods/__pycache__/edit_user_star_subscription.cpython-313.pyc,,
+aiogram/methods/__pycache__/export_chat_invite_link.cpython-313.pyc,,
+aiogram/methods/__pycache__/forward_message.cpython-313.pyc,,
+aiogram/methods/__pycache__/forward_messages.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_available_gifts.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_business_account_gifts.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_business_account_star_balance.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_business_connection.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_chat.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_chat_administrators.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_chat_member.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_chat_member_count.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_chat_menu_button.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_custom_emoji_stickers.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_file.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_forum_topic_icon_stickers.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_game_high_scores.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_me.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_my_commands.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_my_default_administrator_rights.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_my_description.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_my_name.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_my_short_description.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_star_transactions.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_sticker_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_updates.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_user_chat_boosts.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_user_profile_photos.cpython-313.pyc,,
+aiogram/methods/__pycache__/get_webhook_info.cpython-313.pyc,,
+aiogram/methods/__pycache__/gift_premium_subscription.cpython-313.pyc,,
+aiogram/methods/__pycache__/hide_general_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/leave_chat.cpython-313.pyc,,
+aiogram/methods/__pycache__/log_out.cpython-313.pyc,,
+aiogram/methods/__pycache__/pin_chat_message.cpython-313.pyc,,
+aiogram/methods/__pycache__/post_story.cpython-313.pyc,,
+aiogram/methods/__pycache__/promote_chat_member.cpython-313.pyc,,
+aiogram/methods/__pycache__/read_business_message.cpython-313.pyc,,
+aiogram/methods/__pycache__/refund_star_payment.cpython-313.pyc,,
+aiogram/methods/__pycache__/remove_business_account_profile_photo.cpython-313.pyc,,
+aiogram/methods/__pycache__/remove_chat_verification.cpython-313.pyc,,
+aiogram/methods/__pycache__/remove_user_verification.cpython-313.pyc,,
+aiogram/methods/__pycache__/reopen_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/reopen_general_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/replace_sticker_in_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/restrict_chat_member.cpython-313.pyc,,
+aiogram/methods/__pycache__/revoke_chat_invite_link.cpython-313.pyc,,
+aiogram/methods/__pycache__/save_prepared_inline_message.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_animation.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_audio.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_chat_action.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_contact.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_dice.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_document.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_game.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_gift.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_invoice.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_location.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_media_group.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_message.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_paid_media.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_photo.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_poll.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_sticker.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_venue.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_video.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_video_note.cpython-313.pyc,,
+aiogram/methods/__pycache__/send_voice.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_business_account_bio.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_business_account_gift_settings.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_business_account_name.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_business_account_profile_photo.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_business_account_username.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_chat_administrator_custom_title.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_chat_description.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_chat_menu_button.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_chat_permissions.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_chat_photo.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_chat_sticker_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_chat_title.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_custom_emoji_sticker_set_thumbnail.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_game_score.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_message_reaction.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_my_commands.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_my_default_administrator_rights.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_my_description.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_my_name.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_my_short_description.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_passport_data_errors.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_sticker_emoji_list.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_sticker_keywords.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_sticker_mask_position.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_sticker_position_in_set.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_sticker_set_thumbnail.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_sticker_set_title.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_user_emoji_status.cpython-313.pyc,,
+aiogram/methods/__pycache__/set_webhook.cpython-313.pyc,,
+aiogram/methods/__pycache__/stop_message_live_location.cpython-313.pyc,,
+aiogram/methods/__pycache__/stop_poll.cpython-313.pyc,,
+aiogram/methods/__pycache__/transfer_business_account_stars.cpython-313.pyc,,
+aiogram/methods/__pycache__/transfer_gift.cpython-313.pyc,,
+aiogram/methods/__pycache__/unban_chat_member.cpython-313.pyc,,
+aiogram/methods/__pycache__/unban_chat_sender_chat.cpython-313.pyc,,
+aiogram/methods/__pycache__/unhide_general_forum_topic.cpython-313.pyc,,
+aiogram/methods/__pycache__/unpin_all_chat_messages.cpython-313.pyc,,
+aiogram/methods/__pycache__/unpin_all_forum_topic_messages.cpython-313.pyc,,
+aiogram/methods/__pycache__/unpin_all_general_forum_topic_messages.cpython-313.pyc,,
+aiogram/methods/__pycache__/unpin_chat_message.cpython-313.pyc,,
+aiogram/methods/__pycache__/upgrade_gift.cpython-313.pyc,,
+aiogram/methods/__pycache__/upload_sticker_file.cpython-313.pyc,,
+aiogram/methods/__pycache__/verify_chat.cpython-313.pyc,,
+aiogram/methods/__pycache__/verify_user.cpython-313.pyc,,
+aiogram/methods/add_sticker_to_set.py,sha256=PR2B-SDNNYLaH70oevadRNAoiUjFQXLffGSIhQ7uah4,1443
+aiogram/methods/answer_callback_query.py,sha256=YVozC3bMDE8YoH6x5TipzWiXCwdWLAU96GWOJTxf1AE,2903
+aiogram/methods/answer_inline_query.py,sha256=ZVC6hK6YsPPkXj2ZQ60RVBLME316WZ-9p4a-KsWKb08,3627
+aiogram/methods/answer_pre_checkout_query.py,sha256=5peOULN2DO0VoK3nEAnsN-E9RWAH5ab64UUc-4apRHk,2172
+aiogram/methods/answer_shipping_query.py,sha256=yUO6Cm1Reo-QBHH-QT-6H0x-07FtOTyj6aO5jgC4dNM,2248
+aiogram/methods/answer_web_app_query.py,sha256=YmmWnI0NcEcxxniAb9pG-3V9dyREC-hw1PDYg_P0Ilc,1504
+aiogram/methods/approve_chat_join_request.py,sha256=Lyh6bvmRqNfwuAOrtNUCMEafOP2E6fxW0x6SKjCx19k,1298
+aiogram/methods/ban_chat_member.py,sha256=vuX8Pw83U1tfU4Epafds_nRFKrJ1UrCzX46oNvVhgVQ,2425
+aiogram/methods/ban_chat_sender_chat.py,sha256=7nNubaecDKyfW__qNszJZLFCtW4PYxtrAQ66AYfNpLU,1586
+aiogram/methods/base.py,sha256=o1E5PvtlUNXv2w8WcMb7sLzjXh9IcwuatlINys1ogLQ,2731
+aiogram/methods/close.py,sha256=Bnzle__tO6tCMMLHkN1E00ypkrdQ0RjhkBNxhjDOq3k,593
+aiogram/methods/close_forum_topic.py,sha256=QGiDveKpOWX210KBERQ8riPfLbxubyM_jQI_IjN1GlM,1492
+aiogram/methods/close_general_forum_topic.py,sha256=7rOcYFfa4IlSEIuJTKWAhXiYSi47QLrWBLyUIK654mM,1240
+aiogram/methods/convert_gift_to_stars.py,sha256=cfVdbXX18ACNuxmpefyc4DA711p5o2xDLh8neB4T9OA,1353
+aiogram/methods/copy_message.py,sha256=8wMh-xgsKfQCARj9xpRPA6LLsmN6JSV18aX1fPtf6c8,6594
+aiogram/methods/copy_messages.py,sha256=qBZBWMSm-pdf_I29ifie44OLBg27zWAnaG0ivzo2IyA,3277
+aiogram/methods/create_chat_invite_link.py,sha256=OmQpGOKjz08AuTws5_LqpJbfB5rSOaaUlzkgj1OC8Y4,2470
+aiogram/methods/create_chat_subscription_invite_link.py,sha256=MgcNPUbSF81_B3Nv-gWQw49DGh4W33ZJ_QQlglsP1-c,2434
+aiogram/methods/create_forum_topic.py,sha256=ky1JOQvCT-lkU48cdApLcmUbS58UthpsiQ9qp1259QQ,2186
+aiogram/methods/create_invoice_link.py,sha256=1GnMXw0Mr3JrmerY76H2uEyGStlt_e-ACpMFmAzgxOs,7573
+aiogram/methods/create_new_sticker_set.py,sha256=GqZvQOMXgN1gf44dma_soOIQx1B1eOonyQX1OFaxFxQ,2922
+aiogram/methods/decline_chat_join_request.py,sha256=LsgHgahFIutfQOiuBtQz9JIUf6T7RUKgQIaUCe96IzQ,1298
+aiogram/methods/delete_business_messages.py,sha256=BhXliqGlfJmeV5HskbW5I-z5GxozjTT7kEGhqwpB50E,1664
+aiogram/methods/delete_chat_photo.py,sha256=VxakOwxoRgQvKUpcuzISRmHi271UEH8oY5FgZQQl_40,1211
+aiogram/methods/delete_chat_sticker_set.py,sha256=3yED97jfR8KlJIuQ-Dhd8eq0Anv6xxOHpUthH5df888,1365
+aiogram/methods/delete_forum_topic.py,sha256=b73dK0IoRXD9_8l5Q7fMdy6z9xfTZDsYoea-ZnxDfFs,1487
+aiogram/methods/delete_message.py,sha256=wVt2pngGBTTvPh_kRJk_012zaNVTa729Ai73vpR5ugY,1924
+aiogram/methods/delete_messages.py,sha256=4670Qx_htRsKh7oTUWdPCL1RJTsAeZGy2hZVCL955g4,1412
+aiogram/methods/delete_my_commands.py,sha256=n7eeclWT3bfF7rdCT4YkoFs1-rJ1zxjSpV0jhbqC9dw,1701
+aiogram/methods/delete_sticker_from_set.py,sha256=J2PsBRRTBks5TDlp4mlmubem7MSWKh8jzJMmLJQV9CI,944
+aiogram/methods/delete_sticker_set.py,sha256=csUT6RkdqmOy0K7vT2QXXR_YJfpQ78S31WYttFqEPY8,908
+aiogram/methods/delete_story.py,sha256=tMYbsLOf4JhDUTc1NGNkIvxTjEMkaRC9vAP3u7uAVh8,1301
+aiogram/methods/delete_webhook.py,sha256=7kfmOOSlujfXV5JZEozbuQQzNrX5YV0f6nMvUo5aw_k,1155
+aiogram/methods/edit_chat_invite_link.py,sha256=VMaqqUxnCYj6PfvRR7m1kJK9vMGm8tzogIus2Wz3-sc,2489
+aiogram/methods/edit_chat_subscription_invite_link.py,sha256=eU7-0X5x7uCbY68LITIJI1cNaZckwwsc5Cge7KyOqsk,1608
+aiogram/methods/edit_forum_topic.py,sha256=D8r9QLbc30zfUAbKKVb-hFejFNRk86jyV-tLOmkZYe4,2212
+aiogram/methods/edit_general_forum_topic.py,sha256=5AUMYXbVvm-D8YJMDt1lFXecUbVafGVDqLhQX6tIU_Y,1323
+aiogram/methods/edit_message_caption.py,sha256=IVdHvnywzWpsN7DjiEUM1giaTqqAsRCWiHTT_YiFtKY,3976
+aiogram/methods/edit_message_live_location.py,sha256=xY7oRgbGjoWM1qbUdTrPkJDafEbolRu9oZAoxixLwVQ,4210
+aiogram/methods/edit_message_media.py,sha256=OYiDaBqhyd8hRytp5Q7XFujDIDYmEGNN_q6bNTlrNu8,3187
+aiogram/methods/edit_message_reply_markup.py,sha256=Nl6x4J52sS1R_TcV_DWaAA5QCBcyLH8qsWukptSrdU8,2663
+aiogram/methods/edit_message_text.py,sha256=8FgR3lNHipberpizDgz6ESZULrq_N3ZRoKjC47fhoeM,4426
+aiogram/methods/edit_story.py,sha256=fEDOChUI4IjhPFp8dXzLK11mCRr1Us6SgXuByMqBttY,2518
+aiogram/methods/edit_user_star_subscription.py,sha256=d1iE8CbFm-gDcG98xFfPbW8oaXDPtuD65FfwofTr20g,1678
+aiogram/methods/export_chat_invite_link.py,sha256=p0AqEuBszR-ylU8knpeoTZ6YOyMgaitrfFYZxzOA2qM,1809
+aiogram/methods/forward_message.py,sha256=DZ4uRDC8q8TJyPfvw3VC-z75NZMYfBOMwZPjmw0AcRY,2875
+aiogram/methods/forward_messages.py,sha256=mOVdIYxL3lXF-IP-LOuek1zZMdgZ68AjKsYKlzq5SuA,2758
+aiogram/methods/get_available_gifts.py,sha256=elM0QwIwvlMz35y6yUhKh3CqzQ6SABpofNFkc1VZZfA,464
+aiogram/methods/get_business_account_gifts.py,sha256=0dbbr0mdrgm-Zdca5JxOGPKZO6rxay3uPeaOZDOo0D8,3047
+aiogram/methods/get_business_account_star_balance.py,sha256=16k3zKFXNnuPjDlFXrjUDiFbY5VyDy8IdYKL4bvv1s0,1210
+aiogram/methods/get_business_connection.py,sha256=wJhKMcBoLcOXTxK1_xG8SR2h85e1sW1C4sWD6L6bTTM,1200
+aiogram/methods/get_chat.py,sha256=e9mWr_xKH-Cj0TnBJP0Fqgn3pIlQPzFZe-Q5RB14-wc,1143
+aiogram/methods/get_chat_administrators.py,sha256=AYHL6etYm273VqYedUJBXUA-uc9OfLZ023JYzNiV0N8,1235
+aiogram/methods/get_chat_member.py,sha256=iIzkGL1oMUaUQ86n2KwWhpiFOTK-jyUEonSOu37_Gmo,1375
+aiogram/methods/get_chat_member_count.py,sha256=sqnuLhiDKL6AA1blDJRmTsuVODII0L6scXrb1xhJViA,1084
+aiogram/methods/get_chat_menu_button.py,sha256=WoKMHDCKLVkJKNK2A5zZY2ILvDY1iJ4qs8QND6MbHHk,1233
+aiogram/methods/get_custom_emoji_stickers.py,sha256=mj0agT_CquoIu48YeAiy0JWb6ZdGXKiWGT5dnu5xwls,1195
+aiogram/methods/get_file.py,sha256=FutkpYaOz_xjdU_1FwGY75ZYZ-uqBCZapZBiE5K9sC0,1571
+aiogram/methods/get_forum_topic_icon_stickers.py,sha256=KbkTvUq447TgRKJ2ak8fkZrNpiDs9f4DFcGy0Yjs7YM,532
+aiogram/methods/get_game_high_scores.py,sha256=seFMcDr_LE0lDUoJ2nPLfzO-5ZjPyF6gyOfxVcDEOhk,2150
+aiogram/methods/get_me.py,sha256=gA4vD-v3WYPpZaSTy6mpGZmsV5WXdSHv06EymV9ZQnU,439
+aiogram/methods/get_my_commands.py,sha256=zJUDIyhc1dtoRCKB3McsveHURrESM0AhF8s6IjJG-2I,1547
+aiogram/methods/get_my_default_administrator_rights.py,sha256=dw1MnQACVfVsQeYs5ikZG1jThB15HR8Trv1xHg_oSLY,1359
+aiogram/methods/get_my_description.py,sha256=UzgJhr6sl4i4RD9LIYxvTx4z4V3cZMGQavCFucWwv1I,1156
+aiogram/methods/get_my_name.py,sha256=GGY2ZnZ_uXL5GqRKHJ2uXs5v_LUBqg6yx0NdrBLZoy8,1057
+aiogram/methods/get_my_short_description.py,sha256=yRQ0ertSdcbEy32FC07FAo12q7eyLEN04h0gkxzpmGE,1203
+aiogram/methods/get_star_transactions.py,sha256=kCp-vAuYCbogKN6PQ4_ulx4ByBatWbMwuXUTsMib22M,1374
+aiogram/methods/get_sticker_set.py,sha256=oh9jEInEgKDfOhAu58ex4rUYRCJCk-BTsOAvNa7GPMg,965
+aiogram/methods/get_updates.py,sha256=LvWmTo059jtv0kVKLUw284FqoelqmVbzJ0weMTJrlcs,3018
+aiogram/methods/get_user_chat_boosts.py,sha256=5flAdfzwcciMrZLoa19Pr6H0lCZpqdFbheYLCIyZ4Rw,1253
+aiogram/methods/get_user_profile_photos.py,sha256=URseFqr69kRj4-gqNkSl4TsiEaAK78iAyjYrTv4tCpA,1507
+aiogram/methods/get_webhook_info.py,sha256=8h38GW1au2fAZau2qmXuOnmu-H6kIjXQEms3VKLJf5c,576
+aiogram/methods/gift_premium_subscription.py,sha256=K3FrRg-pnXab7s3V0n4sFNmJIks3B9yUd7L3rqS011Q,2611
+aiogram/methods/hide_general_forum_topic.py,sha256=j4GCQB65DXFlOP-SjV-AV58K0fPkYV_Kg_8MJBQTiQc,1287
+aiogram/methods/leave_chat.py,sha256=m_5yb9USkUV2vHcOCCVmWMB6nhCqiGwW4lO9-s6PLWM,1080
+aiogram/methods/log_out.py,sha256=yBkCbabI7CRBkTHwhJ61KmqazMxiUuGRMhxlzl7BWB4,660
+aiogram/methods/pin_chat_message.py,sha256=n5B7RNc3U0mHRdWGlwoEO3wNRcfP3GEzycPG6WP9EDA,2160
+aiogram/methods/post_story.py,sha256=YQmBXJGMWIPLFM6O0di7ra5wYkxHrnXAO21HSr__WYU,3103
+aiogram/methods/promote_chat_member.py,sha256=7f4eSGBSEh3Ef58FPhCagolh7Cp6omIQOWWltbq_F4A,5585
+aiogram/methods/read_business_message.py,sha256=k41ISCImaAkxv2rfErBy8JxUcr60-v36K0Y7O_D9MJk,1561
+aiogram/methods/refund_star_payment.py,sha256=s-eELWhpYoE8ubWNvlYc0dmPGCcBiATS0fU50IXXZ5g,1264
+aiogram/methods/remove_business_account_profile_photo.py,sha256=8p8L01Op9-zd43EY5jaArmeDXg34hIJYsa7HKX3w80o,1588
+aiogram/methods/remove_chat_verification.py,sha256=-HD-voBSz4jha5SXD-pKlHFzLmKIWQYR3lJDTRrz0gM,1207
+aiogram/methods/remove_user_verification.py,sha256=wTbWoN-vR3javWvSN_wYyw7WMYbaVWOHR2rTuUwKZ1g,1060
+aiogram/methods/reopen_forum_topic.py,sha256=xJHnJrEkcf8xPJQzjSXbjws0L78OEBHatEqtQe49d8s,1497
+aiogram/methods/reopen_general_forum_topic.py,sha256=VcNplRNf_jvemqZ9Nxc6pX_x_cWbsN_q1UohIl5c0us,1304
+aiogram/methods/replace_sticker_in_set.py,sha256=df80oQuwZsYrbmUixIPxtQ75iUqIMZXsiIyoMZHious,1858
+aiogram/methods/restrict_chat_member.py,sha256=JWfnir4745-fARK7L_0CYvtIyWGwo_yTWwEpJCU_V5M,2676
+aiogram/methods/revoke_chat_invite_link.py,sha256=Amh1KR3yigLEOftMLNtAlI-hhwmnQf0RYOz3etdbv-I,1475
+aiogram/methods/save_prepared_inline_message.py,sha256=Yjwm8XkKs6zrPDdnKWJRLfJc_FA0VxE_ItYJ04m0GtI,2366
+aiogram/methods/send_animation.py,sha256=nKnV5IDSlqLmUaHl5E2lo2LOwRtPQmdpCqpGJjyUcbc,7906
+aiogram/methods/send_audio.py,sha256=OgDMOq4z3e5ST5rpYUo75slmt8UatdmGJaX_MUZ3dMQ,7362
+aiogram/methods/send_chat_action.py,sha256=sTceSyOofS-rTOYsQebl13siZJtVhM8OgOPQa3ceOj0,3204
+aiogram/methods/send_contact.py,sha256=SKKyw9tGockg2GKFPcOMLnXp-OK8zH0X8KxLocY-T_U,5260
+aiogram/methods/send_dice.py,sha256=kFCB4f8IG619lnxPdBUCCYOtFUGEaZ8MQPoubFNVGCY,5030
+aiogram/methods/send_document.py,sha256=gpSdUDVzn98nk-EZMC6mn610uQ76jqAiqq_iQ5g8cDM,7114
+aiogram/methods/send_game.py,sha256=JH6trpdVW0Z_9y3QXDuy16TUzjswgQOLx5YWrXoPa9E,4706
+aiogram/methods/send_gift.py,sha256=6ZvhwGSxIz_0hwFN3wOAg7HBN6BHw9-HaJoz1fLcW0g,2923
+aiogram/methods/send_invoice.py,sha256=4IIzKftogFvzMqB1biz1zi7C7N1BV8_oWI-gk5ttkr8,10625
+aiogram/methods/send_location.py,sha256=1DnShKGhnkCBeV2oNnbVyTMQVTL3eS719BzvZ1ZVGPU,6058
+aiogram/methods/send_media_group.py,sha256=zQrYMW4fjHgsOXK48ir8zEmoP9iEqWD2M0N9-UJvzps,4550
+aiogram/methods/send_message.py,sha256=Yf_7tgRqRcenK5PriTutLiTnHQpBTfbxgga7bghY8E0,6334
+aiogram/methods/send_paid_media.py,sha256=-e__CHH0YxStzmV0zEbH7NlOSGJEpbyY8v136PTQBRQ,5042
+aiogram/methods/send_photo.py,sha256=gs2x8IndHXllmhrwjkrVl1ISzTvPVqEeecBpJy3axgA,6705
+aiogram/methods/send_poll.py,sha256=AHhbVRiIf5AkTWug7l0MwSz2jZhcXQLWkuHa7tmcr4E,8531
+aiogram/methods/send_sticker.py,sha256=r2jk4EiVFJThcsgskK5GI-TLjXhk81ohYmJwZVDxiL8,5503
+aiogram/methods/send_venue.py,sha256=BpPcZjXVg9fETX_J3NHcjEW3WOiHvUeaXXMiMy2oaQY,6027
+aiogram/methods/send_video.py,sha256=mLPodGo-iyyOyQDUjfv55TvrdAMzMQBd7YE4HsrPqeA,8847
+aiogram/methods/send_video_note.py,sha256=cJmqLRXA4S1ph5qoof8ceM3-h64dfGySwzMbTNZlg5M,6272
+aiogram/methods/send_voice.py,sha256=sLd-q9mq68RBHUbzcyg2Ih9ZLG_K-U8RphZcPH4QwH4,6495
+aiogram/methods/set_business_account_bio.py,sha256=VmPvFr2FM1z1z5OOvvdPKoFEPjWDLR1y9lO8u5O5vkI,1306
+aiogram/methods/set_business_account_gift_settings.py,sha256=2YO6cmhjI_C3ink7tuVIG9_5CNr3mkUsIDoIpSazhpw,1729
+aiogram/methods/set_business_account_name.py,sha256=SwjUcHO7ggy71_nfN16kFd9VJqQ7wqn0SM2xCTh_fUY,1560
+aiogram/methods/set_business_account_profile_photo.py,sha256=MVk_2kpx1wsZdVIFfphtuLpllU85Qjq0ExFLr9bCbsY,1707
+aiogram/methods/set_business_account_username.py,sha256=eSovkaPU1Tt74LsA72nnaYuWFq_yoG_DM2LiqZ0r1Wk,1388
+aiogram/methods/set_chat_administrator_custom_title.py,sha256=FjVMHy3nOniZWPwpJWJHk3Apgzoe74rTMHXYGiN01cE,1507
+aiogram/methods/set_chat_description.py,sha256=BtHk97w2zUUZboLYP6bna8wG5_G9blAaQ2T2w1ws-Rw,1424
+aiogram/methods/set_chat_menu_button.py,sha256=zrg1XuwQQfgGQZVWllUP5YF5Wsx7lpSRsq2QYEceTqo,1451
+aiogram/methods/set_chat_permissions.py,sha256=sucYDhJzoO41ew7YmZhDTjAe9VbJZ0VN3BM6CpiFGtQ,2157
+aiogram/methods/set_chat_photo.py,sha256=EjJNVSb9OljIXc0GBEhxa3Rtw4y91H58BUVT_KX9ubE,1343
+aiogram/methods/set_chat_sticker_set.py,sha256=jMrDSHBOm2O8miOCDbcJs6wqEd_qEtVER-qhxL3nrXQ,1588
+aiogram/methods/set_chat_title.py,sha256=rWEHCmaG6ANpZvTeBpWJJ38Bxn2YZMlBGvOTa8DE8F8,1292
+aiogram/methods/set_custom_emoji_sticker_set_thumbnail.py,sha256=E8zURRFNnJnjzxVnYchBta807eCrarjMzpKWp0R5Ypg,1309
+aiogram/methods/set_game_score.py,sha256=RDiYH61W1aN6WZoRLKI_vDQJz8-7V1I8tP__UbZLw1s,2626
+aiogram/methods/set_message_reaction.py,sha256=hJn8ksqPqKKOqU0Cy3sUiMTlXVIg8CnMCzeW_7n7FUQ,2276
+aiogram/methods/set_my_commands.py,sha256=Ye3_mE85NQFcjnV5gExdpd_QtyfmAkON_-Xelu-lOHI,1886
+aiogram/methods/set_my_default_administrator_rights.py,sha256=DKX3KXLXbfv-heE5uJfPbcFXQRvNG6ps3ih1bQNa5RY,1750
+aiogram/methods/set_my_description.py,sha256=ww9IAjtC4X6Ti9cFlnE3dleZ_FKE6byjblGUYn2EqwI,1489
+aiogram/methods/set_my_name.py,sha256=xqSgEYS3Rgr2ETQlvBuD_VopBsuDX_DZY_MnbsOoJgs,1274
+aiogram/methods/set_my_short_description.py,sha256=ONiD6HfZxxnHRjPstEmuBqedjQVjZ-lSJPY14sTRPyc,1639
+aiogram/methods/set_passport_data_errors.py,sha256=mEiM2Oo0JP8slhzo2V7iWgyT3TxUhug3fTl8nwDYXW0,1721
+aiogram/methods/set_sticker_emoji_list.py,sha256=H4PY-fc-SABtoWZ7Vn4XjNYWEO5702xnt8jRpusU89E,1195
+aiogram/methods/set_sticker_keywords.py,sha256=mINPtlVYRMpD6nfDTP78wafUNt5LNhub1js78w6T848,1314
+aiogram/methods/set_sticker_mask_position.py,sha256=eoT5D9VmWuRNsUqyzrHlYWd_bVaK583o3hP_KsoevaI,1450
+aiogram/methods/set_sticker_position_in_set.py,sha256=QJI3x-tobyjpFoEThjcqGQLjXWdCZTd59ei49Gi2Mcg,1100
+aiogram/methods/set_sticker_set_thumbnail.py,sha256=vw-dWC4ZW_TkgtULczhNDgk7WyTttVANQiwKgHuznpA,2877
+aiogram/methods/set_sticker_set_title.py,sha256=kf1H5K3capHR5wlu91DXmP6Q1G_TG_AEJeivppuM-58,1011
+aiogram/methods/set_user_emoji_status.py,sha256=K_Ls8s-sVxB7Jc5-xhiXx3dO1sDwhD-0l49-VQp4uhY,1814
+aiogram/methods/set_webhook.py,sha256=Odg1jc5QTD6poINuz1l-bfmoAPcUkRxDeLwCE5kW2rI,4624
+aiogram/methods/stop_message_live_location.py,sha256=7ZTmi53g_De2yR4U44ef87_DOQbmnDPXCciCC_xClLE,2544
+aiogram/methods/stop_poll.py,sha256=jzqyr9Fzymdv44MQBg--nvvNUjiuim4zBsYe-D536r0,1931
+aiogram/methods/transfer_business_account_stars.py,sha256=254YmYyW45b1S47_3XErWKWzxaCoDwguQKGvcEDcHgI,1360
+aiogram/methods/transfer_gift.py,sha256=0FEVN2-Q2PgAxgO2Av--gezpguO6-Sr0uP9yRI0gQvU,1939
+aiogram/methods/unban_chat_member.py,sha256=PSxlW1D2Cq8yurh-hdtcpvqJbs1HELPyzoB2RvtKAJ0,1936
+aiogram/methods/unban_chat_sender_chat.py,sha256=aQOf8i6uSE4WpA3wKKLCRmlEwKT0PB56LHfPLqnoLFs,1393
+aiogram/methods/unhide_general_forum_topic.py,sha256=7ldwLnrdll5J9f29OpoIhXHB332A8_Xuz6ZX9MgrSJA,1240
+aiogram/methods/unpin_all_chat_messages.py,sha256=JE_JSJjHRGUqtx6g4U6nNmnZ6oPBXTUQm1CV7QObZuc,1320
+aiogram/methods/unpin_all_forum_topic_messages.py,sha256=VpS9YbEYikRHQv9sJU3MDTSG--raSGA4RSM0pC-kBtk,1506
+aiogram/methods/unpin_all_general_forum_topic_messages.py,sha256=Y0mzaMaWP4FvTxZo1gqMZKf5oIMIyAF0UZOZuFNxa_A,1266
+aiogram/methods/unpin_chat_message.py,sha256=xWg5a2W-gSnKr_kHU-zHCT-Q8Q97pmssZs2C0HKpyj0,1995
+aiogram/methods/upgrade_gift.py,sha256=ut1UHylfD8a7uziIy0gPGJc74qsbcVCEhKA2Cjg4iik,2103
+aiogram/methods/upload_sticker_file.py,sha256=TgGArcP8fVpAOM7GRmpbk7GO3sKn2PfBEV--WOo0NKo,1951
+aiogram/methods/verify_chat.py,sha256=H1ykU7ut4mAkPczgseGsTIRhxPfuCDCpPqYhiXrNdx0,1513
+aiogram/methods/verify_user.py,sha256=NGfU1t_O7ybeqItkqi4nnQPNuQfSkBVsVIOcZzfMZOs,1389
+aiogram/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/types/__init__.py,sha256=wQy3PeplT1AOgr0nyhgDWEwqrfswl7F5Me_y6UazU1c,23867
+aiogram/types/__pycache__/__init__.cpython-313.pyc,,
+aiogram/types/__pycache__/accepted_gift_types.cpython-313.pyc,,
+aiogram/types/__pycache__/affiliate_info.cpython-313.pyc,,
+aiogram/types/__pycache__/animation.cpython-313.pyc,,
+aiogram/types/__pycache__/audio.cpython-313.pyc,,
+aiogram/types/__pycache__/background_fill.cpython-313.pyc,,
+aiogram/types/__pycache__/background_fill_freeform_gradient.cpython-313.pyc,,
+aiogram/types/__pycache__/background_fill_gradient.cpython-313.pyc,,
+aiogram/types/__pycache__/background_fill_solid.cpython-313.pyc,,
+aiogram/types/__pycache__/background_fill_union.cpython-313.pyc,,
+aiogram/types/__pycache__/background_type.cpython-313.pyc,,
+aiogram/types/__pycache__/background_type_chat_theme.cpython-313.pyc,,
+aiogram/types/__pycache__/background_type_fill.cpython-313.pyc,,
+aiogram/types/__pycache__/background_type_pattern.cpython-313.pyc,,
+aiogram/types/__pycache__/background_type_union.cpython-313.pyc,,
+aiogram/types/__pycache__/background_type_wallpaper.cpython-313.pyc,,
+aiogram/types/__pycache__/base.cpython-313.pyc,,
+aiogram/types/__pycache__/birthdate.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope_all_chat_administrators.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope_all_group_chats.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope_all_private_chats.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope_chat.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope_chat_administrators.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope_chat_member.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope_default.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_command_scope_union.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_description.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_name.cpython-313.pyc,,
+aiogram/types/__pycache__/bot_short_description.cpython-313.pyc,,
+aiogram/types/__pycache__/business_bot_rights.cpython-313.pyc,,
+aiogram/types/__pycache__/business_connection.cpython-313.pyc,,
+aiogram/types/__pycache__/business_intro.cpython-313.pyc,,
+aiogram/types/__pycache__/business_location.cpython-313.pyc,,
+aiogram/types/__pycache__/business_messages_deleted.cpython-313.pyc,,
+aiogram/types/__pycache__/business_opening_hours.cpython-313.pyc,,
+aiogram/types/__pycache__/business_opening_hours_interval.cpython-313.pyc,,
+aiogram/types/__pycache__/callback_game.cpython-313.pyc,,
+aiogram/types/__pycache__/callback_query.cpython-313.pyc,,
+aiogram/types/__pycache__/chat.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_administrator_rights.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_background.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost_added.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost_removed.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost_source.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost_source_gift_code.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost_source_giveaway.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost_source_premium.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost_source_union.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_boost_updated.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_full_info.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_id_union.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_invite_link.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_join_request.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_location.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member_administrator.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member_banned.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member_left.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member_member.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member_owner.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member_restricted.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member_union.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_member_updated.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_permissions.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_photo.cpython-313.pyc,,
+aiogram/types/__pycache__/chat_shared.cpython-313.pyc,,
+aiogram/types/__pycache__/chosen_inline_result.cpython-313.pyc,,
+aiogram/types/__pycache__/contact.cpython-313.pyc,,
+aiogram/types/__pycache__/copy_text_button.cpython-313.pyc,,
+aiogram/types/__pycache__/custom.cpython-313.pyc,,
+aiogram/types/__pycache__/date_time_union.cpython-313.pyc,,
+aiogram/types/__pycache__/dice.cpython-313.pyc,,
+aiogram/types/__pycache__/document.cpython-313.pyc,,
+aiogram/types/__pycache__/downloadable.cpython-313.pyc,,
+aiogram/types/__pycache__/encrypted_credentials.cpython-313.pyc,,
+aiogram/types/__pycache__/encrypted_passport_element.cpython-313.pyc,,
+aiogram/types/__pycache__/error_event.cpython-313.pyc,,
+aiogram/types/__pycache__/external_reply_info.cpython-313.pyc,,
+aiogram/types/__pycache__/file.cpython-313.pyc,,
+aiogram/types/__pycache__/force_reply.cpython-313.pyc,,
+aiogram/types/__pycache__/forum_topic.cpython-313.pyc,,
+aiogram/types/__pycache__/forum_topic_closed.cpython-313.pyc,,
+aiogram/types/__pycache__/forum_topic_created.cpython-313.pyc,,
+aiogram/types/__pycache__/forum_topic_edited.cpython-313.pyc,,
+aiogram/types/__pycache__/forum_topic_reopened.cpython-313.pyc,,
+aiogram/types/__pycache__/game.cpython-313.pyc,,
+aiogram/types/__pycache__/game_high_score.cpython-313.pyc,,
+aiogram/types/__pycache__/general_forum_topic_hidden.cpython-313.pyc,,
+aiogram/types/__pycache__/general_forum_topic_unhidden.cpython-313.pyc,,
+aiogram/types/__pycache__/gift.cpython-313.pyc,,
+aiogram/types/__pycache__/gift_info.cpython-313.pyc,,
+aiogram/types/__pycache__/gifts.cpython-313.pyc,,
+aiogram/types/__pycache__/giveaway.cpython-313.pyc,,
+aiogram/types/__pycache__/giveaway_completed.cpython-313.pyc,,
+aiogram/types/__pycache__/giveaway_created.cpython-313.pyc,,
+aiogram/types/__pycache__/giveaway_winners.cpython-313.pyc,,
+aiogram/types/__pycache__/inaccessible_message.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_keyboard_button.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_keyboard_markup.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_article.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_audio.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_cached_audio.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_cached_document.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_cached_gif.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_cached_mpeg4_gif.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_cached_photo.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_cached_sticker.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_cached_video.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_cached_voice.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_contact.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_document.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_game.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_gif.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_location.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_mpeg4_gif.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_photo.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_union.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_venue.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_video.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_result_voice.cpython-313.pyc,,
+aiogram/types/__pycache__/inline_query_results_button.cpython-313.pyc,,
+aiogram/types/__pycache__/input_contact_message_content.cpython-313.pyc,,
+aiogram/types/__pycache__/input_file.cpython-313.pyc,,
+aiogram/types/__pycache__/input_file_union.cpython-313.pyc,,
+aiogram/types/__pycache__/input_invoice_message_content.cpython-313.pyc,,
+aiogram/types/__pycache__/input_location_message_content.cpython-313.pyc,,
+aiogram/types/__pycache__/input_media.cpython-313.pyc,,
+aiogram/types/__pycache__/input_media_animation.cpython-313.pyc,,
+aiogram/types/__pycache__/input_media_audio.cpython-313.pyc,,
+aiogram/types/__pycache__/input_media_document.cpython-313.pyc,,
+aiogram/types/__pycache__/input_media_photo.cpython-313.pyc,,
+aiogram/types/__pycache__/input_media_union.cpython-313.pyc,,
+aiogram/types/__pycache__/input_media_video.cpython-313.pyc,,
+aiogram/types/__pycache__/input_message_content.cpython-313.pyc,,
+aiogram/types/__pycache__/input_message_content_union.cpython-313.pyc,,
+aiogram/types/__pycache__/input_paid_media.cpython-313.pyc,,
+aiogram/types/__pycache__/input_paid_media_photo.cpython-313.pyc,,
+aiogram/types/__pycache__/input_paid_media_union.cpython-313.pyc,,
+aiogram/types/__pycache__/input_paid_media_video.cpython-313.pyc,,
+aiogram/types/__pycache__/input_poll_option.cpython-313.pyc,,
+aiogram/types/__pycache__/input_poll_option_union.cpython-313.pyc,,
+aiogram/types/__pycache__/input_profile_photo.cpython-313.pyc,,
+aiogram/types/__pycache__/input_profile_photo_animated.cpython-313.pyc,,
+aiogram/types/__pycache__/input_profile_photo_static.cpython-313.pyc,,
+aiogram/types/__pycache__/input_profile_photo_union.cpython-313.pyc,,
+aiogram/types/__pycache__/input_sticker.cpython-313.pyc,,
+aiogram/types/__pycache__/input_story_content.cpython-313.pyc,,
+aiogram/types/__pycache__/input_story_content_photo.cpython-313.pyc,,
+aiogram/types/__pycache__/input_story_content_union.cpython-313.pyc,,
+aiogram/types/__pycache__/input_story_content_video.cpython-313.pyc,,
+aiogram/types/__pycache__/input_text_message_content.cpython-313.pyc,,
+aiogram/types/__pycache__/input_venue_message_content.cpython-313.pyc,,
+aiogram/types/__pycache__/invoice.cpython-313.pyc,,
+aiogram/types/__pycache__/keyboard_button.cpython-313.pyc,,
+aiogram/types/__pycache__/keyboard_button_poll_type.cpython-313.pyc,,
+aiogram/types/__pycache__/keyboard_button_request_chat.cpython-313.pyc,,
+aiogram/types/__pycache__/keyboard_button_request_user.cpython-313.pyc,,
+aiogram/types/__pycache__/keyboard_button_request_users.cpython-313.pyc,,
+aiogram/types/__pycache__/labeled_price.cpython-313.pyc,,
+aiogram/types/__pycache__/link_preview_options.cpython-313.pyc,,
+aiogram/types/__pycache__/location.cpython-313.pyc,,
+aiogram/types/__pycache__/location_address.cpython-313.pyc,,
+aiogram/types/__pycache__/login_url.cpython-313.pyc,,
+aiogram/types/__pycache__/mask_position.cpython-313.pyc,,
+aiogram/types/__pycache__/maybe_inaccessible_message.cpython-313.pyc,,
+aiogram/types/__pycache__/maybe_inaccessible_message_union.cpython-313.pyc,,
+aiogram/types/__pycache__/media_union.cpython-313.pyc,,
+aiogram/types/__pycache__/menu_button.cpython-313.pyc,,
+aiogram/types/__pycache__/menu_button_commands.cpython-313.pyc,,
+aiogram/types/__pycache__/menu_button_default.cpython-313.pyc,,
+aiogram/types/__pycache__/menu_button_union.cpython-313.pyc,,
+aiogram/types/__pycache__/menu_button_web_app.cpython-313.pyc,,
+aiogram/types/__pycache__/message.cpython-313.pyc,,
+aiogram/types/__pycache__/message_auto_delete_timer_changed.cpython-313.pyc,,
+aiogram/types/__pycache__/message_entity.cpython-313.pyc,,
+aiogram/types/__pycache__/message_id.cpython-313.pyc,,
+aiogram/types/__pycache__/message_origin.cpython-313.pyc,,
+aiogram/types/__pycache__/message_origin_channel.cpython-313.pyc,,
+aiogram/types/__pycache__/message_origin_chat.cpython-313.pyc,,
+aiogram/types/__pycache__/message_origin_hidden_user.cpython-313.pyc,,
+aiogram/types/__pycache__/message_origin_union.cpython-313.pyc,,
+aiogram/types/__pycache__/message_origin_user.cpython-313.pyc,,
+aiogram/types/__pycache__/message_reaction_count_updated.cpython-313.pyc,,
+aiogram/types/__pycache__/message_reaction_updated.cpython-313.pyc,,
+aiogram/types/__pycache__/order_info.cpython-313.pyc,,
+aiogram/types/__pycache__/owned_gift.cpython-313.pyc,,
+aiogram/types/__pycache__/owned_gift_regular.cpython-313.pyc,,
+aiogram/types/__pycache__/owned_gift_union.cpython-313.pyc,,
+aiogram/types/__pycache__/owned_gift_unique.cpython-313.pyc,,
+aiogram/types/__pycache__/owned_gifts.cpython-313.pyc,,
+aiogram/types/__pycache__/paid_media.cpython-313.pyc,,
+aiogram/types/__pycache__/paid_media_info.cpython-313.pyc,,
+aiogram/types/__pycache__/paid_media_photo.cpython-313.pyc,,
+aiogram/types/__pycache__/paid_media_preview.cpython-313.pyc,,
+aiogram/types/__pycache__/paid_media_purchased.cpython-313.pyc,,
+aiogram/types/__pycache__/paid_media_union.cpython-313.pyc,,
+aiogram/types/__pycache__/paid_media_video.cpython-313.pyc,,
+aiogram/types/__pycache__/paid_message_price_changed.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_data.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_data_field.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_file.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_files.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_front_side.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_reverse_side.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_selfie.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_translation_file.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_translation_files.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_union.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_element_error_unspecified.cpython-313.pyc,,
+aiogram/types/__pycache__/passport_file.cpython-313.pyc,,
+aiogram/types/__pycache__/photo_size.cpython-313.pyc,,
+aiogram/types/__pycache__/poll.cpython-313.pyc,,
+aiogram/types/__pycache__/poll_answer.cpython-313.pyc,,
+aiogram/types/__pycache__/poll_option.cpython-313.pyc,,
+aiogram/types/__pycache__/pre_checkout_query.cpython-313.pyc,,
+aiogram/types/__pycache__/prepared_inline_message.cpython-313.pyc,,
+aiogram/types/__pycache__/proximity_alert_triggered.cpython-313.pyc,,
+aiogram/types/__pycache__/reaction_count.cpython-313.pyc,,
+aiogram/types/__pycache__/reaction_type.cpython-313.pyc,,
+aiogram/types/__pycache__/reaction_type_custom_emoji.cpython-313.pyc,,
+aiogram/types/__pycache__/reaction_type_emoji.cpython-313.pyc,,
+aiogram/types/__pycache__/reaction_type_paid.cpython-313.pyc,,
+aiogram/types/__pycache__/reaction_type_union.cpython-313.pyc,,
+aiogram/types/__pycache__/refunded_payment.cpython-313.pyc,,
+aiogram/types/__pycache__/reply_keyboard_markup.cpython-313.pyc,,
+aiogram/types/__pycache__/reply_keyboard_remove.cpython-313.pyc,,
+aiogram/types/__pycache__/reply_markup_union.cpython-313.pyc,,
+aiogram/types/__pycache__/reply_parameters.cpython-313.pyc,,
+aiogram/types/__pycache__/response_parameters.cpython-313.pyc,,
+aiogram/types/__pycache__/result_chat_member_union.cpython-313.pyc,,
+aiogram/types/__pycache__/result_menu_button_union.cpython-313.pyc,,
+aiogram/types/__pycache__/revenue_withdrawal_state.cpython-313.pyc,,
+aiogram/types/__pycache__/revenue_withdrawal_state_failed.cpython-313.pyc,,
+aiogram/types/__pycache__/revenue_withdrawal_state_pending.cpython-313.pyc,,
+aiogram/types/__pycache__/revenue_withdrawal_state_succeeded.cpython-313.pyc,,
+aiogram/types/__pycache__/revenue_withdrawal_state_union.cpython-313.pyc,,
+aiogram/types/__pycache__/sent_web_app_message.cpython-313.pyc,,
+aiogram/types/__pycache__/shared_user.cpython-313.pyc,,
+aiogram/types/__pycache__/shipping_address.cpython-313.pyc,,
+aiogram/types/__pycache__/shipping_option.cpython-313.pyc,,
+aiogram/types/__pycache__/shipping_query.cpython-313.pyc,,
+aiogram/types/__pycache__/star_amount.cpython-313.pyc,,
+aiogram/types/__pycache__/star_transaction.cpython-313.pyc,,
+aiogram/types/__pycache__/star_transactions.cpython-313.pyc,,
+aiogram/types/__pycache__/sticker.cpython-313.pyc,,
+aiogram/types/__pycache__/sticker_set.cpython-313.pyc,,
+aiogram/types/__pycache__/story.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area_position.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area_type.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area_type_link.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area_type_location.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area_type_suggested_reaction.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area_type_union.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area_type_unique_gift.cpython-313.pyc,,
+aiogram/types/__pycache__/story_area_type_weather.cpython-313.pyc,,
+aiogram/types/__pycache__/successful_payment.cpython-313.pyc,,
+aiogram/types/__pycache__/switch_inline_query_chosen_chat.cpython-313.pyc,,
+aiogram/types/__pycache__/text_quote.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner_affiliate_program.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner_chat.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner_fragment.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner_other.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner_telegram_ads.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner_telegram_api.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner_union.cpython-313.pyc,,
+aiogram/types/__pycache__/transaction_partner_user.cpython-313.pyc,,
+aiogram/types/__pycache__/unique_gift.cpython-313.pyc,,
+aiogram/types/__pycache__/unique_gift_backdrop.cpython-313.pyc,,
+aiogram/types/__pycache__/unique_gift_backdrop_colors.cpython-313.pyc,,
+aiogram/types/__pycache__/unique_gift_info.cpython-313.pyc,,
+aiogram/types/__pycache__/unique_gift_model.cpython-313.pyc,,
+aiogram/types/__pycache__/unique_gift_symbol.cpython-313.pyc,,
+aiogram/types/__pycache__/update.cpython-313.pyc,,
+aiogram/types/__pycache__/user.cpython-313.pyc,,
+aiogram/types/__pycache__/user_chat_boosts.cpython-313.pyc,,
+aiogram/types/__pycache__/user_profile_photos.cpython-313.pyc,,
+aiogram/types/__pycache__/user_shared.cpython-313.pyc,,
+aiogram/types/__pycache__/users_shared.cpython-313.pyc,,
+aiogram/types/__pycache__/venue.cpython-313.pyc,,
+aiogram/types/__pycache__/video.cpython-313.pyc,,
+aiogram/types/__pycache__/video_chat_ended.cpython-313.pyc,,
+aiogram/types/__pycache__/video_chat_participants_invited.cpython-313.pyc,,
+aiogram/types/__pycache__/video_chat_scheduled.cpython-313.pyc,,
+aiogram/types/__pycache__/video_chat_started.cpython-313.pyc,,
+aiogram/types/__pycache__/video_note.cpython-313.pyc,,
+aiogram/types/__pycache__/voice.cpython-313.pyc,,
+aiogram/types/__pycache__/web_app_data.cpython-313.pyc,,
+aiogram/types/__pycache__/web_app_info.cpython-313.pyc,,
+aiogram/types/__pycache__/webhook_info.cpython-313.pyc,,
+aiogram/types/__pycache__/write_access_allowed.cpython-313.pyc,,
+aiogram/types/accepted_gift_types.py,sha256=WySy4UOtdY8RKKMZr5dnSXUkQMYe-3bctuNr0LNONOA,1539
+aiogram/types/affiliate_info.py,sha256=3pdlbpp2BMx69FQ9Oe2Fc0ME43H2eTvixrg4B0tSy9Q,2180
+aiogram/types/animation.py,sha256=W9LGC1-JeWGolCU3OI1a3dXjtD5pCnaOd_J7ulWhau8,2673
+aiogram/types/audio.py,sha256=2WPtZmAQfW6ewCb6ozlcfXXZACQEX7c1MYTEVMAy9Lw,2823
+aiogram/types/background_fill.py,sha256=sJj85JGxTXOJVd_dq0jpgH5TbBPlvRKFNjk2CNoM5Bw,513
+aiogram/types/background_fill_freeform_gradient.py,sha256=87YdL1Z7TDBNSJRuVFDNKL_5kHPoDxxdhTexN1Pqc5s,1201
+aiogram/types/background_fill_gradient.py,sha256=bSkNQPDrdWCrSIoCSBE3iFI3NaOAk2cktmLOFUbX2qA,1434
+aiogram/types/background_fill_solid.py,sha256=cL3N_tRhRdpM3rGYjHqh1c05Ys1_w5Sn5RVFX4Kzrhc,1022
+aiogram/types/background_fill_union.py,sha256=Je1MfjdLKjvt_axa7I_QUZqXE8bE77u9XqAJZCbSqv0,368
+aiogram/types/background_type.py,sha256=_UKdw_LQfpR4z7W8wdtEmKV38EUlsSCheh0l4O0d90Y,540
+aiogram/types/background_type_chat_theme.py,sha256=1mylq_KCHfLYikVuv2FVNHTK-FivuOc3fIN16ThxGX0,1077
+aiogram/types/background_type_fill.py,sha256=qcfyK1Uf-f3wiTW0CS6lEw2XGeQM4sjnSmDhsM1l5Ag,1346
+aiogram/types/background_type_pattern.py,sha256=_A3Es3HnXK49Cgv_neET5NQyU7Tymyzv9fDQse2TdOs,2206
+aiogram/types/background_type_union.py,sha256=ihmdXi0rcqj0231A5fS6gR6-wGp-mocMgzpD4PrMWrY,429
+aiogram/types/background_type_wallpaper.py,sha256=6uYeiZ4xQBTmJY0jCTeUFAj65Q872NZL7D2-WMeSLac,1868
+aiogram/types/base.py,sha256=ZAKfSk-DVyoBoYdyyZUTkoIKzuaj0kJS0ophsohsdI4,1762
+aiogram/types/birthdate.py,sha256=ev957uyU2tG4cRqQ838h8LHW0uIPFUu0TdC1YfL0mnY,1056
+aiogram/types/bot_command.py,sha256=rJuwZroECtHDZxhyv92K2vyTUlXdieXdCEhewEsIPk0,1017
+aiogram/types/bot_command_scope.py,sha256=rs7YoyRACVLm4tMMEQ01LM6ckWbF7o81edYEAnWXoyY,951
+aiogram/types/bot_command_scope_all_chat_administrators.py,sha256=3wvcWAh_yZADVbqPQD09kd1hyjmDL_KuoYR8us7A0jI,1311
+aiogram/types/bot_command_scope_all_group_chats.py,sha256=BElN12t3RwjYAFgo__K4PSUA5Mf0Vgzx6lzrhO1_kOY,1225
+aiogram/types/bot_command_scope_all_private_chats.py,sha256=1Ww3HUSSJINy4qNSqF5lybQJwWHpflhMM2So6EMplyg,1226
+aiogram/types/bot_command_scope_chat.py,sha256=HckwEUF_KH3hend_ahHLuR1NiRyy3lxjF5xEoRUCJKU,1374
+aiogram/types/bot_command_scope_chat_administrators.py,sha256=j7U7UEnJlVrfbrNni2Xp_MjcRUvICrHRthCCsYP2Voo,1565
+aiogram/types/bot_command_scope_chat_member.py,sha256=Yog3QOPuV_Zw0OMlJR0ch6_n6yeAJBc4eJhPk38d3Xc,1560
+aiogram/types/bot_command_scope_default.py,sha256=Aqa5eiFS2_2rd8S19i7qfBPIk8TNPVdOEOMR1oSPMuI,1270
+aiogram/types/bot_command_scope_union.py,sha256=KbPJMaXa-9edPHdfibZHO2dgt81XpqGCsZWyPvxR2_o,859
+aiogram/types/bot_description.py,sha256=daKHDJ4d2c9j7wCTKwDLgbXy1HNrjbYkZkwC9D7FiPQ,781
+aiogram/types/bot_name.py,sha256=ut3sf9j5LYd2xki-_pZ1lnVvN7HOUr6v37llIi75j6w,717
+aiogram/types/bot_short_description.py,sha256=UdHLoRvp1hdhEg-W1XYUoDwPeCxvuU2H430JrNDiY4U,849
+aiogram/types/business_bot_rights.py,sha256=4oeNhyBNHeD9kA1bkzGtktcSLIGPZGna5Ht8A45zOSM,4548
+aiogram/types/business_connection.py,sha256=2gtifg44PeSVe3CiHUbr2FgAqOGSUFuOt31Z5p8ZK0o,2500
+aiogram/types/business_intro.py,sha256=TTTNSlPX-bvzbDqKd-YzwXaUjgznpZxnBDGtAKpmSBc,1303
+aiogram/types/business_location.py,sha256=OHFm2V3jLoRWJdXS3ubflMjFGd2Wo6sMhMhvsHbJUUY,1103
+aiogram/types/business_messages_deleted.py,sha256=LYV9OC1fKsPN3t1TOhkLSJK7lyFSSLkgOuhbGU5O448,1472
+aiogram/types/business_opening_hours.py,sha256=D7Cn967ZUdDE-vwJHYLnIeFzxpeKGobQYdlMRl6t-gc,1276
+aiogram/types/business_opening_hours_interval.py,sha256=NFi-_QWLEN_0D1fPpqqp2TlrdWBJ71Rz7c4P-lSWj9Y,1329
+aiogram/types/callback_game.py,sha256=AF-WqkqFcC6nG_tKoNX1sRjRiKEstbEFJfLy4NPKtRQ,298
+aiogram/types/callback_query.py,sha256=CAiS35lJWBMEHmob-dtJ3J1slnUfdPgHrfRojfaTrqI,5987
+aiogram/types/chat.py,sha256=FBu9KuqFn8xgvZtnpqW13BYbV7o969zub6YImiOld2o,64075
+aiogram/types/chat_administrator_rights.py,sha256=xwIgM6y2daN5FSYNJagmhBtgEy88S9GTSQk_OWgrykU,4578
+aiogram/types/chat_background.py,sha256=Tcc01zymJ6aJngiM_x1ME0ch4i5EiVdmJK5TbgwGqWw,910
+aiogram/types/chat_boost.py,sha256=jXtBiv8rFKC1dmRzdomrmXe63jQlWmrlmjaTN6rWxjE,1583
+aiogram/types/chat_boost_added.py,sha256=4WPPng6cqzhb0qpepGeu4mAoga2ieA2vmqIxWQR5n-A,811
+aiogram/types/chat_boost_removed.py,sha256=AzH--6-cVD7iKTUa2pNgVuyWgMlk6ft6g65mAJzddP4,1472
+aiogram/types/chat_boost_source.py,sha256=-s9Um1lFg4ab2MiQpb1SpJlKM2hJHZkpM43TQE6GEMo,476
+aiogram/types/chat_boost_source_gift_code.py,sha256=VkPQktCIZdyI7wvhR-c7hgDs8lI2XySv_tCX1IJoFDc,1378
+aiogram/types/chat_boost_source_giveaway.py,sha256=4iH0fu4MWRf7HVyS1jUKioG5DVWjFhJ4ueqKzqGZEpQ,2407
+aiogram/types/chat_boost_source_premium.py,sha256=nN3o9Kvt5JHXcp1RpYq1WDX8Szzn9so1-FgGR1Olf38,1278
+aiogram/types/chat_boost_source_union.py,sha256=PjJ5pVY5lFQ_9zc967FQqDQjNj6huCrAnAgm0akV9yg,363
+aiogram/types/chat_boost_updated.py,sha256=L0LKL6jutsHYPbCDQoXHaZVjIS5y7uIDXlacKNIFvE0,1002
+aiogram/types/chat_full_info.py,sha256=GJmBdaZktc5FRqhKDaBpEgmNz_esZ-mTnBX4Srhp-zY,14129
+aiogram/types/chat_id_union.py,sha256=1rBUadTFXlUtpp2ISvgZyh7zaIBP5kcSeeBe9Zk5Fy4,92
+aiogram/types/chat_invite_link.py,sha256=FfaheNzGBuDsKaV08kR2vtDRowzhTbvFeU6NtKlaLRc,3219
+aiogram/types/chat_join_request.py,sha256=VzdE_8SmoFOeVMEM6OdrWEmIgr7Z75gMXJxp5jCeAgM,184140
+aiogram/types/chat_location.py,sha256=qZUA9NnQBDCHRLvKDP1Oo0wDX5T5tw-j14-NX8tlXSM,1062
+aiogram/types/chat_member.py,sha256=sq0RhcwghiW4Gy9XJTskFA3dHxaol5EA5Oify1QJfz4,722
+aiogram/types/chat_member_administrator.py,sha256=d7se9Lm1AWDuZRNYGbK3ZLC2NkZVkSzegziJ0Lx66Qc,5453
+aiogram/types/chat_member_banned.py,sha256=bvvMSTPn4iNy6N5nGoPYoxR3pjqDZhFFqvGC_Jb1T3M,1500
+aiogram/types/chat_member_left.py,sha256=YhW1LjLUG5TDTARmj44DaJ0OyX2Gm8CW9-K6EA7LYgI,1254
+aiogram/types/chat_member_member.py,sha256=2AtZsJz3aICbn2eqCmG1p0UsBYSqlNLmN-wnqnC6uks,1482
+aiogram/types/chat_member_owner.py,sha256=2gV3f1ubns_eORZjJocWSuwH8IW_cv2j2I0MuHbVa68,1676
+aiogram/types/chat_member_restricted.py,sha256=7F40ERHf29ihfrB4tTc9JWL5w5xRBjqVLGoMWMgyWlg,4545
+aiogram/types/chat_member_union.py,sha256=5TpJGKB0t0J-Y36aKzWnNMxTOdrpf1qYf82Rfvl6V88,540
+aiogram/types/chat_member_updated.py,sha256=iB_JMfJUGfD53tPBtHdMQ2-lsTfO4u0neOxGNS8q6dc,92945
+aiogram/types/chat_permissions.py,sha256=A6I6DuCQGRWBqhQuVe8xMnRkd9i0iD7gOZm6Qg7m0LY,4382
+aiogram/types/chat_photo.py,sha256=BouKO-6NIn5d17fB9acX9iAbv_gjYzbeKuTqN3BcFD4,1872
+aiogram/types/chat_shared.py,sha256=zGBx81dC3SpqbFwYtGIyKKad1QdeejmvdL-N7waJgfs,2254
+aiogram/types/chosen_inline_result.py,sha256=VFMo9FklvYjWrPbwrxeIyHrDwLlRvnFObUV5EhaannU,2399
+aiogram/types/contact.py,sha256=jWvv9gc-4LyFyBLeAeucyr7A8yjBk7-sJQH10NKoydU,1848
+aiogram/types/copy_text_button.py,sha256=wbr68I7ATgVXhbhSfzEpAsKqNiPjUY-AhKVZcnRl1MM,864
+aiogram/types/custom.py,sha256=3Xqsx2Llx47Hu1v4hGEFOjbMzkgkdQ9lmKW87Atulp4,819
+aiogram/types/date_time_union.py,sha256=IOTdQYsvJZW6IPqbL35v61dMkX9mIT9jIvB0fdgLyPI,144
+aiogram/types/dice.py,sha256=QOFOqUx3jqVtqU_nwuWhhSthy5CBR_mNTMuIpwiD2KY,1165
+aiogram/types/document.py,sha256=6tKzYSPyON6BoWLn3F3tiXHUxaQNG1YNl6kC6bO-0ZE,2425
+aiogram/types/downloadable.py,sha256=z85vtL0yaiqJVfDo0DhrWLgNw7-lpcl9mbEtxRozqVo,108
+aiogram/types/encrypted_credentials.py,sha256=1ZC-Q3c84mEVZGEK_cXTkqzX4FzBujn0_necxJ1uSPc,1521
+aiogram/types/encrypted_passport_element.py,sha256=MHZyzj2tEw7lOCELnp2Yo5qxgIZbT25_KUl-2G8XSjk,4727
+aiogram/types/error_event.py,sha256=m0QrLksRJ0-x0q5xpb6iyI4rqPfiz3XJom_Gh75CJ-8,714
+aiogram/types/external_reply_info.py,sha256=WxDCCqOitwfcfinO-S2mdoOyafHGGuRenyT95NS3P1s,6802
+aiogram/types/file.py,sha256=52bE-c7RjZmTdXk8ij8PJ5fsx2-1IfgedM763PmzGnQ,2166
+aiogram/types/force_reply.py,sha256=YkTteaPMOUH544hl9h6VDypMxyiLIKFd9KXryouTmVM,3024
+aiogram/types/forum_topic.py,sha256=CchPMME1NgB8WT9FWLgQ5mYZ7uXFG2yuTmDMaDZ6kcU,1422
+aiogram/types/forum_topic_closed.py,sha256=aw1K6fIadwJtSTZnyTQq3xtEf7920vodFjK5lHeKVgs,309
+aiogram/types/forum_topic_created.py,sha256=OPYpne_Zz5tdOpzjYOXGplCxLhF1aeKnHFzpn3qXIRg,1321
+aiogram/types/forum_topic_edited.py,sha256=Fq8QDirNBsymOKbAxBYnFqhmXL52XuqKAQrLxePRyA8,1230
+aiogram/types/forum_topic_reopened.py,sha256=MloV3nhDpHSLe5VoVgmC99u7ch3IYahIHH2EokGCWgY,315
+aiogram/types/game.py,sha256=iY-bnyCh7FH92LUpE4mL2sIP8RYnrEHS3YySkqi_odY,2359
+aiogram/types/game_high_score.py,sha256=rwCyO24y4BkcTJSmoLPA7pGEsgfA6-_3i40uvCgxp6k,1203
+aiogram/types/general_forum_topic_hidden.py,sha256=QC3u0Qpt3nptdhl3dxqgNXVrptwSAdnEzI-OWP8QMMw,301
+aiogram/types/general_forum_topic_unhidden.py,sha256=W8HRGyB81eyooaucgD0ojeAzywD8AjnMnUf2hf7r5Nk,307
+aiogram/types/gift.py,sha256=iJ6DZ-P9rSSvJF3F6yKnmDgo6Vf2ToQn084YKAAeKV0,1977
+aiogram/types/gift_info.py,sha256=0SYCA0MUKmuCn82d6o-gzjMAKdiFD1GiKb_9YGGxcD4,2756
+aiogram/types/gifts.py,sha256=xnMajTJ-MoODaiGp0xSF9W9n3vg8oww0aEl1i46umFU,816
+aiogram/types/giveaway.py,sha256=PXB4nsACiEbZCkCaXGhzbipX5VJb3Fh9EJEo7dW4b5A,3341
+aiogram/types/giveaway_completed.py,sha256=-yBzrJeMF8b5Vhs-PlyZQNl4nAuGmZit7qBnqNwwGyg,1811
+aiogram/types/giveaway_created.py,sha256=At22BaRdK_bueF4zp1cSO4QsY6idqSLhpUPkYwhMdWE,1026
+aiogram/types/giveaway_winners.py,sha256=wRhpWdD3pTvyOFBdD8qMD3XpvGX-o_tsGCaeX3gH_NQ,3624
+aiogram/types/inaccessible_message.py,sha256=o46zTJxfKI7sGoW-WGsUp_HNqAoWTfWMESDIMMJmGoY,189464
+aiogram/types/inline_keyboard_button.py,sha256=djbmGtYmMlmd7GwwotfEi5vjYmGeNXq7Vc7UoB2VqBY,5055
+aiogram/types/inline_keyboard_markup.py,sha256=trf-DSyapyYnNoXeO0qu8h1OcR8TokB2q697jMhN3dA,1267
+aiogram/types/inline_query.py,sha256=oSWWRhIdy1-CMprPlgrxZl4_SY5r-cpIBjRZqJ67Z_8,5121
+aiogram/types/inline_query_result.py,sha256=8Ve8Fe1Yf6O7NHWCYdTVIgnbawI6hIo5B0l2cV5ZN20,2189
+aiogram/types/inline_query_result_article.py,sha256=STgxREUtVkrU7nAIR010Xhhnr-f3WrLbP23-P53iJ4o,3247
+aiogram/types/inline_query_result_audio.py,sha256=L4HeDvYvG7u0Fus1d7k3Ej9aYCgmP-WeRAAbAP2tdF0,3601
+aiogram/types/inline_query_result_cached_audio.py,sha256=5HgBOj0xZM-Z82nXh7lW0J22kEMl0TGNeFQi4DW7o9A,3252
+aiogram/types/inline_query_result_cached_document.py,sha256=SYBwLYuEhJAUpTOnsmPXblVZWwJCt3GUjMDDXvpi1w0,3594
+aiogram/types/inline_query_result_cached_gif.py,sha256=7Wb7jfrJTOYdDNl28bs9CFRHogCujjMQ8HbOUrN27Qo,3835
+aiogram/types/inline_query_result_cached_mpeg4_gif.py,sha256=YmQVEqUsmcKQt8lrzhZ4aAR5FC7s3m824hx4xT4xv-Y,3933
+aiogram/types/inline_query_result_cached_photo.py,sha256=Ft-z08C-mFM2Y4TLFUMwna2NvedxxgFh51G5lORwpIQ,4003
+aiogram/types/inline_query_result_cached_sticker.py,sha256=bQh4REzYmsT6bK3QoiTRToYu4Hi_1NVjogmv_MKPW2A,2333
+aiogram/types/inline_query_result_cached_video.py,sha256=OQwNqsaKF1s-DLGLvFxKcpnguPSMaU1EAxCk9iALEWA,3973
+aiogram/types/inline_query_result_cached_voice.py,sha256=hnv63mFkVoSd4sPcnz6Zif4T9bxw0ndt211VCawPkdM,3378
+aiogram/types/inline_query_result_contact.py,sha256=VsmQIXcsIHr27UtAl74MTkU-op_dl3KO2hrExReSldQ,3344
+aiogram/types/inline_query_result_document.py,sha256=TI3WDRB4Hrb9yEjP_2_rZ2fPqEsuSlJ9gLfvrDjhfyU,4281
+aiogram/types/inline_query_result_game.py,sha256=9t2HzFgVgHjPW_pQZ4YBTeGptSbn9KOHcGsbEPpUwzQ,1758
+aiogram/types/inline_query_result_gif.py,sha256=-wjAtIzx4UrYBXa1wVHE7gvB_BxnVo22ker_SRyWA5I,4745
+aiogram/types/inline_query_result_location.py,sha256=-s2_5R45f1ULz2oDYcGPvf6wWwp90Xy-oAsVVL7QkSo,4194
+aiogram/types/inline_query_result_mpeg4_gif.py,sha256=JD0vmpfePfLeoUwTz9ArWhBWRiazlrYN5x-kadYXi20,4848
+aiogram/types/inline_query_result_photo.py,sha256=uKfzvfj0ezQGydsVUXbnxeKBLDuV1wGR68f-644do0A,4479
+aiogram/types/inline_query_result_union.py,sha256=rVF16N_1EnX2eZ7OD6hY_N6KZm-b0X5K6NQQxBG0N-E,2099
+aiogram/types/inline_query_result_venue.py,sha256=aw0zEyQ7wKek7LnhCI0rkAEfMQIg46PWTHi0rRehduY,4137
+aiogram/types/inline_query_result_video.py,sha256=g7TQhmEu39e-DzR3w81eq8R489Vws0ZfldRoT9lT4RQ,5076
+aiogram/types/inline_query_result_voice.py,sha256=Invm6PfnUObZPiyqCQ2xHerVRJd8ma9cbEogqNeoV7k,3544
+aiogram/types/inline_query_results_button.py,sha256=mcDUu9wvU35tBvH1BhICorSlJ25XUVbpJlh9BWE3HNQ,1878
+aiogram/types/input_contact_message_content.py,sha256=GR2RDpizrX7rlxjf05CKzRT3zmLEO1yJSpqbmxCLwQA,1599
+aiogram/types/input_file.py,sha256=oCElYrCtJgfP5_ck0MQxvGppVZyXW5BnsHcmSg1Ds1o,4672
+aiogram/types/input_file_union.py,sha256=VMtFJd_7TYA56rK93PQHr5fC0BvxP52WpfytLElaXDI,136
+aiogram/types/input_invoice_message_content.py,sha256=EJf4oo8a0alA1zACIfPb68VJxE3F0AvoCkuNjfiu1h0,6896
+aiogram/types/input_location_message_content.py,sha256=UmmTHtSm-0MbIp2pISbl6FoPo9rjKeBK0pKzKg66GvE,2374
+aiogram/types/input_media.py,sha256=2nTD1Wg9VX8x74KTAf2d6OjjGTwPTUXaQL5Ty5TxvYQ,619
+aiogram/types/input_media_animation.py,sha256=UbwZBiM7h00fsB7BQZL9-aPxb6I4PY-XF2VKKIcEaSg,4402
+aiogram/types/input_media_audio.py,sha256=x_iDzgIT4arhpJMYW3mZ6bV-GQ1mmmbexsTcmR8dUlc,3735
+aiogram/types/input_media_document.py,sha256=TcVh8fAqlX5QMXzG3KkPnssNjRq6AAp4I0mcAdzA-Go,3657
+aiogram/types/input_media_photo.py,sha256=A9cIU1Dff8CCCHvxW6ka4RbAi6Eo_lwCDSxGQX5HuJI,3118
+aiogram/types/input_media_union.py,sha256=3BHh-TZhx1BR9Vn_vfnTfK_0ZT-Gojhik4_JY8jZCOU,434
+aiogram/types/input_media_video.py,sha256=wPG3bA-TiXqsRe7JPb_lxVaSHBXFxHs_OcKJXVOEhfE,5315
+aiogram/types/input_message_content.py,sha256=wj0C4RyiLpVP4yz0LmmO4qMNNIwRMihjnoMrjBSxjDE,793
+aiogram/types/input_message_content_union.py,sha256=S-DrnYh1YY2dcnRRw4dOeomxYk6zzMJkE2g6aeYbxb0,597
+aiogram/types/input_paid_media.py,sha256=z-STAz_0G590-eFlOYNTv_HP1LOWbACXM0XMYbEBXrg,380
+aiogram/types/input_paid_media_photo.py,sha256=I-L-nxLOHhrPwQpEpX32WtgR-vRl4rGhZabrCKhE3Fs,1488
+aiogram/types/input_paid_media_union.py,sha256=mRq78DNn_h-LQ_jzaP_yLPEtw2nCcjGH-mNDJ_h3U7w,245
+aiogram/types/input_paid_media_video.py,sha256=yHzFw2s35ksX3nVx8CiemOT5YkkhEhOu4BuUX2fd2nE,3750
+aiogram/types/input_poll_option.py,sha256=xvXNI_QLkU1UMHaFgHBAF7VKAY7JbZTjMYb0RYkfYVs,1785
+aiogram/types/input_poll_option_union.py,sha256=_UDhdeDLqlFxQ-a3zYTaOKXGftNp0-y4zYklcjtVwrM,161
+aiogram/types/input_profile_photo.py,sha256=zq_EiYKXEgO-rtR5qbz3gX4Zor38NEmiahFy_qlkLeo,439
+aiogram/types/input_profile_photo_animated.py,sha256=9q098IkXJkkYOuI2o1DKgSWENMTIcqEvnVsSeO3-iJI,1891
+aiogram/types/input_profile_photo_static.py,sha256=8YsqWr4b-YNB3Igt52Vd_2mdcV_kPq3Kw5mdUo5rdyw,1496
+aiogram/types/input_profile_photo_union.py,sha256=SkUR3-fLJskFplyqlQ1K2JWgAxBX_UL5qpyAiH9yDKU,242
+aiogram/types/input_sticker.py,sha256=aMD6UQgs9KJxbWF8K931DL3nD_LwDw6dfimf3PUH2wU,2380
+aiogram/types/input_story_content.py,sha256=Y9wcp5cdZi4D6G4tYw76DONJ1y1-HxPRhbTWrBNR7go,439
+aiogram/types/input_story_content_photo.py,sha256=1XCgo5O_gilxK7cOy-CNNLD6iZ6pmW3MrFGIF6flrF8,1477
+aiogram/types/input_story_content_union.py,sha256=vUOYDQdYeARjoCXYLJKMrGnyS0K6qZCPxnlN_KK5mwg,230
+aiogram/types/input_story_content_video.py,sha256=QsjlXQm9kQ__VJI15tOcsLKBq3MgIR-pH2JEsP6IzHQ,2324
+aiogram/types/input_text_message_content.py,sha256=i5edPai_FFJ-U7Rqh-PMdEwXI_ez-uFqOl7tzRTch0Y,2676
+aiogram/types/input_venue_message_content.py,sha256=CZsCPYQrFdP_BrYBzNJ_Ik39PlJ1VLOsvI5q9vRS0Ns,2411
+aiogram/types/invoice.py,sha256=gOiw5G9yXJ8ZkAVupt2ww-mcooYanTix6t7KarSni9Y,1932
+aiogram/types/keyboard_button.py,sha256=L0cHsJEsKQziqK3zJN6laQL9drC36AhbhMOG20vhzcE,4352
+aiogram/types/keyboard_button_poll_type.py,sha256=tPGlW_jRXaDxZML1_vK080sp6BO86DO5cbBP-TEOf4Q,1153
+aiogram/types/keyboard_button_request_chat.py,sha256=N8UBPPlrQ07OSCO-33mfP5lKJ744sugaS86dYWpxMRQ,4448
+aiogram/types/keyboard_button_request_user.py,sha256=89efkQPnTYrtpBozhTvXp00YE8uKqgJInVUafJV7nkI,1990
+aiogram/types/keyboard_button_request_users.py,sha256=bhj4_scIdCcKxWeuC8f8guU_tcWTvwrbISe_PycG-XE,2747
+aiogram/types/labeled_price.py,sha256=7kRZPTy8HgJG4FYrix21xGfhgT_u93fROUBOj1wB4Rk,1330
+aiogram/types/link_preview_options.py,sha256=xv8Z-qE_NBfojELQHSlgegmsXso661AL8562z8i0dls,2747
+aiogram/types/location.py,sha256=0X9SBlANNn_ODEByFE0oDiJxpKtGEQ6OI6fDXB_1loA,2115
+aiogram/types/location_address.py,sha256=tQZrO6GUTChLXTSa-XoMzxmjV_wxU77PwAUJc2N7v2U,1447
+aiogram/types/login_url.py,sha256=VxZTVG1LbmKeon_spDg17HJiPh1l1buOI5eFBNLu1Rk,2771
+aiogram/types/mask_position.py,sha256=ZH0pNJ8u4Xlos2MwCtsnSzMNfhgGvacCGdJ42qFp9no,1627
+aiogram/types/maybe_inaccessible_message.py,sha256=TbxUHEoW88w4nWer6zhQhWaAjTqr2Xi3H9-ZJRfvA9Q,388
+aiogram/types/maybe_inaccessible_message_union.py,sha256=qtQdgfk2iZskzJwjea8mzHK6YbZMYpYdcQvpCAlNqS8,214
+aiogram/types/media_union.py,sha256=boBBSq5TEjrKD3oKvQigLEwWop56o2wlq3IDJmzl-h8,311
+aiogram/types/menu_button.py,sha256=4Q2I_AlbnRe2fQ0f1a-LNl0toGOHI73ehjhMQmLngV4,2103
+aiogram/types/menu_button_commands.py,sha256=NMmH1S0jcEivjXmzRfMTLJAO4UBKVhFuo8wS4ONgZwc,1038
+aiogram/types/menu_button_default.py,sha256=FnjUz1-aXR3-0oHPv0pNU5yi1M86wnzwCbNnzEMu094,1027
+aiogram/types/menu_button_union.py,sha256=MSheNGWTBcvg6UZ7kk37SY0pFfNDkijhpGWdhylzTKo,298
+aiogram/types/menu_button_web_app.py,sha256=G-yWLPg91mgaMP672VRj6xmB8_UqDpMeH2iePvY0rw0,1715
+aiogram/types/message.py,sha256=V3eE1A5d0Ev9bq7A3O5E-TV3mN0Bevg0IEyqRJ0LJjY,255661
+aiogram/types/message_auto_delete_timer_changed.py,sha256=D9GoK5tOtxWTksB_yaIKthfiHWJhOI6SUBWWpW_PRTY,1020
+aiogram/types/message_entity.py,sha256=HFSk-rWsATvYBtVxGQFihPhiVNB1n3UusXiOIQNsbfg,3349
+aiogram/types/message_id.py,sha256=JGHbRBB4KbmtK0L4VTcWLrlttF3M4eukcUXkmDQF6T0,1072
+aiogram/types/message_origin.py,sha256=uSs6n9q5JhIzaV42ldMJJL_8nAx_aCQ3xNqrRVMJsWg,518
+aiogram/types/message_origin_channel.py,sha256=tgCfiuS81A0oWD9EY90F0P3B9s-Avsm0FJlw5ra8umA,1795
+aiogram/types/message_origin_chat.py,sha256=_EE8lVR8Kp745dHTlT1zHYXEDImbGhq_nuZgteu9lbc,1725
+aiogram/types/message_origin_hidden_user.py,sha256=N8WXMNcBlWSuDMRYUxsUiZubnOxsDFOr7GyYQKRrij4,1377
+aiogram/types/message_origin_union.py,sha256=R6W5cFILBh8M4zDaFGMRHyD2DCGLZRKZVy-_EN5x5wg,404
+aiogram/types/message_origin_user.py,sha256=FTu0wnkg8AElOQtMjy2Ee-ApL2eX57a5qMrudWMWf90,1349
+aiogram/types/message_reaction_count_updated.py,sha256=INsBfsf6UMzCeQraikugzPI9QPRBWH4SeycDKddJhEU,1515
+aiogram/types/message_reaction_updated.py,sha256=WXTgqameHW9TMgBwiZzrG-PT26DhUDEFx6gD1IaIViY,2222
+aiogram/types/order_info.py,sha256=ECWERhAIl3kkclMOwnNN9NHGQLUtW0B6oElkLubPPr4,1516
+aiogram/types/owned_gift.py,sha256=CJ0gEVurMwulgq3FbA--eaJEdRSlNsupxuZTwoGcg6s,410
+aiogram/types/owned_gift_regular.py,sha256=UScXvImQW_mfNkwsWRzJsU9Oie3YJfUbH03y17eRXhw,3866
+aiogram/types/owned_gift_union.py,sha256=HZ9Sz5j1uWs50fKp9WLRyuLsJAFYgV-WTAA6YcvwG0w,181
+aiogram/types/owned_gift_unique.py,sha256=LJzFlmZdCxwvVHKqqurTrF8GxF9IVBBqCfqR-bIa2gw,2697
+aiogram/types/owned_gifts.py,sha256=sRL7E3a4dDVZ_31tow-V2mLThjTuzn_xDX1PNSZJab8,1339
+aiogram/types/paid_media.py,sha256=gw3vvGNuZugsvlWpqxuZs1Q81ALL9MTZ6RVP5EFMbmk,399
+aiogram/types/paid_media_info.py,sha256=xI42d8_jhbAwwdCH0HZug4KpkDwLa-eGgzWTr06C3A0,1130
+aiogram/types/paid_media_photo.py,sha256=03xX-iveseL0dkiaHd0TY9q7MLM9qLO20_c8Yu810QY,1124
+aiogram/types/paid_media_preview.py,sha256=9ZIG6wR-De8VPU2y5Rn77czZFOdLcW_JxKXQeYsiycw,1522
+aiogram/types/paid_media_purchased.py,sha256=J_V6slEyAerISMyRxiiIFKjygHAlusJKCCJY7-LI9Mo,1171
+aiogram/types/paid_media_union.py,sha256=2PnTu4ZArY_Twco0mJHQkpkFNLMQzVSGJh3hHHRj0qU,275
+aiogram/types/paid_media_video.py,sha256=afHhTgBEXuyms9V1FaGqJutjveZeHjESmYvav3D3_ck,1095
+aiogram/types/paid_message_price_changed.py,sha256=OdvjES-XmNGOJSp376KLaagwo7x6r_uWB88I9x1rY5M,1040
+aiogram/types/passport_data.py,sha256=ByKi34EtxO4ipowiWzyzeZYdrIODBAZnzF8DRJ1hLlw,1312
+aiogram/types/passport_element_error.py,sha256=0MooyVK2Yoz-6MTnBDqbyiR9o-cYM5GoM6HC-p6X9jQ,1214
+aiogram/types/passport_element_error_data_field.py,sha256=NQXIJOOjXP56vbMTgKl2z9QqTs7FyHlxURO2xSOMQI0,1850
+aiogram/types/passport_element_error_file.py,sha256=tlUpJBAJFPUzHnCgd07gIS1c_HvFXFTpQWlB6Kipo_w,1619
+aiogram/types/passport_element_error_files.py,sha256=6tX9sDOVBez80HlGwWY2ypo3oKYVyrlDaqYMAqLWBio,1728
+aiogram/types/passport_element_error_front_side.py,sha256=669dn7UWwY4GnNnmaUBipHj8U22PahkJFmzLVerAGXk,1721
+aiogram/types/passport_element_error_reverse_side.py,sha256=ZVfTzKDmrZqzwcOBNuzsSwfEUip8hHCzeRk2jyiWDak,1704
+aiogram/types/passport_element_error_selfie.py,sha256=KR-TG1DguG1w9Kv1rIJRf7qkI_L7euSwr9h5IC8DAJU,1623
+aiogram/types/passport_element_error_translation_file.py,sha256=Zm4DzT7yQoHHdANCgq0uW6kmskULr56hwjv0GFPWTGI,1843
+aiogram/types/passport_element_error_translation_files.py,sha256=QZqQRIKd0qfVzmiKN9JHDVn32PFdNq6sIkKiZn6GScs,1946
+aiogram/types/passport_element_error_union.py,sha256=Sbvt4V-bqu0D9Ka-yZQ4Zu5uczz6t2i6XtFo1R6taB8,1128
+aiogram/types/passport_element_error_unspecified.py,sha256=KqvSPstDlkcEJRDA-JkFX5JK97uO9R4Nqx_Sbp5iW4Q,1651
+aiogram/types/passport_file.py,sha256=tN7IbA6M4Zk6WH4CpVeI0exfi_UKoKOUiz1iT1e1epo,1599
+aiogram/types/photo_size.py,sha256=J1rOX1QxScCjA0LPm4KgdLZBpsAQfscAaDfuocE4cC0,1664
+aiogram/types/poll.py,sha256=WHHT_JkYIBH7D70qk1IsCeR2914X8Uk8Ib78BZZvV74,3731
+aiogram/types/poll_answer.py,sha256=ujKTddKv7gCre2Uw4IQ0HT6bvuk2NTZuX1SMgYK4Efc,1608
+aiogram/types/poll_option.py,sha256=XfbZtlUS_Eo7yKn1Cy9auho6TY4M9kpqITwrMZYCObo,1439
+aiogram/types/pre_checkout_query.py,sha256=CaYsF1zvPb1k5cgka1GC12VMS3eZc3RWVba7VmRr6L4,4410
+aiogram/types/prepared_inline_message.py,sha256=-nsLE4Yn_nFONy12-zzcWhfkTeHsW8pVWRnfOi1PRew,1175
+aiogram/types/proximity_alert_triggered.py,sha256=b2zF9r0sjf-cp6Gj-pyTIJq9x5a_JBjdp-DseDGpM_0,1253
+aiogram/types/reaction_count.py,sha256=5RVIcaCs1i8xKrYtKJi_TQS-hotzPmhDBUA0mCIdezo,1104
+aiogram/types/reaction_type.py,sha256=EBHvWnPblOe2T6ey0_V9m6vReAX8VcHX4wuzKLVMR0w,442
+aiogram/types/reaction_type_custom_emoji.py,sha256=dzZSLhEtBke35GtTgfSxrijMu9jQzob6drdFkYReR7w,1150
+aiogram/types/reaction_type_emoji.py,sha256=F5WoRrUm9tOV3YJVNh8quD4D2OfsU53Y-mbqggbnm-w,1682
+aiogram/types/reaction_type_paid.py,sha256=dazJsDfQEMF9mgQZ0So4t7S-QFKHGyr6HKyYyBsnPtU,951
+aiogram/types/reaction_type_union.py,sha256=6f2AnIxKesdHRROu86up20RXsVolRoATgx4DT0O2haY,315
+aiogram/types/refunded_payment.py,sha256=yaj69LD-j7ffwtTk69ozl0MXz3r2kUlBTgOuWEqvxto,2180
+aiogram/types/reply_keyboard_markup.py,sha256=fLfhKqj11SKDkuKrzDdHgGnpEIZhHsYKI7e5pCV9Frg,3367
+aiogram/types/reply_keyboard_remove.py,sha256=vt2LTPCyoNO1SzO7JLJAUTLxfcyVh5eVKTkFmjQVvag,2093
+aiogram/types/reply_markup_union.py,sha256=OGXQphj_n9kWmMZRSdnmGmSOg25M7uK_tuUI3GZgmFY,373
+aiogram/types/reply_parameters.py,sha256=LMJQiTjiL9AQiZYSTvvUfzpLz2DrJDdySc1k42ojG7o,3531
+aiogram/types/response_parameters.py,sha256=qPu3C079bJZRdUIQwr-r9WIcW6yYW7rdWJlraZQbw-M,1550
+aiogram/types/result_chat_member_union.py,sha256=amU0t7aQ9RBrv9qQXgqJ_5MSTZ6Q_SYspiV1_02BtK4,510
+aiogram/types/result_menu_button_union.py,sha256=b-C23IbT03p6M1VLi0iUNSYobxQKHvCbAxqTEk4zYv0,268
+aiogram/types/revenue_withdrawal_state.py,sha256=rUzcoQ2Nbmm-2EwkoD-g_xWUp9o3mIsthyE2ZWrg0ZY,585
+aiogram/types/revenue_withdrawal_state_failed.py,sha256=uhCBqAV8SpbCkL364ygkvGg7TzarISQ6NniBeHvn3HE,1133
+aiogram/types/revenue_withdrawal_state_pending.py,sha256=rVieabsj2ayXpzN7yW8uGN-8p6Qy_lQyrKYFSKH5qmw,1115
+aiogram/types/revenue_withdrawal_state_succeeded.py,sha256=d2cBJbxXEPhtSLWb-TzyDy-iumMWkG7G6LWNRBmH7oI,1409
+aiogram/types/revenue_withdrawal_state_union.py,sha256=Y0hzi9UpIKO1vS2WHmviUAaT29Qx6feTQyqCloFWXN0,429
+aiogram/types/sent_web_app_message.py,sha256=1p2Xr_3czwPbZd8PpylTSo31ZgeAEBLnlnlRcBY31xc,1168
+aiogram/types/shared_user.py,sha256=UPL2qcpYgtKEPL8v5_CTF6NPOZrvR0FCzegIYjJG3vk,2334
+aiogram/types/shipping_address.py,sha256=9JTEnZoNaPa-T1p_YolL1ErIGWJol8lAU4F8ycsQ8ZY,1550
+aiogram/types/shipping_option.py,sha256=S5Jd4zr-7xbI5uaCLO696jlURKCdgZHgZD9hOrCj-gQ,1092
+aiogram/types/shipping_query.py,sha256=Tjrwg66Vgv8WgmGBwGdNK-HQKrvxPQN3S7VxARbq92E,3452
+aiogram/types/star_amount.py,sha256=ntbQD-r-mW2eIb4oNbIDmmZgTf7P2jHVFJjyoddd9VU,1172
+aiogram/types/star_transaction.py,sha256=eV1HblfYAI-70tZZZ1Bm4hkGAE19nPD5M0-MixWEvX4,2626
+aiogram/types/star_transactions.py,sha256=QbV2EsfoupTvwfYyD_WFlaiqLBenA6ik6-dwoqbUGjk,948
+aiogram/types/sticker.py,sha256=Tcz8iqKzCbfvP7MdV3NVwUEt9u27EmB7_R-N_BxSd6M,5902
+aiogram/types/sticker_set.py,sha256=Z6heidYoOQUkfS2PijUSCEg3L_NjgD3hkhChCE6jwpw,2382
+aiogram/types/story.py,sha256=2Bm9ZHpfr4_yeBPWFgwnqTs-y4xFgKqW8NLRVWzMdqM,884
+aiogram/types/story_area.py,sha256=ZMgBU7CS5R25QNy48kogPz5J1xSS0ixP90O0Aodu_HA,1109
+aiogram/types/story_area_position.py,sha256=oV2Yfk9A_DWNYBTiBjPc2tRVeGMLsZaCzUUylFitlNI,1990
+aiogram/types/story_area_type.py,sha256=MQk--NXA8cnBTQP7tr7BGxT-5A8P8rMF_6A5nBA7uhw,669
+aiogram/types/story_area_type_link.py,sha256=n8oP7lSGDVBI-5pXHt1SHHFWXwByWE5DlC6Kq_KmSmY,1195
+aiogram/types/story_area_type_location.py,sha256=Dri_zlRtpRk7OckuKYitfX7_HZLMEWH-WKKyAqYPmZ4,1664
+aiogram/types/story_area_type_suggested_reaction.py,sha256=txBn2tEKCZS9_NpYNVRqQYxhfG38gjfk7twlVKAm3CU,1908
+aiogram/types/story_area_type_union.py,sha256=615SV-XZ55khkjPeh5t5j9oOnGyPORcQ1ljSUDZt4aQ,512
+aiogram/types/story_area_type_unique_gift.py,sha256=k71mfgp5W2a-yV3MU13TZRSCOxZESsIbOPPceo2AlKQ,1214
+aiogram/types/story_area_type_weather.py,sha256=TaKrmF0dssQiIlvMGVLG43QZxpH0ONhbbTtuAwevnog,1571
+aiogram/types/successful_payment.py,sha256=27MZNMpq4v5f3H71oYLcilA1Ea3Jq8oLFOEGb_nTKIo,3517
+aiogram/types/switch_inline_query_chosen_chat.py,sha256=KH9p_x5aY6XxQn71LRa92cVQMl8glZKdc2m2935i_Yo,2002
+aiogram/types/text_quote.py,sha256=u6Carp9C3dKz3-u35EIhnulAxpfGh0_BXsfAG5M4bHs,1857
+aiogram/types/transaction_partner.py,sha256=rgiZNODfYP1dzzNceHZPQ4P_o_f1GVRpVbJAWkZyYd4,899
+aiogram/types/transaction_partner_affiliate_program.py,sha256=3EvIelQf7fuzSrQZV8BjK5X5CQYXxehBwr7rTnNS2Xk,1869
+aiogram/types/transaction_partner_chat.py,sha256=eszVC9nS9SsxYgFDw-s0vCeOdkZvoTWCcM7zJ5YLV9w,1386
+aiogram/types/transaction_partner_fragment.py,sha256=KSIh1yLjwNdiWINympxMYIX-vWom5fAjnBb9SZI8Ek0,1475
+aiogram/types/transaction_partner_other.py,sha256=iHViDYZ62dQS3z6k1YkMOqFELyBM4wpAkGzRlif-_xw,1104
+aiogram/types/transaction_partner_telegram_ads.py,sha256=QmVjyRZUGNTpxRIFZF4F_pAPj9i4224E1PsnA9GS8YU,1185
+aiogram/types/transaction_partner_telegram_api.py,sha256=ntdhxePoaNtTFNKkwVN34VeX60VYkH0PxJnRI4_0z1E,1419
+aiogram/types/transaction_partner_union.py,sha256=KuvpF1zBlZcznZHo2oZizEZo56f0CBMby9ivjtBb1t0,817
+aiogram/types/transaction_partner_user.py,sha256=OeRmQ_ONWFP6Z37jsxTGi0VQrJGztpgUlkx5enRpVOY,3792
+aiogram/types/unique_gift.py,sha256=08y6ExpWpp7jBvqCkryrVjtIZ-kTez1R5BIU51uidkI,1895
+aiogram/types/unique_gift_backdrop.py,sha256=MrNGGteE176XFjjlck5Tl82435WfRXagpKTmwv4PXaE,1294
+aiogram/types/unique_gift_backdrop_colors.py,sha256=11k1VGVeMEpMMlH0v5zT_L7BLiWqbxyrLhfrTCAaL10,1452
+aiogram/types/unique_gift_info.py,sha256=6TpQEmz9GqsvifLOCnPPouHPJE1vxoD0_hxrA6ffFjw,1708
+aiogram/types/unique_gift_model.py,sha256=3uTZtjzIhKePWc4J8_YBNe3haAAeXaRXP-kuKKLxWqQ,1233
+aiogram/types/unique_gift_symbol.py,sha256=tbNlZIK36OiEUhb99XkwFnHA1DHnlhXXV04nTX6YKCk,1258
+aiogram/types/update.py,sha256=vRi2nszPAGjfYLgjVfxvROOrakObWp_hFtf3BS-AAvQ,11923
+aiogram/types/user.py,sha256=DW0Xg1Lld2oB5wwOZtBIJggt-WiNLKOY-4HHSpU_t1k,6001
+aiogram/types/user_chat_boosts.py,sha256=SLpS9r5MUTva6qyarE6wkGV8e1KTvUqM9ldfXAwHw-o,940
+aiogram/types/user_profile_photos.py,sha256=ET0y9iSQw7975QnIjsLzjZ-nWpvhDwMrZRJuxsSdfY8,1118
+aiogram/types/user_shared.py,sha256=1yGKAO67fshHSOCtVl3dO_oD1-VOyzPBC4Ak-hflMOQ,1534
+aiogram/types/users_shared.py,sha256=W8gUM4q8YZvLEFnvkQsLHV91iMRvC7TcXywXmMVe1Wc,1980
+aiogram/types/venue.py,sha256=wEmGfGAiqdhDhTskRoxOKiNVliUaPpPOxBmohfDlL5I,2147
+aiogram/types/video.py,sha256=rqUoQNnhQ400UWzgLemmVmKekYEToUX-eUupaYiRc5Y,3055
+aiogram/types/video_chat_ended.py,sha256=eL3ZSR0WfVcHEEpXrdLm1mvuogXS7RAoxLwX2AwMdeg,839
+aiogram/types/video_chat_participants_invited.py,sha256=FQAGFFuJkrkg7GwoYx0IxHebIV4ap1czpALPE7282N8,937
+aiogram/types/video_chat_scheduled.py,sha256=G-a24czeK7NVzJ88SKFNutPd_SGnRgTBLy85rHozNLo,990
+aiogram/types/video_chat_started.py,sha256=FYHVcH-a5knoXIYMmCQThFt8hjjPwAiZ8QvGLNVWgl4,309
+aiogram/types/video_note.py,sha256=Hwa8uTCnyb9yT9eGikFwyVfk6X779md3DNAPbav6VrM,2059
+aiogram/types/voice.py,sha256=AMyEJovxyDl2TRVpEfpHLMSmsXNjXIrNDH73HxQUxqg,1932
+aiogram/types/web_app_data.py,sha256=CzkuU2VwVYQ7WBkFA6Zh8BL-qUKQeB__mcmhmVZnT2A,1107
+aiogram/types/web_app_info.py,sha256=aPH4uLFFLKNLEF3RUm3uYCkg9Hk545kMoUvrkg4TUds,931
+aiogram/types/webhook_info.py,sha256=huNLXO-9PAFI8ti5a4TcYfbWCirITn6N-i2Lphc1Yak,2986
+aiogram/types/write_access_allowed.py,sha256=3GiPknn_fKHAJ53FROE4AK4MtpwluNlAuZvFuOP6diA,1912
+aiogram/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/utils/__pycache__/__init__.cpython-313.pyc,,
+aiogram/utils/__pycache__/auth_widget.cpython-313.pyc,,
+aiogram/utils/__pycache__/backoff.cpython-313.pyc,,
+aiogram/utils/__pycache__/callback_answer.cpython-313.pyc,,
+aiogram/utils/__pycache__/chat_action.cpython-313.pyc,,
+aiogram/utils/__pycache__/chat_member.cpython-313.pyc,,
+aiogram/utils/__pycache__/class_attrs_resolver.cpython-313.pyc,,
+aiogram/utils/__pycache__/dataclass.cpython-313.pyc,,
+aiogram/utils/__pycache__/deep_linking.cpython-313.pyc,,
+aiogram/utils/__pycache__/formatting.cpython-313.pyc,,
+aiogram/utils/__pycache__/keyboard.cpython-313.pyc,,
+aiogram/utils/__pycache__/link.cpython-313.pyc,,
+aiogram/utils/__pycache__/magic_filter.cpython-313.pyc,,
+aiogram/utils/__pycache__/markdown.cpython-313.pyc,,
+aiogram/utils/__pycache__/media_group.cpython-313.pyc,,
+aiogram/utils/__pycache__/mixins.cpython-313.pyc,,
+aiogram/utils/__pycache__/mypy_hacks.cpython-313.pyc,,
+aiogram/utils/__pycache__/payload.cpython-313.pyc,,
+aiogram/utils/__pycache__/serialization.cpython-313.pyc,,
+aiogram/utils/__pycache__/text_decorations.cpython-313.pyc,,
+aiogram/utils/__pycache__/token.cpython-313.pyc,,
+aiogram/utils/__pycache__/warnings.cpython-313.pyc,,
+aiogram/utils/__pycache__/web_app.cpython-313.pyc,,
+aiogram/utils/auth_widget.py,sha256=kcNMXu7hA4kWHw_PeZsGFaeC0m0Sbtbd2-8Q9rWfkHg,981
+aiogram/utils/backoff.py,sha256=D_d7z94PyR5USzeoIednnCgW07qQgwQNgVdPGkgrmJM,2123
+aiogram/utils/callback_answer.py,sha256=_NHsLMjfZBKOXtyCSHBh4s9V3go-U8Wsk5JqpMh-O4c,6573
+aiogram/utils/chat_action.py,sha256=3GW2mDqQQ5fv6LMpeqB0j-J1d1blml2aF4q7vqlnMBQ,12201
+aiogram/utils/chat_member.py,sha256=WwMEi__6DYeF55TFuLxPS-OQaDdTa0I2f-yJkt3Dio0,942
+aiogram/utils/class_attrs_resolver.py,sha256=MDJArsv--q9FThSyyI-WPXyQvMB25RD4k1as95fFXuU,3332
+aiogram/utils/dataclass.py,sha256=xJgw_pmxSr0mINDKdZdxKfxRJMguhQt3fPIB8ZFszHE,2035
+aiogram/utils/deep_linking.py,sha256=lIfsEQpVmx4WxUI22lNEDX-Hnz3CwiOZscPNAt5-3kE,4312
+aiogram/utils/formatting.py,sha256=1pdklthv7YwvmUdmu0c773eF_I3hr0xaOG83tD9gff4,19818
+aiogram/utils/i18n/__init__.py,sha256=mwTwSL1cuXYi3a3LBICqoH66y4kHVML24YNPbGlZ55M,440
+aiogram/utils/i18n/__pycache__/__init__.cpython-313.pyc,,
+aiogram/utils/i18n/__pycache__/context.cpython-313.pyc,,
+aiogram/utils/i18n/__pycache__/core.cpython-313.pyc,,
+aiogram/utils/i18n/__pycache__/lazy_proxy.cpython-313.pyc,,
+aiogram/utils/i18n/__pycache__/middleware.cpython-313.pyc,,
+aiogram/utils/i18n/context.py,sha256=fhLzDZvxqRMvPu2-lEUrH7n09oHl-H0qo2mLFyKzCJk,549
+aiogram/utils/i18n/core.py,sha256=XX_iuwylDTfrfCrafnqiFq28LDr-bvoO4Qnkhy81d_M,3542
+aiogram/utils/i18n/lazy_proxy.py,sha256=0yHtyrejG9wG4yzLl1cDEsFomww2nyR7KFSbFyp7_NA,472
+aiogram/utils/i18n/middleware.py,sha256=lqeui9-x7ztMQPI0IeQeRawe6orMjpsg2EtvXTzAQj4,5874
+aiogram/utils/keyboard.py,sha256=hJFQRbcSofx75QlM6WWyyFm-XBR-XC1CGQ9cZ7CzVtA,13441
+aiogram/utils/link.py,sha256=z7Zp5uk5z3iNO26-wZrhoCDNLt1N0KjbPYhthOq-50o,2261
+aiogram/utils/magic_filter.py,sha256=WGHOC9k2acxrcpkFF-ViQv3LbzRAKtJj5MRv7IEi75c,666
+aiogram/utils/markdown.py,sha256=3T1UVSzaAwnYnTNNq6pklq-TTs6Y6zINp-LIWgwrAyU,4481
+aiogram/utils/media_group.py,sha256=E28oJhPoTQ4iKXr0QUx5W1nd7VPHAJf0PQz0MeqG46E,14804
+aiogram/utils/mixins.py,sha256=ox0Q6BlxcyTfAtzLVMEY9eUfXXhnXtkkLBQlUQ6uL4o,2923
+aiogram/utils/mypy_hacks.py,sha256=cm5_tBzfrkG5OOIs2m5U4JfQKohj1KkmCRXNLTJFDy0,433
+aiogram/utils/payload.py,sha256=mGJdQryRHL07VbSjdzGbN1NbYzd_mN2MGY1RiY3_KX4,2942
+aiogram/utils/serialization.py,sha256=SMiqv2TQed_GOhvhWoaABFM65jjIiXqBJTRRdMQ9nXY,2765
+aiogram/utils/text_decorations.py,sha256=eEUykrlq22MQuKrzayVBWpBPaXEZqI6j5PbJH2HyFNE,8256
+aiogram/utils/token.py,sha256=iFfmK-pHGyPsF4ekWWcOlfH4OR9xGNAyCIavND8Ykrc,936
+aiogram/utils/warnings.py,sha256=xGsQcxrMXtdZfLOGRCqKRIJbw80DA39COcctikBfYAE,89
+aiogram/utils/web_app.py,sha256=pYFAohjk8OW3qRQkJebMtKaFJ7vOL4OJivUEh171kkI,7105
+aiogram/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+aiogram/webhook/__pycache__/__init__.cpython-313.pyc,,
+aiogram/webhook/__pycache__/aiohttp_server.cpython-313.pyc,,
+aiogram/webhook/__pycache__/security.cpython-313.pyc,,
+aiogram/webhook/aiohttp_server.py,sha256=rh_dNpqwtPzG3WAuhtbvsDgkocP2JurvFjsDrJ1H0Ko,10637
+aiogram/webhook/security.py,sha256=ifd2TrPSOlXfutYyAmRh0LT3hJkB4o79XmEV1lo6fv0,1350
diff --git a/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/REQUESTED b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/WHEEL b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/WHEEL
new file mode 100644
index 0000000..12228d4
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/WHEEL
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: hatchling 1.27.0
+Root-Is-Purelib: true
+Tag: py3-none-any
diff --git a/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/licenses/LICENSE b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/licenses/LICENSE
new file mode 100644
index 0000000..caa060c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram-3.20.0.post0.dist-info/licenses/LICENSE
@@ -0,0 +1,18 @@
+Copyright (c) 2017 - present Alex Root Junior
+
+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.
diff --git a/myenv/Lib/site-packages/aiogram/__init__.py b/myenv/Lib/site-packages/aiogram/__init__.py
new file mode 100644
index 0000000..1fbee0e
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/__init__.py
@@ -0,0 +1,41 @@
+import asyncio as _asyncio
+from contextlib import suppress
+
+from aiogram.dispatcher.flags import FlagGenerator
+
+from . import enums, methods, types
+from .__meta__ import __api_version__, __version__
+from .client import session
+from .client.bot import Bot
+from .dispatcher.dispatcher import Dispatcher
+from .dispatcher.middlewares.base import BaseMiddleware
+from .dispatcher.router import Router
+from .utils.magic_filter import MagicFilter
+from .utils.text_decorations import html_decoration as html
+from .utils.text_decorations import markdown_decoration as md
+
+with suppress(ImportError):
+ import uvloop as _uvloop
+
+ _asyncio.set_event_loop_policy(_uvloop.EventLoopPolicy())
+
+
+F = MagicFilter()
+flags = FlagGenerator()
+
+__all__ = (
+ "__api_version__",
+ "__version__",
+ "types",
+ "methods",
+ "enums",
+ "Bot",
+ "session",
+ "Dispatcher",
+ "Router",
+ "BaseMiddleware",
+ "F",
+ "html",
+ "md",
+ "flags",
+)
diff --git a/myenv/Lib/site-packages/aiogram/__meta__.py b/myenv/Lib/site-packages/aiogram/__meta__.py
new file mode 100644
index 0000000..569721c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/__meta__.py
@@ -0,0 +1,2 @@
+__version__ = "3.20.0.post0"
+__api_version__ = "9.0"
diff --git a/myenv/Lib/site-packages/aiogram/client/__init__.py b/myenv/Lib/site-packages/aiogram/client/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram/client/bot.py b/myenv/Lib/site-packages/aiogram/client/bot.py
new file mode 100644
index 0000000..255ac86
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/bot.py
@@ -0,0 +1,5418 @@
+from __future__ import annotations
+
+import io
+import pathlib
+from contextlib import asynccontextmanager
+from types import TracebackType
+from typing import (
+ Any,
+ AsyncGenerator,
+ AsyncIterator,
+ BinaryIO,
+ Optional,
+ Type,
+ TypeVar,
+ Union,
+ cast,
+)
+
+import aiofiles
+
+from aiogram.utils.token import extract_bot_id, validate_token
+
+from ..methods import (
+ AddStickerToSet,
+ AnswerCallbackQuery,
+ AnswerInlineQuery,
+ AnswerPreCheckoutQuery,
+ AnswerShippingQuery,
+ AnswerWebAppQuery,
+ ApproveChatJoinRequest,
+ BanChatMember,
+ BanChatSenderChat,
+ Close,
+ CloseForumTopic,
+ CloseGeneralForumTopic,
+ ConvertGiftToStars,
+ CopyMessage,
+ CopyMessages,
+ CreateChatInviteLink,
+ CreateChatSubscriptionInviteLink,
+ CreateForumTopic,
+ CreateInvoiceLink,
+ CreateNewStickerSet,
+ DeclineChatJoinRequest,
+ DeleteBusinessMessages,
+ DeleteChatPhoto,
+ DeleteChatStickerSet,
+ DeleteForumTopic,
+ DeleteMessage,
+ DeleteMessages,
+ DeleteMyCommands,
+ DeleteStickerFromSet,
+ DeleteStickerSet,
+ DeleteStory,
+ DeleteWebhook,
+ EditChatInviteLink,
+ EditChatSubscriptionInviteLink,
+ EditForumTopic,
+ EditGeneralForumTopic,
+ EditMessageCaption,
+ EditMessageLiveLocation,
+ EditMessageMedia,
+ EditMessageReplyMarkup,
+ EditMessageText,
+ EditStory,
+ EditUserStarSubscription,
+ ExportChatInviteLink,
+ ForwardMessage,
+ ForwardMessages,
+ GetAvailableGifts,
+ GetBusinessAccountGifts,
+ GetBusinessAccountStarBalance,
+ GetBusinessConnection,
+ GetChat,
+ GetChatAdministrators,
+ GetChatMember,
+ GetChatMemberCount,
+ GetChatMenuButton,
+ GetCustomEmojiStickers,
+ GetFile,
+ GetForumTopicIconStickers,
+ GetGameHighScores,
+ GetMe,
+ GetMyCommands,
+ GetMyDefaultAdministratorRights,
+ GetMyDescription,
+ GetMyName,
+ GetMyShortDescription,
+ GetStarTransactions,
+ GetStickerSet,
+ GetUpdates,
+ GetUserChatBoosts,
+ GetUserProfilePhotos,
+ GetWebhookInfo,
+ GiftPremiumSubscription,
+ HideGeneralForumTopic,
+ LeaveChat,
+ LogOut,
+ PinChatMessage,
+ PostStory,
+ PromoteChatMember,
+ ReadBusinessMessage,
+ RefundStarPayment,
+ RemoveBusinessAccountProfilePhoto,
+ RemoveChatVerification,
+ RemoveUserVerification,
+ ReopenForumTopic,
+ ReopenGeneralForumTopic,
+ ReplaceStickerInSet,
+ RestrictChatMember,
+ RevokeChatInviteLink,
+ SavePreparedInlineMessage,
+ SendAnimation,
+ SendAudio,
+ SendChatAction,
+ SendContact,
+ SendDice,
+ SendDocument,
+ SendGame,
+ SendGift,
+ SendInvoice,
+ SendLocation,
+ SendMediaGroup,
+ SendMessage,
+ SendPaidMedia,
+ SendPhoto,
+ SendPoll,
+ SendSticker,
+ SendVenue,
+ SendVideo,
+ SendVideoNote,
+ SendVoice,
+ SetBusinessAccountBio,
+ SetBusinessAccountGiftSettings,
+ SetBusinessAccountName,
+ SetBusinessAccountProfilePhoto,
+ SetBusinessAccountUsername,
+ SetChatAdministratorCustomTitle,
+ SetChatDescription,
+ SetChatMenuButton,
+ SetChatPermissions,
+ SetChatPhoto,
+ SetChatStickerSet,
+ SetChatTitle,
+ SetCustomEmojiStickerSetThumbnail,
+ SetGameScore,
+ SetMessageReaction,
+ SetMyCommands,
+ SetMyDefaultAdministratorRights,
+ SetMyDescription,
+ SetMyName,
+ SetMyShortDescription,
+ SetPassportDataErrors,
+ SetStickerEmojiList,
+ SetStickerKeywords,
+ SetStickerMaskPosition,
+ SetStickerPositionInSet,
+ SetStickerSetThumbnail,
+ SetStickerSetTitle,
+ SetUserEmojiStatus,
+ SetWebhook,
+ StopMessageLiveLocation,
+ StopPoll,
+ TelegramMethod,
+ TransferBusinessAccountStars,
+ TransferGift,
+ UnbanChatMember,
+ UnbanChatSenderChat,
+ UnhideGeneralForumTopic,
+ UnpinAllChatMessages,
+ UnpinAllForumTopicMessages,
+ UnpinAllGeneralForumTopicMessages,
+ UnpinChatMessage,
+ UpgradeGift,
+ UploadStickerFile,
+ VerifyChat,
+ VerifyUser,
+)
+from ..types import (
+ AcceptedGiftTypes,
+ BotCommand,
+ BotCommandScopeUnion,
+ BotDescription,
+ BotName,
+ BotShortDescription,
+ BusinessConnection,
+ ChatAdministratorRights,
+ ChatFullInfo,
+ ChatIdUnion,
+ ChatInviteLink,
+ ChatPermissions,
+ DateTimeUnion,
+ Downloadable,
+ File,
+ ForumTopic,
+ GameHighScore,
+ Gifts,
+ InlineKeyboardMarkup,
+ InlineQueryResultsButton,
+ InlineQueryResultUnion,
+ InputFile,
+ InputFileUnion,
+ InputMediaUnion,
+ InputPaidMediaUnion,
+ InputPollOptionUnion,
+ InputProfilePhotoUnion,
+ InputSticker,
+ InputStoryContentUnion,
+ LabeledPrice,
+ LinkPreviewOptions,
+ MaskPosition,
+ MediaUnion,
+ MenuButtonUnion,
+ Message,
+ MessageEntity,
+ MessageId,
+ OwnedGifts,
+ PassportElementErrorUnion,
+ Poll,
+ PreparedInlineMessage,
+ ReactionTypeUnion,
+ ReplyMarkupUnion,
+ ReplyParameters,
+ ResultChatMemberUnion,
+ ResultMenuButtonUnion,
+ SentWebAppMessage,
+ ShippingOption,
+ StarAmount,
+ StarTransactions,
+ Sticker,
+ StickerSet,
+ Story,
+ StoryArea,
+ Update,
+ User,
+ UserChatBoosts,
+ UserProfilePhotos,
+ WebhookInfo,
+)
+from .default import Default, DefaultBotProperties
+from .session.aiohttp import AiohttpSession
+from .session.base import BaseSession
+
+T = TypeVar("T")
+
+
+class Bot:
+ def __init__(
+ self,
+ token: str,
+ session: Optional[BaseSession] = None,
+ default: Optional[DefaultBotProperties] = None,
+ **kwargs: Any,
+ ) -> None:
+ """
+ Bot class
+
+ :param token: Telegram Bot token `Obtained from @BotFather `_
+ :param session: HTTP Client session (For example AiohttpSession).
+ If not specified it will be automatically created.
+ :param default: Default bot properties.
+ If specified it will be propagated into the API methods at runtime.
+ :raise TokenValidationError: When token has invalid format this exception will be raised
+ """
+
+ validate_token(token)
+
+ if session is None:
+ session = AiohttpSession()
+ if default is None:
+ default = DefaultBotProperties()
+
+ self.session = session
+
+ # Few arguments are completely removed in 3.7.0 version
+ # Temporary solution to raise an error if user passed these arguments
+ # with explanation how to fix it
+ parse_mode = kwargs.get("parse_mode", None)
+ link_preview_is_disabled = kwargs.get("disable_web_page_preview", None)
+ protect_content = kwargs.get("protect_content", None)
+ if (
+ parse_mode is not None
+ or link_preview_is_disabled is not None
+ or protect_content is not None
+ ):
+ example_kwargs = {
+ "parse_mode": parse_mode,
+ "link_preview_is_disabled": link_preview_is_disabled,
+ "protect_content": protect_content,
+ }
+ replacement_spec = ", ".join(
+ f"{k}={v!r}" for k, v in example_kwargs.items() if v is not None
+ )
+ raise TypeError(
+ "Passing `parse_mode`, `disable_web_page_preview` or `protect_content` "
+ "to Bot initializer is not supported anymore. These arguments have been removed "
+ f"in 3.7.0 version. Use `default=DefaultBotProperties({replacement_spec})` argument instead."
+ )
+
+ self.default = default
+
+ self.__token = token
+ self._me: Optional[User] = None
+
+ async def __aenter__(self) -> "Bot":
+ return self
+
+ async def __aexit__(
+ self,
+ exc_type: Optional[Type[BaseException]],
+ exc_value: Optional[BaseException],
+ traceback: Optional[TracebackType],
+ ) -> None:
+ await self.session.close()
+
+ @property
+ def token(self) -> str:
+ return self.__token
+
+ @property
+ def id(self) -> int:
+ """
+ Get bot ID from token
+
+ :return:
+ """
+ return extract_bot_id(self.__token)
+
+ @asynccontextmanager
+ async def context(self, auto_close: bool = True) -> AsyncIterator[Bot]:
+ """
+ Generate bot context
+
+ :param auto_close: close session on exit
+ :return:
+ """
+ try:
+ yield self
+ finally:
+ if auto_close:
+ await self.session.close()
+
+ async def me(self) -> User:
+ """
+ Cached alias for getMe method
+
+ :return:
+ """
+ if self._me is None: # pragma: no cover
+ self._me = await self.get_me()
+ return self._me
+
+ @classmethod
+ async def __download_file_binary_io(
+ cls, destination: BinaryIO, seek: bool, stream: AsyncGenerator[bytes, None]
+ ) -> BinaryIO:
+ async for chunk in stream:
+ destination.write(chunk)
+ destination.flush()
+ if seek is True:
+ destination.seek(0)
+ return destination
+
+ @classmethod
+ async def __download_file(
+ cls, destination: Union[str, pathlib.Path], stream: AsyncGenerator[bytes, None]
+ ) -> None:
+ async with aiofiles.open(destination, "wb") as f:
+ async for chunk in stream:
+ await f.write(chunk)
+
+ @classmethod
+ async def __aiofiles_reader(
+ cls, file: Union[str, pathlib.Path], chunk_size: int = 65536
+ ) -> AsyncGenerator[bytes, None]:
+ async with aiofiles.open(file, "rb") as f:
+ while chunk := await f.read(chunk_size):
+ yield chunk
+
+ async def download_file(
+ self,
+ file_path: Union[str, pathlib.Path],
+ destination: Optional[Union[BinaryIO, pathlib.Path, str]] = None,
+ timeout: int = 30,
+ chunk_size: int = 65536,
+ seek: bool = True,
+ ) -> Optional[BinaryIO]:
+ """
+ Download file by file_path to destination.
+
+ If you want to automatically create destination (:class:`io.BytesIO`) use default
+ value of destination and handle result of this method.
+
+ :param file_path: File path on Telegram server (You can get it from :obj:`aiogram.types.File`)
+ :param destination: Filename, file path or instance of :class:`io.IOBase`. For e.g. :class:`io.BytesIO`, defaults to None
+ :param timeout: Total timeout in seconds, defaults to 30
+ :param chunk_size: File chunks size, defaults to 64 kb
+ :param seek: Go to start of file when downloading is finished. Used only for destination with :class:`typing.BinaryIO` type, defaults to True
+ """
+ if destination is None:
+ destination = io.BytesIO()
+
+ close_stream = False
+ if self.session.api.is_local:
+ stream = self.__aiofiles_reader(
+ self.session.api.wrap_local_file.to_local(file_path), chunk_size=chunk_size
+ )
+ close_stream = True
+ else:
+ url = self.session.api.file_url(self.__token, file_path)
+ stream = self.session.stream_content(
+ url=url,
+ timeout=timeout,
+ chunk_size=chunk_size,
+ raise_for_status=True,
+ )
+
+ try:
+ if isinstance(destination, (str, pathlib.Path)):
+ await self.__download_file(destination=destination, stream=stream)
+ return None
+ return await self.__download_file_binary_io(
+ destination=destination, seek=seek, stream=stream
+ )
+ finally:
+ if close_stream:
+ await stream.aclose()
+
+ async def download(
+ self,
+ file: Union[str, Downloadable],
+ destination: Optional[Union[BinaryIO, pathlib.Path, str]] = None,
+ timeout: int = 30,
+ chunk_size: int = 65536,
+ seek: bool = True,
+ ) -> Optional[BinaryIO]:
+ """
+ Download file by file_id or Downloadable object to destination.
+
+ If you want to automatically create destination (:class:`io.BytesIO`) use default
+ value of destination and handle result of this method.
+
+ :param file: file_id or Downloadable object
+ :param destination: Filename, file path or instance of :class:`io.IOBase`. For e.g. :class:`io.BytesIO`, defaults to None
+ :param timeout: Total timeout in seconds, defaults to 30
+ :param chunk_size: File chunks size, defaults to 64 kb
+ :param seek: Go to start of file when downloading is finished. Used only for destination with :class:`typing.BinaryIO` type, defaults to True
+ """
+ if isinstance(file, str):
+ file_id = file
+ else:
+ # type is ignored in due to:
+ # Incompatible types in assignment (expression has type "Optional[Any]", variable has type "str")
+ file_id = getattr(file, "file_id", None) # type: ignore
+ if file_id is None:
+ raise TypeError("file can only be of the string or Downloadable type")
+
+ file_ = await self.get_file(file_id)
+
+ # `file_path` can be None for large files but this files can't be downloaded
+ # So we need to do type-cast
+ # https://github.com/aiogram/aiogram/pull/282/files#r394110017
+ file_path = cast(str, file_.file_path)
+
+ return await self.download_file(
+ file_path, destination=destination, timeout=timeout, chunk_size=chunk_size, seek=seek
+ )
+
+ async def __call__(
+ self, method: TelegramMethod[T], request_timeout: Optional[int] = None
+ ) -> T:
+ """
+ Call API method
+
+ :param method:
+ :return:
+ """
+ return await self.session(self, method, timeout=request_timeout)
+
+ def __hash__(self) -> int:
+ """
+ Get hash for the token
+
+ :return:
+ """
+ return hash(self.__token)
+
+ def __eq__(self, other: Any) -> bool:
+ """
+ Compare current bot with another bot instance
+
+ :param other:
+ :return:
+ """
+ if not isinstance(other, Bot):
+ return False
+ return hash(self) == hash(other)
+
+ async def add_sticker_to_set(
+ self,
+ user_id: int,
+ name: str,
+ sticker: InputSticker,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to add a new sticker to a set created by the bot. Emoji sticker sets can have up to 200 stickers. Other sticker sets can have up to 120 stickers. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#addstickertoset
+
+ :param user_id: User identifier of sticker set owner
+ :param name: Sticker set name
+ :param sticker: A JSON-serialized object with information about the added sticker. If exactly the same sticker had already been added to the set, then the set isn't changed.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = AddStickerToSet(
+ user_id=user_id,
+ name=name,
+ sticker=sticker,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def answer_callback_query(
+ self,
+ callback_query_id: str,
+ text: Optional[str] = None,
+ show_alert: Optional[bool] = None,
+ url: Optional[str] = None,
+ cache_time: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to send answers to callback queries sent from `inline keyboards `_. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, :code:`True` is returned.
+
+ Alternatively, the user can be redirected to the specified Game URL. For this option to work, you must first create a game for your bot via `@BotFather `_ and accept the terms. Otherwise, you may use links like :code:`t.me/your_bot?start=XXXX` that open your bot with a parameter.
+
+ Source: https://core.telegram.org/bots/api#answercallbackquery
+
+ :param callback_query_id: Unique identifier for the query to be answered
+ :param text: Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters
+ :param show_alert: If :code:`True`, an alert will be shown by the client instead of a notification at the top of the chat screen. Defaults to *false*.
+ :param url: URL that will be opened by the user's client. If you have created a :class:`aiogram.types.game.Game` and accepted the conditions via `@BotFather `_, specify the URL that opens your game - note that this will only work if the query comes from a `https://core.telegram.org/bots/api#inlinekeyboardbutton `_ *callback_game* button.
+ :param cache_time: The maximum amount of time in seconds that the result of the callback query may be cached client-side. Telegram apps will support caching starting in version 3.14. Defaults to 0.
+ :param request_timeout: Request timeout
+ :return: Otherwise, you may use links like :code:`t.me/your_bot?start=XXXX` that open your bot with a parameter.
+ """
+
+ call = AnswerCallbackQuery(
+ callback_query_id=callback_query_id,
+ text=text,
+ show_alert=show_alert,
+ url=url,
+ cache_time=cache_time,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def answer_inline_query(
+ self,
+ inline_query_id: str,
+ results: list[InlineQueryResultUnion],
+ cache_time: Optional[int] = None,
+ is_personal: Optional[bool] = None,
+ next_offset: Optional[str] = None,
+ button: Optional[InlineQueryResultsButton] = None,
+ switch_pm_parameter: Optional[str] = None,
+ switch_pm_text: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to send answers to an inline query. On success, :code:`True` is returned.
+
+ No more than **50** results per query are allowed.
+
+ Source: https://core.telegram.org/bots/api#answerinlinequery
+
+ :param inline_query_id: Unique identifier for the answered query
+ :param results: A JSON-serialized array of results for the inline query
+ :param cache_time: The maximum amount of time in seconds that the result of the inline query may be cached on the server. Defaults to 300.
+ :param is_personal: Pass :code:`True` if results may be cached on the server side only for the user that sent the query. By default, results may be returned to any user who sends the same query.
+ :param next_offset: Pass the offset that a client should send in the next query with the same text to receive more results. Pass an empty string if there are no more results or if you don't support pagination. Offset length can't exceed 64 bytes.
+ :param button: A JSON-serialized object describing a button to be shown above inline query results
+ :param switch_pm_parameter: `Deep-linking `_ parameter for the /start message sent to the bot when user presses the switch button. 1-64 characters, only :code:`A-Z`, :code:`a-z`, :code:`0-9`, :code:`_` and :code:`-` are allowed.
+ :param switch_pm_text: If passed, clients will display a button with specified text that switches the user to a private chat with the bot and sends the bot a start message with the parameter *switch_pm_parameter*
+ :param request_timeout: Request timeout
+ :return: On success, :code:`True` is returned.
+ """
+
+ call = AnswerInlineQuery(
+ inline_query_id=inline_query_id,
+ results=results,
+ cache_time=cache_time,
+ is_personal=is_personal,
+ next_offset=next_offset,
+ button=button,
+ switch_pm_parameter=switch_pm_parameter,
+ switch_pm_text=switch_pm_text,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def answer_pre_checkout_query(
+ self,
+ pre_checkout_query_id: str,
+ ok: bool,
+ error_message: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of an :class:`aiogram.types.update.Update` with the field *pre_checkout_query*. Use this method to respond to such pre-checkout queries. On success, :code:`True` is returned. **Note:** The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
+
+ Source: https://core.telegram.org/bots/api#answerprecheckoutquery
+
+ :param pre_checkout_query_id: Unique identifier for the query to be answered
+ :param ok: Specify :code:`True` if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use :code:`False` if there are any problems.
+ :param error_message: Required if *ok* is :code:`False`. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user.
+ :param request_timeout: Request timeout
+ :return: **Note:** The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
+ """
+
+ call = AnswerPreCheckoutQuery(
+ pre_checkout_query_id=pre_checkout_query_id,
+ ok=ok,
+ error_message=error_message,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def answer_shipping_query(
+ self,
+ shipping_query_id: str,
+ ok: bool,
+ shipping_options: Optional[list[ShippingOption]] = None,
+ error_message: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ If you sent an invoice requesting a shipping address and the parameter *is_flexible* was specified, the Bot API will send an :class:`aiogram.types.update.Update` with a *shipping_query* field to the bot. Use this method to reply to shipping queries. On success, :code:`True` is returned.
+
+ Source: https://core.telegram.org/bots/api#answershippingquery
+
+ :param shipping_query_id: Unique identifier for the query to be answered
+ :param ok: Pass :code:`True` if delivery to the specified address is possible and :code:`False` if there are any problems (for example, if delivery to the specified address is not possible)
+ :param shipping_options: Required if *ok* is :code:`True`. A JSON-serialized array of available shipping options.
+ :param error_message: Required if *ok* is :code:`False`. Error message in human readable form that explains why it is impossible to complete the order (e.g. 'Sorry, delivery to your desired address is unavailable'). Telegram will display this message to the user.
+ :param request_timeout: Request timeout
+ :return: On success, :code:`True` is returned.
+ """
+
+ call = AnswerShippingQuery(
+ shipping_query_id=shipping_query_id,
+ ok=ok,
+ shipping_options=shipping_options,
+ error_message=error_message,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def answer_web_app_query(
+ self,
+ web_app_query_id: str,
+ result: InlineQueryResultUnion,
+ request_timeout: Optional[int] = None,
+ ) -> SentWebAppMessage:
+ """
+ Use this method to set the result of an interaction with a `Web App `_ and send a corresponding message on behalf of the user to the chat from which the query originated. On success, a :class:`aiogram.types.sent_web_app_message.SentWebAppMessage` object is returned.
+
+ Source: https://core.telegram.org/bots/api#answerwebappquery
+
+ :param web_app_query_id: Unique identifier for the query to be answered
+ :param result: A JSON-serialized object describing the message to be sent
+ :param request_timeout: Request timeout
+ :return: On success, a :class:`aiogram.types.sent_web_app_message.SentWebAppMessage` object is returned.
+ """
+
+ call = AnswerWebAppQuery(
+ web_app_query_id=web_app_query_id,
+ result=result,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def approve_chat_join_request(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to approve a chat join request. The bot must be an administrator in the chat for this to work and must have the *can_invite_users* administrator right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#approvechatjoinrequest
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param user_id: Unique identifier of the target user
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = ApproveChatJoinRequest(
+ chat_id=chat_id,
+ user_id=user_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def ban_chat_member(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ until_date: Optional[DateTimeUnion] = None,
+ revoke_messages: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to ban a user in a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the chat on their own using invite links, etc., unless `unbanned `_ first. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#banchatmember
+
+ :param chat_id: Unique identifier for the target group or username of the target supergroup or channel (in the format :code:`@channelusername`)
+ :param user_id: Unique identifier of the target user
+ :param until_date: Date when the user will be unbanned; Unix time. If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever. Applied for supergroups and channels only.
+ :param revoke_messages: Pass :code:`True` to delete all messages from the chat for the user that is being removed. If :code:`False`, the user will be able to see messages in the group that were sent before the user was removed. Always :code:`True` for supergroups and channels.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = BanChatMember(
+ chat_id=chat_id,
+ user_id=user_id,
+ until_date=until_date,
+ revoke_messages=revoke_messages,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def ban_chat_sender_chat(
+ self,
+ chat_id: ChatIdUnion,
+ sender_chat_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to ban a channel chat in a supergroup or a channel. Until the chat is `unbanned `_, the owner of the banned chat won't be able to send messages on behalf of **any of their channels**. The bot must be an administrator in the supergroup or channel for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#banchatsenderchat
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param sender_chat_id: Unique identifier of the target sender chat
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = BanChatSenderChat(
+ chat_id=chat_id,
+ sender_chat_id=sender_chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def close(
+ self,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to close the bot instance before moving it from one local server to another. You need to delete the webhook before calling this method to ensure that the bot isn't launched again after server restart. The method will return error 429 in the first 10 minutes after the bot is launched. Returns :code:`True` on success. Requires no parameters.
+
+ Source: https://core.telegram.org/bots/api#close
+
+ :param request_timeout: Request timeout
+ :return: Requires no parameters.
+ """
+
+ call = Close()
+ return await self(call, request_timeout=request_timeout)
+
+ async def close_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ message_thread_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to close an open topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights, unless it is the creator of the topic. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#closeforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param message_thread_id: Unique identifier for the target message thread of the forum topic
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = CloseForumTopic(
+ chat_id=chat_id,
+ message_thread_id=message_thread_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def copy_message(
+ self,
+ chat_id: ChatIdUnion,
+ from_chat_id: ChatIdUnion,
+ message_id: int,
+ message_thread_id: Optional[int] = None,
+ video_start_timestamp: Optional[DateTimeUnion] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ caption_entities: Optional[list[MessageEntity]] = None,
+ show_caption_above_media: Optional[Union[bool, Default]] = Default(
+ "show_caption_above_media"
+ ),
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> MessageId:
+ """
+ Use this method to copy messages of any kind. Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz :class:`aiogram.methods.poll.Poll` can be copied only if the value of the field *correct_option_id* is known to the bot. The method is analogous to the method :class:`aiogram.methods.forward_message.ForwardMessage`, but the copied message doesn't have a link to the original message. Returns the :class:`aiogram.types.message_id.MessageId` of the sent message on success.
+
+ Source: https://core.telegram.org/bots/api#copymessage
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format :code:`@channelusername`)
+ :param message_id: Message identifier in the chat specified in *from_chat_id*
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param video_start_timestamp: New start timestamp for the copied video in the message
+ :param caption: New caption for media, 0-1024 characters after entities parsing. If not specified, the original caption is kept
+ :param parse_mode: Mode for parsing entities in the new caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the new caption, which can be specified instead of *parse_mode*
+ :param show_caption_above_media: Pass :code:`True`, if the caption must be shown above the message media. Ignored if a new caption isn't specified.
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: Returns the :class:`aiogram.types.message_id.MessageId` of the sent message on success.
+ """
+
+ call = CopyMessage(
+ chat_id=chat_id,
+ from_chat_id=from_chat_id,
+ message_id=message_id,
+ message_thread_id=message_thread_id,
+ video_start_timestamp=video_start_timestamp,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ show_caption_above_media=show_caption_above_media,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def create_chat_invite_link(
+ self,
+ chat_id: ChatIdUnion,
+ name: Optional[str] = None,
+ expire_date: Optional[DateTimeUnion] = None,
+ member_limit: Optional[int] = None,
+ creates_join_request: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> ChatInviteLink:
+ """
+ Use this method to create an additional invite link for a chat. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. The link can be revoked using the method :class:`aiogram.methods.revoke_chat_invite_link.RevokeChatInviteLink`. Returns the new invite link as :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+
+ Source: https://core.telegram.org/bots/api#createchatinvitelink
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param name: Invite link name; 0-32 characters
+ :param expire_date: Point in time (Unix timestamp) when the link will expire
+ :param member_limit: The maximum number of users that can be members of the chat simultaneously after joining the chat via this invite link; 1-99999
+ :param creates_join_request: :code:`True`, if users joining the chat via the link need to be approved by chat administrators. If :code:`True`, *member_limit* can't be specified
+ :param request_timeout: Request timeout
+ :return: Returns the new invite link as :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+ """
+
+ call = CreateChatInviteLink(
+ chat_id=chat_id,
+ name=name,
+ expire_date=expire_date,
+ member_limit=member_limit,
+ creates_join_request=creates_join_request,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def create_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ name: str,
+ icon_color: Optional[int] = None,
+ icon_custom_emoji_id: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> ForumTopic:
+ """
+ Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights. Returns information about the created topic as a :class:`aiogram.types.forum_topic.ForumTopic` object.
+
+ Source: https://core.telegram.org/bots/api#createforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param name: Topic name, 1-128 characters
+ :param icon_color: Color of the topic icon in RGB format. Currently, must be one of 7322096 (0x6FB9F0), 16766590 (0xFFD67E), 13338331 (0xCB86DB), 9367192 (0x8EEE98), 16749490 (0xFF93B2), or 16478047 (0xFB6F5F)
+ :param icon_custom_emoji_id: Unique identifier of the custom emoji shown as the topic icon. Use :class:`aiogram.methods.get_forum_topic_icon_stickers.GetForumTopicIconStickers` to get all allowed custom emoji identifiers.
+ :param request_timeout: Request timeout
+ :return: Returns information about the created topic as a :class:`aiogram.types.forum_topic.ForumTopic` object.
+ """
+
+ call = CreateForumTopic(
+ chat_id=chat_id,
+ name=name,
+ icon_color=icon_color,
+ icon_custom_emoji_id=icon_custom_emoji_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def create_invoice_link(
+ self,
+ title: str,
+ description: str,
+ payload: str,
+ currency: str,
+ prices: list[LabeledPrice],
+ business_connection_id: Optional[str] = None,
+ provider_token: Optional[str] = None,
+ subscription_period: Optional[int] = None,
+ max_tip_amount: Optional[int] = None,
+ suggested_tip_amounts: Optional[list[int]] = None,
+ provider_data: Optional[str] = None,
+ photo_url: Optional[str] = None,
+ photo_size: Optional[int] = None,
+ photo_width: Optional[int] = None,
+ photo_height: Optional[int] = None,
+ need_name: Optional[bool] = None,
+ need_phone_number: Optional[bool] = None,
+ need_email: Optional[bool] = None,
+ need_shipping_address: Optional[bool] = None,
+ send_phone_number_to_provider: Optional[bool] = None,
+ send_email_to_provider: Optional[bool] = None,
+ is_flexible: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> str:
+ """
+ Use this method to create a link for an invoice. Returns the created invoice link as *String* on success.
+
+ Source: https://core.telegram.org/bots/api#createinvoicelink
+
+ :param title: Product name, 1-32 characters
+ :param description: Product description, 1-255 characters
+ :param payload: Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use it for your internal processes.
+ :param currency: Three-letter ISO 4217 currency code, see `more on currencies `_. Pass 'XTR' for payments in `Telegram Stars `_.
+ :param prices: Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). Must contain exactly one item for payments in `Telegram Stars `_.
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the link will be created. For payments in `Telegram Stars `_ only.
+ :param provider_token: Payment provider token, obtained via `@BotFather `_. Pass an empty string for payments in `Telegram Stars `_.
+ :param subscription_period: The number of seconds the subscription will be active for before the next payment. The currency must be set to 'XTR' (Telegram Stars) if the parameter is used. Currently, it must always be 2592000 (30 days) if specified. Any number of subscriptions can be active for a given bot at the same time, including multiple concurrent subscriptions from the same user. Subscription price must no exceed 10000 Telegram Stars.
+ :param max_tip_amount: The maximum accepted amount for tips in the *smallest units* of the currency (integer, **not** float/double). For example, for a maximum tip of :code:`US$ 1.45` pass :code:`max_tip_amount = 145`. See the *exp* parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in `Telegram Stars `_.
+ :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the *smallest units* of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed *max_tip_amount*.
+ :param provider_data: JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider.
+ :param photo_url: URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service.
+ :param photo_size: Photo size in bytes
+ :param photo_width: Photo width
+ :param photo_height: Photo height
+ :param need_name: Pass :code:`True` if you require the user's full name to complete the order. Ignored for payments in `Telegram Stars `_.
+ :param need_phone_number: Pass :code:`True` if you require the user's phone number to complete the order. Ignored for payments in `Telegram Stars `_.
+ :param need_email: Pass :code:`True` if you require the user's email address to complete the order. Ignored for payments in `Telegram Stars `_.
+ :param need_shipping_address: Pass :code:`True` if you require the user's shipping address to complete the order. Ignored for payments in `Telegram Stars `_.
+ :param send_phone_number_to_provider: Pass :code:`True` if the user's phone number should be sent to the provider. Ignored for payments in `Telegram Stars `_.
+ :param send_email_to_provider: Pass :code:`True` if the user's email address should be sent to the provider. Ignored for payments in `Telegram Stars `_.
+ :param is_flexible: Pass :code:`True` if the final price depends on the shipping method. Ignored for payments in `Telegram Stars `_.
+ :param request_timeout: Request timeout
+ :return: Returns the created invoice link as *String* on success.
+ """
+
+ call = CreateInvoiceLink(
+ title=title,
+ description=description,
+ payload=payload,
+ currency=currency,
+ prices=prices,
+ business_connection_id=business_connection_id,
+ provider_token=provider_token,
+ subscription_period=subscription_period,
+ max_tip_amount=max_tip_amount,
+ suggested_tip_amounts=suggested_tip_amounts,
+ provider_data=provider_data,
+ photo_url=photo_url,
+ photo_size=photo_size,
+ photo_width=photo_width,
+ photo_height=photo_height,
+ need_name=need_name,
+ need_phone_number=need_phone_number,
+ need_email=need_email,
+ need_shipping_address=need_shipping_address,
+ send_phone_number_to_provider=send_phone_number_to_provider,
+ send_email_to_provider=send_email_to_provider,
+ is_flexible=is_flexible,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def create_new_sticker_set(
+ self,
+ user_id: int,
+ name: str,
+ title: str,
+ stickers: list[InputSticker],
+ sticker_type: Optional[str] = None,
+ needs_repainting: Optional[bool] = None,
+ sticker_format: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to create a new sticker set owned by a user. The bot will be able to edit the sticker set thus created. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#createnewstickerset
+
+ :param user_id: User identifier of created sticker set owner
+ :param name: Short name of sticker set, to be used in :code:`t.me/addstickers/` URLs (e.g., *animals*). Can contain only English letters, digits and underscores. Must begin with a letter, can't contain consecutive underscores and must end in :code:`"_by_"`. :code:`` is case insensitive. 1-64 characters.
+ :param title: Sticker set title, 1-64 characters
+ :param stickers: A JSON-serialized list of 1-50 initial stickers to be added to the sticker set
+ :param sticker_type: Type of stickers in the set, pass 'regular', 'mask', or 'custom_emoji'. By default, a regular sticker set is created.
+ :param needs_repainting: Pass :code:`True` if stickers in the sticker set must be repainted to the color of text when used in messages, the accent color if used as emoji status, white on chat photos, or another appropriate color based on context; for custom emoji sticker sets only
+ :param sticker_format: Format of stickers in the set, must be one of 'static', 'animated', 'video'
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = CreateNewStickerSet(
+ user_id=user_id,
+ name=name,
+ title=title,
+ stickers=stickers,
+ sticker_type=sticker_type,
+ needs_repainting=needs_repainting,
+ sticker_format=sticker_format,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def decline_chat_join_request(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to decline a chat join request. The bot must be an administrator in the chat for this to work and must have the *can_invite_users* administrator right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#declinechatjoinrequest
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param user_id: Unique identifier of the target user
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeclineChatJoinRequest(
+ chat_id=chat_id,
+ user_id=user_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_chat_photo(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to delete a chat photo. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletechatphoto
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteChatPhoto(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_chat_sticker_set(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Use the field *can_set_sticker_set* optionally returned in :class:`aiogram.methods.get_chat.GetChat` requests to check if the bot can use this method. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletechatstickerset
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteChatStickerSet(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ message_thread_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to delete a forum topic along with all its messages in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_delete_messages* administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deleteforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param message_thread_id: Unique identifier for the target message thread of the forum topic
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteForumTopic(
+ chat_id=chat_id,
+ message_thread_id=message_thread_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_message(
+ self,
+ chat_id: ChatIdUnion,
+ message_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to delete a message, including service messages, with the following limitations:
+
+ - A message can only be deleted if it was sent less than 48 hours ago.
+
+ - Service messages about a supergroup, channel, or forum topic creation can't be deleted.
+
+ - A dice message in a private chat can only be deleted if it was sent more than 24 hours ago.
+
+ - Bots can delete outgoing messages in private chats, groups, and supergroups.
+
+ - Bots can delete incoming messages in private chats.
+
+ - Bots granted *can_post_messages* permissions can delete outgoing messages in channels.
+
+ - If the bot is an administrator of a group, it can delete any message there.
+
+ - If the bot has *can_delete_messages* permission in a supergroup or a channel, it can delete any message there.
+
+ Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletemessage
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Identifier of the message to delete
+ :param request_timeout: Request timeout
+ :return: Use this method to delete a message, including service messages, with the following limitations:
+ """
+
+ call = DeleteMessage(
+ chat_id=chat_id,
+ message_id=message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_my_commands(
+ self,
+ scope: Optional[BotCommandScopeUnion] = None,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to delete the list of the bot's commands for the given scope and user language. After deletion, `higher level commands `_ will be shown to affected users. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletemycommands
+
+ :param scope: A JSON-serialized object, describing scope of users for which the commands are relevant. Defaults to :class:`aiogram.types.bot_command_scope_default.BotCommandScopeDefault`.
+ :param language_code: A two-letter ISO 639-1 language code. If empty, commands will be applied to all users from the given scope, for whose language there are no dedicated commands
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteMyCommands(
+ scope=scope,
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_sticker_from_set(
+ self,
+ sticker: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to delete a sticker from a set created by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletestickerfromset
+
+ :param sticker: File identifier of the sticker
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteStickerFromSet(
+ sticker=sticker,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_webhook(
+ self,
+ drop_pending_updates: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to remove webhook integration if you decide to switch back to :class:`aiogram.methods.get_updates.GetUpdates`. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletewebhook
+
+ :param drop_pending_updates: Pass :code:`True` to drop all pending updates
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteWebhook(
+ drop_pending_updates=drop_pending_updates,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_chat_invite_link(
+ self,
+ chat_id: ChatIdUnion,
+ invite_link: str,
+ name: Optional[str] = None,
+ expire_date: Optional[DateTimeUnion] = None,
+ member_limit: Optional[int] = None,
+ creates_join_request: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> ChatInviteLink:
+ """
+ Use this method to edit a non-primary invite link created by the bot. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns the edited invite link as a :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+
+ Source: https://core.telegram.org/bots/api#editchatinvitelink
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param invite_link: The invite link to edit
+ :param name: Invite link name; 0-32 characters
+ :param expire_date: Point in time (Unix timestamp) when the link will expire
+ :param member_limit: The maximum number of users that can be members of the chat simultaneously after joining the chat via this invite link; 1-99999
+ :param creates_join_request: :code:`True`, if users joining the chat via the link need to be approved by chat administrators. If :code:`True`, *member_limit* can't be specified
+ :param request_timeout: Request timeout
+ :return: Returns the edited invite link as a :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+ """
+
+ call = EditChatInviteLink(
+ chat_id=chat_id,
+ invite_link=invite_link,
+ name=name,
+ expire_date=expire_date,
+ member_limit=member_limit,
+ creates_join_request=creates_join_request,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ message_thread_id: int,
+ name: Optional[str] = None,
+ icon_custom_emoji_id: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights, unless it is the creator of the topic. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#editforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param message_thread_id: Unique identifier for the target message thread of the forum topic
+ :param name: New topic name, 0-128 characters. If not specified or empty, the current name of the topic will be kept
+ :param icon_custom_emoji_id: New unique identifier of the custom emoji shown as the topic icon. Use :class:`aiogram.methods.get_forum_topic_icon_stickers.GetForumTopicIconStickers` to get all allowed custom emoji identifiers. Pass an empty string to remove the icon. If not specified, the current icon will be kept
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = EditForumTopic(
+ chat_id=chat_id,
+ message_thread_id=message_thread_id,
+ name=name,
+ icon_custom_emoji_id=icon_custom_emoji_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_message_caption(
+ self,
+ business_connection_id: Optional[str] = None,
+ chat_id: Optional[ChatIdUnion] = None,
+ message_id: Optional[int] = None,
+ inline_message_id: Optional[str] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ caption_entities: Optional[list[MessageEntity]] = None,
+ show_caption_above_media: Optional[Union[bool, Default]] = Default(
+ "show_caption_above_media"
+ ),
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Union[Message, bool]:
+ """
+ Use this method to edit captions of messages. On success, if the edited message is not an inline message, the edited :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within **48 hours** from the time they were sent.
+
+ Source: https://core.telegram.org/bots/api#editmessagecaption
+
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message to be edited was sent
+ :param chat_id: Required if *inline_message_id* is not specified. Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Required if *inline_message_id* is not specified. Identifier of the message to edit
+ :param inline_message_id: Required if *chat_id* and *message_id* are not specified. Identifier of the inline message
+ :param caption: New caption of the message, 0-1024 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the message caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param show_caption_above_media: Pass :code:`True`, if the caption must be shown above the message media. Supported only for animation, photo and video messages.
+ :param reply_markup: A JSON-serialized object for an `inline keyboard `_.
+ :param request_timeout: Request timeout
+ :return: Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within **48 hours** from the time they were sent.
+ """
+
+ call = EditMessageCaption(
+ business_connection_id=business_connection_id,
+ chat_id=chat_id,
+ message_id=message_id,
+ inline_message_id=inline_message_id,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ show_caption_above_media=show_caption_above_media,
+ reply_markup=reply_markup,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_message_live_location(
+ self,
+ latitude: float,
+ longitude: float,
+ business_connection_id: Optional[str] = None,
+ chat_id: Optional[ChatIdUnion] = None,
+ message_id: Optional[int] = None,
+ inline_message_id: Optional[str] = None,
+ live_period: Optional[int] = None,
+ horizontal_accuracy: Optional[float] = None,
+ heading: Optional[int] = None,
+ proximity_alert_radius: Optional[int] = None,
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Union[Message, bool]:
+ """
+ Use this method to edit live location messages. A location can be edited until its *live_period* expires or editing is explicitly disabled by a call to :class:`aiogram.methods.stop_message_live_location.StopMessageLiveLocation`. On success, if the edited message is not an inline message, the edited :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned.
+
+ Source: https://core.telegram.org/bots/api#editmessagelivelocation
+
+ :param latitude: Latitude of new location
+ :param longitude: Longitude of new location
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message to be edited was sent
+ :param chat_id: Required if *inline_message_id* is not specified. Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Required if *inline_message_id* is not specified. Identifier of the message to edit
+ :param inline_message_id: Required if *chat_id* and *message_id* are not specified. Identifier of the inline message
+ :param live_period: New period in seconds during which the location can be updated, starting from the message send date. If 0x7FFFFFFF is specified, then the location can be updated forever. Otherwise, the new value must not exceed the current *live_period* by more than a day, and the live location expiration date must remain within the next 90 days. If not specified, then *live_period* remains unchanged
+ :param horizontal_accuracy: The radius of uncertainty for the location, measured in meters; 0-1500
+ :param heading: Direction in which the user is moving, in degrees. Must be between 1 and 360 if specified.
+ :param proximity_alert_radius: The maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified.
+ :param reply_markup: A JSON-serialized object for a new `inline keyboard `_.
+ :param request_timeout: Request timeout
+ :return: On success, if the edited message is not an inline message, the edited :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned.
+ """
+
+ call = EditMessageLiveLocation(
+ latitude=latitude,
+ longitude=longitude,
+ business_connection_id=business_connection_id,
+ chat_id=chat_id,
+ message_id=message_id,
+ inline_message_id=inline_message_id,
+ live_period=live_period,
+ horizontal_accuracy=horizontal_accuracy,
+ heading=heading,
+ proximity_alert_radius=proximity_alert_radius,
+ reply_markup=reply_markup,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_message_media(
+ self,
+ media: InputMediaUnion,
+ business_connection_id: Optional[str] = None,
+ chat_id: Optional[ChatIdUnion] = None,
+ message_id: Optional[int] = None,
+ inline_message_id: Optional[str] = None,
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Union[Message, bool]:
+ """
+ Use this method to edit animation, audio, document, photo, or video messages, or to add media to text messages. If a message is part of a message album, then it can be edited only to an audio for audio albums, only to a document for document albums and to a photo or a video otherwise. When an inline message is edited, a new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL. On success, if the edited message is not an inline message, the edited :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within **48 hours** from the time they were sent.
+
+ Source: https://core.telegram.org/bots/api#editmessagemedia
+
+ :param media: A JSON-serialized object for a new media content of the message
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message to be edited was sent
+ :param chat_id: Required if *inline_message_id* is not specified. Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Required if *inline_message_id* is not specified. Identifier of the message to edit
+ :param inline_message_id: Required if *chat_id* and *message_id* are not specified. Identifier of the inline message
+ :param reply_markup: A JSON-serialized object for a new `inline keyboard `_.
+ :param request_timeout: Request timeout
+ :return: Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within **48 hours** from the time they were sent.
+ """
+
+ call = EditMessageMedia(
+ media=media,
+ business_connection_id=business_connection_id,
+ chat_id=chat_id,
+ message_id=message_id,
+ inline_message_id=inline_message_id,
+ reply_markup=reply_markup,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_message_reply_markup(
+ self,
+ business_connection_id: Optional[str] = None,
+ chat_id: Optional[ChatIdUnion] = None,
+ message_id: Optional[int] = None,
+ inline_message_id: Optional[str] = None,
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Union[Message, bool]:
+ """
+ Use this method to edit only the reply markup of messages. On success, if the edited message is not an inline message, the edited :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within **48 hours** from the time they were sent.
+
+ Source: https://core.telegram.org/bots/api#editmessagereplymarkup
+
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message to be edited was sent
+ :param chat_id: Required if *inline_message_id* is not specified. Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Required if *inline_message_id* is not specified. Identifier of the message to edit
+ :param inline_message_id: Required if *chat_id* and *message_id* are not specified. Identifier of the inline message
+ :param reply_markup: A JSON-serialized object for an `inline keyboard `_.
+ :param request_timeout: Request timeout
+ :return: Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within **48 hours** from the time they were sent.
+ """
+
+ call = EditMessageReplyMarkup(
+ business_connection_id=business_connection_id,
+ chat_id=chat_id,
+ message_id=message_id,
+ inline_message_id=inline_message_id,
+ reply_markup=reply_markup,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_message_text(
+ self,
+ text: str,
+ business_connection_id: Optional[str] = None,
+ chat_id: Optional[ChatIdUnion] = None,
+ message_id: Optional[int] = None,
+ inline_message_id: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ entities: Optional[list[MessageEntity]] = None,
+ link_preview_options: Optional[Union[LinkPreviewOptions, Default]] = Default(
+ "link_preview"
+ ),
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ disable_web_page_preview: Optional[Union[bool, Default]] = Default(
+ "link_preview_is_disabled"
+ ),
+ request_timeout: Optional[int] = None,
+ ) -> Union[Message, bool]:
+ """
+ Use this method to edit text and `game `_ messages. On success, if the edited message is not an inline message, the edited :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within **48 hours** from the time they were sent.
+
+ Source: https://core.telegram.org/bots/api#editmessagetext
+
+ :param text: New text of the message, 1-4096 characters after entities parsing
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message to be edited was sent
+ :param chat_id: Required if *inline_message_id* is not specified. Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Required if *inline_message_id* is not specified. Identifier of the message to edit
+ :param inline_message_id: Required if *chat_id* and *message_id* are not specified. Identifier of the inline message
+ :param parse_mode: Mode for parsing entities in the message text. See `formatting options `_ for more details.
+ :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of *parse_mode*
+ :param link_preview_options: Link preview generation options for the message
+ :param reply_markup: A JSON-serialized object for an `inline keyboard `_.
+ :param disable_web_page_preview: Disables link previews for links in this message
+ :param request_timeout: Request timeout
+ :return: Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within **48 hours** from the time they were sent.
+ """
+
+ call = EditMessageText(
+ text=text,
+ business_connection_id=business_connection_id,
+ chat_id=chat_id,
+ message_id=message_id,
+ inline_message_id=inline_message_id,
+ parse_mode=parse_mode,
+ entities=entities,
+ link_preview_options=link_preview_options,
+ reply_markup=reply_markup,
+ disable_web_page_preview=disable_web_page_preview,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def export_chat_invite_link(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> str:
+ """
+ Use this method to generate a new primary invite link for a chat; any previously generated primary link is revoked. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns the new invite link as *String* on success.
+
+ Note: Each administrator in a chat generates their own invite links. Bots can't use invite links generated by other administrators. If you want your bot to work with invite links, it will need to generate its own link using :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` or by calling the :class:`aiogram.methods.get_chat.GetChat` method. If your bot needs to generate a new primary invite link replacing its previous one, use :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` again.
+
+ Source: https://core.telegram.org/bots/api#exportchatinvitelink
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param request_timeout: Request timeout
+ :return: If your bot needs to generate a new primary invite link replacing its previous one, use :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` again.
+ """
+
+ call = ExportChatInviteLink(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def forward_message(
+ self,
+ chat_id: ChatIdUnion,
+ from_chat_id: ChatIdUnion,
+ message_id: int,
+ message_thread_id: Optional[int] = None,
+ video_start_timestamp: Optional[DateTimeUnion] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to forward messages of any kind. Service messages and messages with protected content can't be forwarded. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#forwardmessage
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format :code:`@channelusername`)
+ :param message_id: Message identifier in the chat specified in *from_chat_id*
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param video_start_timestamp: New start timestamp for the forwarded video in the message
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the forwarded message from forwarding and saving
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = ForwardMessage(
+ chat_id=chat_id,
+ from_chat_id=from_chat_id,
+ message_id=message_id,
+ message_thread_id=message_thread_id,
+ video_start_timestamp=video_start_timestamp,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_chat(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> ChatFullInfo:
+ """
+ Use this method to get up-to-date information about the chat. Returns a :class:`aiogram.types.chat_full_info.ChatFullInfo` object on success.
+
+ Source: https://core.telegram.org/bots/api#getchat
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup or channel (in the format :code:`@channelusername`)
+ :param request_timeout: Request timeout
+ :return: Returns a :class:`aiogram.types.chat_full_info.ChatFullInfo` object on success.
+ """
+
+ call = GetChat(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_chat_administrators(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> list[ResultChatMemberUnion]:
+ """
+ Use this method to get a list of administrators in a chat, which aren't bots. Returns an Array of :class:`aiogram.types.chat_member.ChatMember` objects.
+
+ Source: https://core.telegram.org/bots/api#getchatadministrators
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup or channel (in the format :code:`@channelusername`)
+ :param request_timeout: Request timeout
+ :return: Returns an Array of :class:`aiogram.types.chat_member.ChatMember` objects.
+ """
+
+ call = GetChatAdministrators(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_chat_member(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> ResultChatMemberUnion:
+ """
+ Use this method to get information about a member of a chat. The method is only guaranteed to work for other users if the bot is an administrator in the chat. Returns a :class:`aiogram.types.chat_member.ChatMember` object on success.
+
+ Source: https://core.telegram.org/bots/api#getchatmember
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup or channel (in the format :code:`@channelusername`)
+ :param user_id: Unique identifier of the target user
+ :param request_timeout: Request timeout
+ :return: Returns a :class:`aiogram.types.chat_member.ChatMember` object on success.
+ """
+
+ call = GetChatMember(
+ chat_id=chat_id,
+ user_id=user_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_chat_member_count(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> int:
+ """
+ Use this method to get the number of members in a chat. Returns *Int* on success.
+
+ Source: https://core.telegram.org/bots/api#getchatmembercount
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup or channel (in the format :code:`@channelusername`)
+ :param request_timeout: Request timeout
+ :return: Returns *Int* on success.
+ """
+
+ call = GetChatMemberCount(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_chat_menu_button(
+ self,
+ chat_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> ResultMenuButtonUnion:
+ """
+ Use this method to get the current value of the bot's menu button in a private chat, or the default menu button. Returns :class:`aiogram.types.menu_button.MenuButton` on success.
+
+ Source: https://core.telegram.org/bots/api#getchatmenubutton
+
+ :param chat_id: Unique identifier for the target private chat. If not specified, default bot's menu button will be returned
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.menu_button.MenuButton` on success.
+ """
+
+ call = GetChatMenuButton(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_custom_emoji_stickers(
+ self,
+ custom_emoji_ids: list[str],
+ request_timeout: Optional[int] = None,
+ ) -> list[Sticker]:
+ """
+ Use this method to get information about custom emoji stickers by their identifiers. Returns an Array of :class:`aiogram.types.sticker.Sticker` objects.
+
+ Source: https://core.telegram.org/bots/api#getcustomemojistickers
+
+ :param custom_emoji_ids: A JSON-serialized list of custom emoji identifiers. At most 200 custom emoji identifiers can be specified.
+ :param request_timeout: Request timeout
+ :return: Returns an Array of :class:`aiogram.types.sticker.Sticker` objects.
+ """
+
+ call = GetCustomEmojiStickers(
+ custom_emoji_ids=custom_emoji_ids,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_file(
+ self,
+ file_id: str,
+ request_timeout: Optional[int] = None,
+ ) -> File:
+ """
+ Use this method to get basic information about a file and prepare it for downloading. For the moment, bots can download files of up to 20MB in size. On success, a :class:`aiogram.types.file.File` object is returned. The file can then be downloaded via the link :code:`https://api.telegram.org/file/bot/`, where :code:`` is taken from the response. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling :class:`aiogram.methods.get_file.GetFile` again.
+ **Note:** This function may not preserve the original file name and MIME type. You should save the file's MIME type and name (if available) when the File object is received.
+
+ Source: https://core.telegram.org/bots/api#getfile
+
+ :param file_id: File identifier to get information about
+ :param request_timeout: Request timeout
+ :return: You should save the file's MIME type and name (if available) when the File object is received.
+ """
+
+ call = GetFile(
+ file_id=file_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_forum_topic_icon_stickers(
+ self,
+ request_timeout: Optional[int] = None,
+ ) -> list[Sticker]:
+ """
+ Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. Requires no parameters. Returns an Array of :class:`aiogram.types.sticker.Sticker` objects.
+
+ Source: https://core.telegram.org/bots/api#getforumtopiciconstickers
+
+ :param request_timeout: Request timeout
+ :return: Returns an Array of :class:`aiogram.types.sticker.Sticker` objects.
+ """
+
+ call = GetForumTopicIconStickers()
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_game_high_scores(
+ self,
+ user_id: int,
+ chat_id: Optional[int] = None,
+ message_id: Optional[int] = None,
+ inline_message_id: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> list[GameHighScore]:
+ """
+ Use this method to get data for high score tables. Will return the score of the specified user and several of their neighbors in a game. Returns an Array of :class:`aiogram.types.game_high_score.GameHighScore` objects.
+
+ This method will currently return scores for the target user, plus two of their closest neighbors on each side. Will also return the top three users if the user and their neighbors are not among them. Please note that this behavior is subject to change.
+
+ Source: https://core.telegram.org/bots/api#getgamehighscores
+
+ :param user_id: Target user id
+ :param chat_id: Required if *inline_message_id* is not specified. Unique identifier for the target chat
+ :param message_id: Required if *inline_message_id* is not specified. Identifier of the sent message
+ :param inline_message_id: Required if *chat_id* and *message_id* are not specified. Identifier of the inline message
+ :param request_timeout: Request timeout
+ :return: Please note that this behavior is subject to change.
+ """
+
+ call = GetGameHighScores(
+ user_id=user_id,
+ chat_id=chat_id,
+ message_id=message_id,
+ inline_message_id=inline_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_me(
+ self,
+ request_timeout: Optional[int] = None,
+ ) -> User:
+ """
+ A simple method for testing your bot's authentication token. Requires no parameters. Returns basic information about the bot in form of a :class:`aiogram.types.user.User` object.
+
+ Source: https://core.telegram.org/bots/api#getme
+
+ :param request_timeout: Request timeout
+ :return: Returns basic information about the bot in form of a :class:`aiogram.types.user.User` object.
+ """
+
+ call = GetMe()
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_my_commands(
+ self,
+ scope: Optional[BotCommandScopeUnion] = None,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> list[BotCommand]:
+ """
+ Use this method to get the current list of the bot's commands for the given scope and user language. Returns an Array of :class:`aiogram.types.bot_command.BotCommand` objects. If commands aren't set, an empty list is returned.
+
+ Source: https://core.telegram.org/bots/api#getmycommands
+
+ :param scope: A JSON-serialized object, describing scope of users. Defaults to :class:`aiogram.types.bot_command_scope_default.BotCommandScopeDefault`.
+ :param language_code: A two-letter ISO 639-1 language code or an empty string
+ :param request_timeout: Request timeout
+ :return: If commands aren't set, an empty list is returned.
+ """
+
+ call = GetMyCommands(
+ scope=scope,
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_my_default_administrator_rights(
+ self,
+ for_channels: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> ChatAdministratorRights:
+ """
+ Use this method to get the current default administrator rights of the bot. Returns :class:`aiogram.types.chat_administrator_rights.ChatAdministratorRights` on success.
+
+ Source: https://core.telegram.org/bots/api#getmydefaultadministratorrights
+
+ :param for_channels: Pass :code:`True` to get default administrator rights of the bot in channels. Otherwise, default administrator rights of the bot for groups and supergroups will be returned.
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.chat_administrator_rights.ChatAdministratorRights` on success.
+ """
+
+ call = GetMyDefaultAdministratorRights(
+ for_channels=for_channels,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_sticker_set(
+ self,
+ name: str,
+ request_timeout: Optional[int] = None,
+ ) -> StickerSet:
+ """
+ Use this method to get a sticker set. On success, a :class:`aiogram.types.sticker_set.StickerSet` object is returned.
+
+ Source: https://core.telegram.org/bots/api#getstickerset
+
+ :param name: Name of the sticker set
+ :param request_timeout: Request timeout
+ :return: On success, a :class:`aiogram.types.sticker_set.StickerSet` object is returned.
+ """
+
+ call = GetStickerSet(
+ name=name,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_updates(
+ self,
+ offset: Optional[int] = None,
+ limit: Optional[int] = None,
+ timeout: Optional[int] = None,
+ allowed_updates: Optional[list[str]] = None,
+ request_timeout: Optional[int] = None,
+ ) -> list[Update]:
+ """
+ Use this method to receive incoming updates using long polling (`wiki `_). Returns an Array of :class:`aiogram.types.update.Update` objects.
+
+ **Notes**
+
+ **1.** This method will not work if an outgoing webhook is set up.
+
+ **2.** In order to avoid getting duplicate updates, recalculate *offset* after each server response.
+
+ Source: https://core.telegram.org/bots/api#getupdates
+
+ :param offset: Identifier of the first update to be returned. Must be greater by one than the highest among the identifiers of previously received updates. By default, updates starting with the earliest unconfirmed update are returned. An update is considered confirmed as soon as :class:`aiogram.methods.get_updates.GetUpdates` is called with an *offset* higher than its *update_id*. The negative offset can be specified to retrieve updates starting from *-offset* update from the end of the updates queue. All previous updates will be forgotten.
+ :param limit: Limits the number of updates to be retrieved. Values between 1-100 are accepted. Defaults to 100.
+ :param timeout: Timeout in seconds for long polling. Defaults to 0, i.e. usual short polling. Should be positive, short polling should be used for testing purposes only.
+ :param allowed_updates: A JSON-serialized list of the update types you want your bot to receive. For example, specify :code:`["message", "edited_channel_post", "callback_query"]` to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all update types except *chat_member*, *message_reaction*, and *message_reaction_count* (default). If not specified, the previous setting will be used.
+ :param request_timeout: Request timeout
+ :return: Returns an Array of :class:`aiogram.types.update.Update` objects.
+ """
+
+ call = GetUpdates(
+ offset=offset,
+ limit=limit,
+ timeout=timeout,
+ allowed_updates=allowed_updates,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_user_profile_photos(
+ self,
+ user_id: int,
+ offset: Optional[int] = None,
+ limit: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> UserProfilePhotos:
+ """
+ Use this method to get a list of profile pictures for a user. Returns a :class:`aiogram.types.user_profile_photos.UserProfilePhotos` object.
+
+ Source: https://core.telegram.org/bots/api#getuserprofilephotos
+
+ :param user_id: Unique identifier of the target user
+ :param offset: Sequential number of the first photo to be returned. By default, all photos are returned.
+ :param limit: Limits the number of photos to be retrieved. Values between 1-100 are accepted. Defaults to 100.
+ :param request_timeout: Request timeout
+ :return: Returns a :class:`aiogram.types.user_profile_photos.UserProfilePhotos` object.
+ """
+
+ call = GetUserProfilePhotos(
+ user_id=user_id,
+ offset=offset,
+ limit=limit,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_webhook_info(
+ self,
+ request_timeout: Optional[int] = None,
+ ) -> WebhookInfo:
+ """
+ Use this method to get current webhook status. Requires no parameters. On success, returns a :class:`aiogram.types.webhook_info.WebhookInfo` object. If the bot is using :class:`aiogram.methods.get_updates.GetUpdates`, will return an object with the *url* field empty.
+
+ Source: https://core.telegram.org/bots/api#getwebhookinfo
+
+ :param request_timeout: Request timeout
+ :return: If the bot is using :class:`aiogram.methods.get_updates.GetUpdates`, will return an object with the *url* field empty.
+ """
+
+ call = GetWebhookInfo()
+ return await self(call, request_timeout=request_timeout)
+
+ async def leave_chat(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method for your bot to leave a group, supergroup or channel. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#leavechat
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup or channel (in the format :code:`@channelusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = LeaveChat(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def log_out(
+ self,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to log out from the cloud Bot API server before launching the bot locally. You **must** log out the bot before running it locally, otherwise there is no guarantee that the bot will receive updates. After a successful call, you can immediately log in on a local server, but will not be able to log in back to the cloud Bot API server for 10 minutes. Returns :code:`True` on success. Requires no parameters.
+
+ Source: https://core.telegram.org/bots/api#logout
+
+ :param request_timeout: Request timeout
+ :return: Requires no parameters.
+ """
+
+ call = LogOut()
+ return await self(call, request_timeout=request_timeout)
+
+ async def pin_chat_message(
+ self,
+ chat_id: ChatIdUnion,
+ message_id: int,
+ business_connection_id: Optional[str] = None,
+ disable_notification: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to add a message to the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#pinchatmessage
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Identifier of a message to pin
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be pinned
+ :param disable_notification: Pass :code:`True` if it is not necessary to send a notification to all chat members about the new pinned message. Notifications are always disabled in channels and private chats.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = PinChatMessage(
+ chat_id=chat_id,
+ message_id=message_id,
+ business_connection_id=business_connection_id,
+ disable_notification=disable_notification,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def promote_chat_member(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ is_anonymous: Optional[bool] = None,
+ can_manage_chat: Optional[bool] = None,
+ can_delete_messages: Optional[bool] = None,
+ can_manage_video_chats: Optional[bool] = None,
+ can_restrict_members: Optional[bool] = None,
+ can_promote_members: Optional[bool] = None,
+ can_change_info: Optional[bool] = None,
+ can_invite_users: Optional[bool] = None,
+ can_post_stories: Optional[bool] = None,
+ can_edit_stories: Optional[bool] = None,
+ can_delete_stories: Optional[bool] = None,
+ can_post_messages: Optional[bool] = None,
+ can_edit_messages: Optional[bool] = None,
+ can_pin_messages: Optional[bool] = None,
+ can_manage_topics: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Pass :code:`False` for all boolean parameters to demote a user. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#promotechatmember
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param user_id: Unique identifier of the target user
+ :param is_anonymous: Pass :code:`True` if the administrator's presence in the chat is hidden
+ :param can_manage_chat: Pass :code:`True` if the administrator can access the chat event log, get boost list, see hidden supergroup and channel members, report spam messages and ignore slow mode. Implied by any other administrator privilege.
+ :param can_delete_messages: Pass :code:`True` if the administrator can delete messages of other users
+ :param can_manage_video_chats: Pass :code:`True` if the administrator can manage video chats
+ :param can_restrict_members: Pass :code:`True` if the administrator can restrict, ban or unban chat members, or access supergroup statistics
+ :param can_promote_members: Pass :code:`True` if the administrator can add new administrators with a subset of their own privileges or demote administrators that they have promoted, directly or indirectly (promoted by administrators that were appointed by him)
+ :param can_change_info: Pass :code:`True` if the administrator can change chat title, photo and other settings
+ :param can_invite_users: Pass :code:`True` if the administrator can invite new users to the chat
+ :param can_post_stories: Pass :code:`True` if the administrator can post stories to the chat
+ :param can_edit_stories: Pass :code:`True` if the administrator can edit stories posted by other users, post stories to the chat page, pin chat stories, and access the chat's story archive
+ :param can_delete_stories: Pass :code:`True` if the administrator can delete stories posted by other users
+ :param can_post_messages: Pass :code:`True` if the administrator can post messages in the channel, or access channel statistics; for channels only
+ :param can_edit_messages: Pass :code:`True` if the administrator can edit messages of other users and can pin messages; for channels only
+ :param can_pin_messages: Pass :code:`True` if the administrator can pin messages; for supergroups only
+ :param can_manage_topics: Pass :code:`True` if the user is allowed to create, rename, close, and reopen forum topics; for supergroups only
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = PromoteChatMember(
+ chat_id=chat_id,
+ user_id=user_id,
+ is_anonymous=is_anonymous,
+ can_manage_chat=can_manage_chat,
+ can_delete_messages=can_delete_messages,
+ can_manage_video_chats=can_manage_video_chats,
+ can_restrict_members=can_restrict_members,
+ can_promote_members=can_promote_members,
+ can_change_info=can_change_info,
+ can_invite_users=can_invite_users,
+ can_post_stories=can_post_stories,
+ can_edit_stories=can_edit_stories,
+ can_delete_stories=can_delete_stories,
+ can_post_messages=can_post_messages,
+ can_edit_messages=can_edit_messages,
+ can_pin_messages=can_pin_messages,
+ can_manage_topics=can_manage_topics,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def reopen_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ message_thread_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights, unless it is the creator of the topic. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#reopenforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param message_thread_id: Unique identifier for the target message thread of the forum topic
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = ReopenForumTopic(
+ chat_id=chat_id,
+ message_thread_id=message_thread_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def restrict_chat_member(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ permissions: ChatPermissions,
+ use_independent_chat_permissions: Optional[bool] = None,
+ until_date: Optional[DateTimeUnion] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for this to work and must have the appropriate administrator rights. Pass :code:`True` for all permissions to lift restrictions from a user. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#restrictchatmember
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param user_id: Unique identifier of the target user
+ :param permissions: A JSON-serialized object for new user permissions
+ :param use_independent_chat_permissions: Pass :code:`True` if chat permissions are set independently. Otherwise, the *can_send_other_messages* and *can_add_web_page_previews* permissions will imply the *can_send_messages*, *can_send_audios*, *can_send_documents*, *can_send_photos*, *can_send_videos*, *can_send_video_notes*, and *can_send_voice_notes* permissions; the *can_send_polls* permission will imply the *can_send_messages* permission.
+ :param until_date: Date when restrictions will be lifted for the user; Unix time. If user is restricted for more than 366 days or less than 30 seconds from the current time, they are considered to be restricted forever
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = RestrictChatMember(
+ chat_id=chat_id,
+ user_id=user_id,
+ permissions=permissions,
+ use_independent_chat_permissions=use_independent_chat_permissions,
+ until_date=until_date,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def revoke_chat_invite_link(
+ self,
+ chat_id: ChatIdUnion,
+ invite_link: str,
+ request_timeout: Optional[int] = None,
+ ) -> ChatInviteLink:
+ """
+ Use this method to revoke an invite link created by the bot. If the primary link is revoked, a new link is automatically generated. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns the revoked invite link as :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+
+ Source: https://core.telegram.org/bots/api#revokechatinvitelink
+
+ :param chat_id: Unique identifier of the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param invite_link: The invite link to revoke
+ :param request_timeout: Request timeout
+ :return: Returns the revoked invite link as :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+ """
+
+ call = RevokeChatInviteLink(
+ chat_id=chat_id,
+ invite_link=invite_link,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_animation(
+ self,
+ chat_id: ChatIdUnion,
+ animation: InputFileUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ duration: Optional[int] = None,
+ width: Optional[int] = None,
+ height: Optional[int] = None,
+ thumbnail: Optional[InputFile] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ caption_entities: Optional[list[MessageEntity]] = None,
+ show_caption_above_media: Optional[Union[bool, Default]] = Default(
+ "show_caption_above_media"
+ ),
+ has_spoiler: Optional[bool] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent :class:`aiogram.types.message.Message` is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
+
+ Source: https://core.telegram.org/bots/api#sendanimation
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param animation: Animation to send. Pass a file_id as String to send an animation that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an animation from the Internet, or upload a new animation using multipart/form-data. :ref:`More information on Sending Files » `
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param duration: Duration of sent animation in seconds
+ :param width: Animation width
+ :param height: Animation height
+ :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://' if the thumbnail was uploaded using multipart/form-data under . :ref:`More information on Sending Files » `
+ :param caption: Animation caption (may also be used when resending animation by *file_id*), 0-1024 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the animation caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param show_caption_above_media: Pass :code:`True`, if the caption must be shown above the message media
+ :param has_spoiler: Pass :code:`True` if the animation needs to be covered with a spoiler animation
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
+ """
+
+ call = SendAnimation(
+ chat_id=chat_id,
+ animation=animation,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ duration=duration,
+ width=width,
+ height=height,
+ thumbnail=thumbnail,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ show_caption_above_media=show_caption_above_media,
+ has_spoiler=has_spoiler,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_audio(
+ self,
+ chat_id: ChatIdUnion,
+ audio: InputFileUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ caption_entities: Optional[list[MessageEntity]] = None,
+ duration: Optional[int] = None,
+ performer: Optional[str] = None,
+ title: Optional[str] = None,
+ thumbnail: Optional[InputFile] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .MP3 or .M4A format. On success, the sent :class:`aiogram.types.message.Message` is returned. Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
+ For sending voice messages, use the :class:`aiogram.methods.send_voice.SendVoice` method instead.
+
+ Source: https://core.telegram.org/bots/api#sendaudio
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param audio: Audio file to send. Pass a file_id as String to send an audio file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an audio file from the Internet, or upload a new one using multipart/form-data. :ref:`More information on Sending Files » `
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param caption: Audio caption, 0-1024 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the audio caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param duration: Duration of the audio in seconds
+ :param performer: Performer
+ :param title: Track name
+ :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://' if the thumbnail was uploaded using multipart/form-data under . :ref:`More information on Sending Files » `
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
+ """
+
+ call = SendAudio(
+ chat_id=chat_id,
+ audio=audio,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ duration=duration,
+ performer=performer,
+ title=title,
+ thumbnail=thumbnail,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_chat_action(
+ self,
+ chat_id: ChatIdUnion,
+ action: str,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns :code:`True` on success.
+
+ Example: The `ImageBot `_ needs some time to process a request and upload the image. Instead of sending a text message along the lines of 'Retrieving image, please wait…', the bot may use :class:`aiogram.methods.send_chat_action.SendChatAction` with *action* = *upload_photo*. The user will see a 'sending photo' status for the bot.
+
+ We only recommend using this method when a response from the bot will take a **noticeable** amount of time to arrive.
+
+ Source: https://core.telegram.org/bots/api#sendchataction
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param action: Type of action to broadcast. Choose one, depending on what the user is about to receive: *typing* for `text messages `_, *upload_photo* for `photos `_, *record_video* or *upload_video* for `videos `_, *record_voice* or *upload_voice* for `voice notes `_, *upload_document* for `general files `_, *choose_sticker* for `stickers `_, *find_location* for `location data `_, *record_video_note* or *upload_video_note* for `video notes `_.
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the action will be sent
+ :param message_thread_id: Unique identifier for the target message thread; for supergroups only
+ :param request_timeout: Request timeout
+ :return: The user will see a 'sending photo' status for the bot.
+ """
+
+ call = SendChatAction(
+ chat_id=chat_id,
+ action=action,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_contact(
+ self,
+ chat_id: ChatIdUnion,
+ phone_number: str,
+ first_name: str,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ last_name: Optional[str] = None,
+ vcard: Optional[str] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send phone contacts. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendcontact
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param phone_number: Contact's phone number
+ :param first_name: Contact's first name
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param last_name: Contact's last name
+ :param vcard: Additional data about the contact in the form of a `vCard `_, 0-2048 bytes
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendContact(
+ chat_id=chat_id,
+ phone_number=phone_number,
+ first_name=first_name,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ last_name=last_name,
+ vcard=vcard,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_dice(
+ self,
+ chat_id: ChatIdUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ emoji: Optional[str] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send an animated emoji that will display a random value. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#senddice
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param emoji: Emoji on which the dice throw animation is based. Currently, must be one of '🎲', '🎯', '🏀', '⚽', '🎳', or '🎰'. Dice can have values 1-6 for '🎲', '🎯' and '🎳', values 1-5 for '🏀' and '⚽', and values 1-64 for '🎰'. Defaults to '🎲'
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendDice(
+ chat_id=chat_id,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ emoji=emoji,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_document(
+ self,
+ chat_id: ChatIdUnion,
+ document: InputFileUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ thumbnail: Optional[InputFile] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ caption_entities: Optional[list[MessageEntity]] = None,
+ disable_content_type_detection: Optional[bool] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send general files. On success, the sent :class:`aiogram.types.message.Message` is returned. Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
+
+ Source: https://core.telegram.org/bots/api#senddocument
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param document: File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. :ref:`More information on Sending Files » `
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://' if the thumbnail was uploaded using multipart/form-data under . :ref:`More information on Sending Files » `
+ :param caption: Document caption (may also be used when resending documents by *file_id*), 0-1024 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the document caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param disable_content_type_detection: Disables automatic server-side content type detection for files uploaded using multipart/form-data
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
+ """
+
+ call = SendDocument(
+ chat_id=chat_id,
+ document=document,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ thumbnail=thumbnail,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ disable_content_type_detection=disable_content_type_detection,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_game(
+ self,
+ chat_id: int,
+ game_short_name: str,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send a game. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendgame
+
+ :param chat_id: Unique identifier for the target chat
+ :param game_short_name: Short name of the game, serves as the unique identifier for the game. Set up your games via `@BotFather `_.
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: A JSON-serialized object for an `inline keyboard `_. If empty, one 'Play game_title' button will be shown. If not empty, the first button must launch the game.
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendGame(
+ chat_id=chat_id,
+ game_short_name=game_short_name,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_invoice(
+ self,
+ chat_id: ChatIdUnion,
+ title: str,
+ description: str,
+ payload: str,
+ currency: str,
+ prices: list[LabeledPrice],
+ message_thread_id: Optional[int] = None,
+ provider_token: Optional[str] = None,
+ max_tip_amount: Optional[int] = None,
+ suggested_tip_amounts: Optional[list[int]] = None,
+ start_parameter: Optional[str] = None,
+ provider_data: Optional[str] = None,
+ photo_url: Optional[str] = None,
+ photo_size: Optional[int] = None,
+ photo_width: Optional[int] = None,
+ photo_height: Optional[int] = None,
+ need_name: Optional[bool] = None,
+ need_phone_number: Optional[bool] = None,
+ need_email: Optional[bool] = None,
+ need_shipping_address: Optional[bool] = None,
+ send_phone_number_to_provider: Optional[bool] = None,
+ send_email_to_provider: Optional[bool] = None,
+ is_flexible: Optional[bool] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send invoices. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendinvoice
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param title: Product name, 1-32 characters
+ :param description: Product description, 1-255 characters
+ :param payload: Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use it for your internal processes.
+ :param currency: Three-letter ISO 4217 currency code, see `more on currencies `_. Pass 'XTR' for payments in `Telegram Stars `_.
+ :param prices: Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). Must contain exactly one item for payments in `Telegram Stars `_.
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param provider_token: Payment provider token, obtained via `@BotFather `_. Pass an empty string for payments in `Telegram Stars `_.
+ :param max_tip_amount: The maximum accepted amount for tips in the *smallest units* of the currency (integer, **not** float/double). For example, for a maximum tip of :code:`US$ 1.45` pass :code:`max_tip_amount = 145`. See the *exp* parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in `Telegram Stars `_.
+ :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the *smallest units* of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed *max_tip_amount*.
+ :param start_parameter: Unique deep-linking parameter. If left empty, **forwarded copies** of the sent message will have a *Pay* button, allowing multiple users to pay directly from the forwarded message, using the same invoice. If non-empty, forwarded copies of the sent message will have a *URL* button with a deep link to the bot (instead of a *Pay* button), with the value used as the start parameter
+ :param provider_data: JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider.
+ :param photo_url: URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for.
+ :param photo_size: Photo size in bytes
+ :param photo_width: Photo width
+ :param photo_height: Photo height
+ :param need_name: Pass :code:`True` if you require the user's full name to complete the order. Ignored for payments in `Telegram Stars `_.
+ :param need_phone_number: Pass :code:`True` if you require the user's phone number to complete the order. Ignored for payments in `Telegram Stars `_.
+ :param need_email: Pass :code:`True` if you require the user's email address to complete the order. Ignored for payments in `Telegram Stars `_.
+ :param need_shipping_address: Pass :code:`True` if you require the user's shipping address to complete the order. Ignored for payments in `Telegram Stars `_.
+ :param send_phone_number_to_provider: Pass :code:`True` if the user's phone number should be sent to the provider. Ignored for payments in `Telegram Stars `_.
+ :param send_email_to_provider: Pass :code:`True` if the user's email address should be sent to the provider. Ignored for payments in `Telegram Stars `_.
+ :param is_flexible: Pass :code:`True` if the final price depends on the shipping method. Ignored for payments in `Telegram Stars `_.
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: A JSON-serialized object for an `inline keyboard `_. If empty, one 'Pay :code:`total price`' button will be shown. If not empty, the first button must be a Pay button.
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendInvoice(
+ chat_id=chat_id,
+ title=title,
+ description=description,
+ payload=payload,
+ currency=currency,
+ prices=prices,
+ message_thread_id=message_thread_id,
+ provider_token=provider_token,
+ max_tip_amount=max_tip_amount,
+ suggested_tip_amounts=suggested_tip_amounts,
+ start_parameter=start_parameter,
+ provider_data=provider_data,
+ photo_url=photo_url,
+ photo_size=photo_size,
+ photo_width=photo_width,
+ photo_height=photo_height,
+ need_name=need_name,
+ need_phone_number=need_phone_number,
+ need_email=need_email,
+ need_shipping_address=need_shipping_address,
+ send_phone_number_to_provider=send_phone_number_to_provider,
+ send_email_to_provider=send_email_to_provider,
+ is_flexible=is_flexible,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_location(
+ self,
+ chat_id: ChatIdUnion,
+ latitude: float,
+ longitude: float,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ horizontal_accuracy: Optional[float] = None,
+ live_period: Optional[int] = None,
+ heading: Optional[int] = None,
+ proximity_alert_radius: Optional[int] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send point on the map. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendlocation
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param latitude: Latitude of the location
+ :param longitude: Longitude of the location
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param horizontal_accuracy: The radius of uncertainty for the location, measured in meters; 0-1500
+ :param live_period: Period in seconds during which the location will be updated (see `Live Locations `_, should be between 60 and 86400, or 0x7FFFFFFF for live locations that can be edited indefinitely.
+ :param heading: For live locations, a direction in which the user is moving, in degrees. Must be between 1 and 360 if specified.
+ :param proximity_alert_radius: For live locations, a maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified.
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendLocation(
+ chat_id=chat_id,
+ latitude=latitude,
+ longitude=longitude,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ horizontal_accuracy=horizontal_accuracy,
+ live_period=live_period,
+ heading=heading,
+ proximity_alert_radius=proximity_alert_radius,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_media_group(
+ self,
+ chat_id: ChatIdUnion,
+ media: list[MediaUnion],
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> list[Message]:
+ """
+ Use this method to send a group of photos, videos, documents or audios as an album. Documents and audio files can be only grouped in an album with messages of the same type. On success, an array of `Messages `_ that were sent is returned.
+
+ Source: https://core.telegram.org/bots/api#sendmediagroup
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param media: A JSON-serialized array describing messages to be sent, must include 2-10 items
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param disable_notification: Sends messages `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent messages from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the messages are a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, an array of `Messages `_ that were sent is returned.
+ """
+
+ call = SendMediaGroup(
+ chat_id=chat_id,
+ media=media,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_message(
+ self,
+ chat_id: ChatIdUnion,
+ text: str,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ entities: Optional[list[MessageEntity]] = None,
+ link_preview_options: Optional[Union[LinkPreviewOptions, Default]] = Default(
+ "link_preview"
+ ),
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ disable_web_page_preview: Optional[Union[bool, Default]] = Default(
+ "link_preview_is_disabled"
+ ),
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send text messages. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendmessage
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param text: Text of the message to be sent, 1-4096 characters after entities parsing
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param parse_mode: Mode for parsing entities in the message text. See `formatting options `_ for more details.
+ :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of *parse_mode*
+ :param link_preview_options: Link preview generation options for the message
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param disable_web_page_preview: Disables link previews for links in this message
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendMessage(
+ chat_id=chat_id,
+ text=text,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ parse_mode=parse_mode,
+ entities=entities,
+ link_preview_options=link_preview_options,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ disable_web_page_preview=disable_web_page_preview,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_photo(
+ self,
+ chat_id: ChatIdUnion,
+ photo: InputFileUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ caption_entities: Optional[list[MessageEntity]] = None,
+ show_caption_above_media: Optional[Union[bool, Default]] = Default(
+ "show_caption_above_media"
+ ),
+ has_spoiler: Optional[bool] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send photos. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendphoto
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param photo: Photo to send. Pass a file_id as String to send a photo that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a photo from the Internet, or upload a new photo using multipart/form-data. The photo must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20. :ref:`More information on Sending Files » `
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param caption: Photo caption (may also be used when resending photos by *file_id*), 0-1024 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the photo caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param show_caption_above_media: Pass :code:`True`, if the caption must be shown above the message media
+ :param has_spoiler: Pass :code:`True` if the photo needs to be covered with a spoiler animation
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendPhoto(
+ chat_id=chat_id,
+ photo=photo,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ show_caption_above_media=show_caption_above_media,
+ has_spoiler=has_spoiler,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_poll(
+ self,
+ chat_id: ChatIdUnion,
+ question: str,
+ options: list[InputPollOptionUnion],
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ question_parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ question_entities: Optional[list[MessageEntity]] = None,
+ is_anonymous: Optional[bool] = None,
+ type: Optional[str] = None,
+ allows_multiple_answers: Optional[bool] = None,
+ correct_option_id: Optional[int] = None,
+ explanation: Optional[str] = None,
+ explanation_parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ explanation_entities: Optional[list[MessageEntity]] = None,
+ open_period: Optional[int] = None,
+ close_date: Optional[DateTimeUnion] = None,
+ is_closed: Optional[bool] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send a native poll. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendpoll
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param question: Poll question, 1-300 characters
+ :param options: A JSON-serialized list of 2-10 answer options
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param question_parse_mode: Mode for parsing entities in the question. See `formatting options `_ for more details. Currently, only custom emoji entities are allowed
+ :param question_entities: A JSON-serialized list of special entities that appear in the poll question. It can be specified instead of *question_parse_mode*
+ :param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
+ :param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
+ :param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
+ :param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
+ :param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
+ :param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options `_ for more details.
+ :param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
+ :param open_period: Amount of time in seconds the poll will be active after creation, 5-600. Can't be used together with *close_date*.
+ :param close_date: Point in time (Unix timestamp) when the poll will be automatically closed. Must be at least 5 and no more than 600 seconds in the future. Can't be used together with *open_period*.
+ :param is_closed: Pass :code:`True` if the poll needs to be immediately closed. This can be useful for poll preview.
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendPoll(
+ chat_id=chat_id,
+ question=question,
+ options=options,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ question_parse_mode=question_parse_mode,
+ question_entities=question_entities,
+ is_anonymous=is_anonymous,
+ type=type,
+ allows_multiple_answers=allows_multiple_answers,
+ correct_option_id=correct_option_id,
+ explanation=explanation,
+ explanation_parse_mode=explanation_parse_mode,
+ explanation_entities=explanation_entities,
+ open_period=open_period,
+ close_date=close_date,
+ is_closed=is_closed,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_sticker(
+ self,
+ chat_id: ChatIdUnion,
+ sticker: InputFileUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ emoji: Optional[str] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send static .WEBP, `animated `_ .TGS, or `video `_ .WEBM stickers. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendsticker
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param sticker: Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP sticker from the Internet, or upload a new .WEBP, .TGS, or .WEBM sticker using multipart/form-data. :ref:`More information on Sending Files » `. Video and animated stickers can't be sent via an HTTP URL.
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param emoji: Emoji associated with the sticker; only for just uploaded stickers
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendSticker(
+ chat_id=chat_id,
+ sticker=sticker,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ emoji=emoji,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_venue(
+ self,
+ chat_id: ChatIdUnion,
+ latitude: float,
+ longitude: float,
+ title: str,
+ address: str,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ foursquare_id: Optional[str] = None,
+ foursquare_type: Optional[str] = None,
+ google_place_id: Optional[str] = None,
+ google_place_type: Optional[str] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send information about a venue. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendvenue
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param latitude: Latitude of the venue
+ :param longitude: Longitude of the venue
+ :param title: Name of the venue
+ :param address: Address of the venue
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param foursquare_id: Foursquare identifier of the venue
+ :param foursquare_type: Foursquare type of the venue, if known. (For example, 'arts_entertainment/default', 'arts_entertainment/aquarium' or 'food/icecream'.)
+ :param google_place_id: Google Places identifier of the venue
+ :param google_place_type: Google Places type of the venue. (See `supported types `_.)
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendVenue(
+ chat_id=chat_id,
+ latitude=latitude,
+ longitude=longitude,
+ title=title,
+ address=address,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ foursquare_id=foursquare_id,
+ foursquare_type=foursquare_type,
+ google_place_id=google_place_id,
+ google_place_type=google_place_type,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_video(
+ self,
+ chat_id: ChatIdUnion,
+ video: InputFileUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ duration: Optional[int] = None,
+ width: Optional[int] = None,
+ height: Optional[int] = None,
+ thumbnail: Optional[InputFile] = None,
+ cover: Optional[InputFileUnion] = None,
+ start_timestamp: Optional[DateTimeUnion] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ caption_entities: Optional[list[MessageEntity]] = None,
+ show_caption_above_media: Optional[Union[bool, Default]] = Default(
+ "show_caption_above_media"
+ ),
+ has_spoiler: Optional[bool] = None,
+ supports_streaming: Optional[bool] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send video files, Telegram clients support MPEG4 videos (other formats may be sent as :class:`aiogram.types.document.Document`). On success, the sent :class:`aiogram.types.message.Message` is returned. Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future.
+
+ Source: https://core.telegram.org/bots/api#sendvideo
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param video: Video to send. Pass a file_id as String to send a video that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a video from the Internet, or upload a new video using multipart/form-data. :ref:`More information on Sending Files » `
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param duration: Duration of sent video in seconds
+ :param width: Video width
+ :param height: Video height
+ :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://' if the thumbnail was uploaded using multipart/form-data under . :ref:`More information on Sending Files » `
+ :param cover: Cover for the video in the message. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet, or pass 'attach://' to upload a new one using multipart/form-data under name. :ref:`More information on Sending Files » `
+ :param start_timestamp: Start timestamp for the video in the message
+ :param caption: Video caption (may also be used when resending videos by *file_id*), 0-1024 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the video caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param show_caption_above_media: Pass :code:`True`, if the caption must be shown above the message media
+ :param has_spoiler: Pass :code:`True` if the video needs to be covered with a spoiler animation
+ :param supports_streaming: Pass :code:`True` if the uploaded video is suitable for streaming
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future.
+ """
+
+ call = SendVideo(
+ chat_id=chat_id,
+ video=video,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ duration=duration,
+ width=width,
+ height=height,
+ thumbnail=thumbnail,
+ cover=cover,
+ start_timestamp=start_timestamp,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ show_caption_above_media=show_caption_above_media,
+ has_spoiler=has_spoiler,
+ supports_streaming=supports_streaming,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_video_note(
+ self,
+ chat_id: ChatIdUnion,
+ video_note: InputFileUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ duration: Optional[int] = None,
+ length: Optional[int] = None,
+ thumbnail: Optional[InputFile] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ As of `v.4.0 `_, Telegram clients support rounded square MPEG4 videos of up to 1 minute long. Use this method to send video messages. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendvideonote
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param video_note: Video note to send. Pass a file_id as String to send a video note that exists on the Telegram servers (recommended) or upload a new video using multipart/form-data. :ref:`More information on Sending Files » `. Sending video notes by a URL is currently unsupported
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param duration: Duration of sent video in seconds
+ :param length: Video width and height, i.e. diameter of the video message
+ :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://' if the thumbnail was uploaded using multipart/form-data under . :ref:`More information on Sending Files » `
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendVideoNote(
+ chat_id=chat_id,
+ video_note=video_note,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ duration=duration,
+ length=length,
+ thumbnail=thumbnail,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_voice(
+ self,
+ chat_id: ChatIdUnion,
+ voice: InputFileUnion,
+ business_connection_id: Optional[str] = None,
+ message_thread_id: Optional[int] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[Union[str, Default]] = Default("parse_mode"),
+ caption_entities: Optional[list[MessageEntity]] = None,
+ duration: Optional[int] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[Union[bool, Default]] = Default("protect_content"),
+ allow_paid_broadcast: Optional[bool] = None,
+ message_effect_id: Optional[str] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ allow_sending_without_reply: Optional[bool] = None,
+ reply_to_message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .OGG file encoded with OPUS, or in .MP3 format, or in .M4A format (other formats may be sent as :class:`aiogram.types.audio.Audio` or :class:`aiogram.types.document.Document`). On success, the sent :class:`aiogram.types.message.Message` is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
+
+ Source: https://core.telegram.org/bots/api#sendvoice
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param voice: Audio file to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. :ref:`More information on Sending Files » `
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param caption: Voice message caption, 0-1024 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the voice message caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param duration: Duration of the voice message in seconds
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param allow_sending_without_reply: Pass :code:`True` if the message should be sent even if the specified replied-to message is not found
+ :param reply_to_message_id: If the message is a reply, ID of the original message
+ :param request_timeout: Request timeout
+ :return: Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
+ """
+
+ call = SendVoice(
+ chat_id=chat_id,
+ voice=voice,
+ business_connection_id=business_connection_id,
+ message_thread_id=message_thread_id,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ duration=duration,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ message_effect_id=message_effect_id,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ allow_sending_without_reply=allow_sending_without_reply,
+ reply_to_message_id=reply_to_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_chat_administrator_custom_title(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ custom_title: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to set a custom title for an administrator in a supergroup promoted by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setchatadministratorcustomtitle
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param user_id: Unique identifier of the target user
+ :param custom_title: New custom title for the administrator; 0-16 characters, emoji are not allowed
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetChatAdministratorCustomTitle(
+ chat_id=chat_id,
+ user_id=user_id,
+ custom_title=custom_title,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_chat_description(
+ self,
+ chat_id: ChatIdUnion,
+ description: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the description of a group, a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setchatdescription
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param description: New chat description, 0-255 characters
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetChatDescription(
+ chat_id=chat_id,
+ description=description,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_chat_menu_button(
+ self,
+ chat_id: Optional[int] = None,
+ menu_button: Optional[MenuButtonUnion] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the bot's menu button in a private chat, or the default menu button. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setchatmenubutton
+
+ :param chat_id: Unique identifier for the target private chat. If not specified, default bot's menu button will be changed
+ :param menu_button: A JSON-serialized object for the bot's new menu button. Defaults to :class:`aiogram.types.menu_button_default.MenuButtonDefault`
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetChatMenuButton(
+ chat_id=chat_id,
+ menu_button=menu_button,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_chat_permissions(
+ self,
+ chat_id: ChatIdUnion,
+ permissions: ChatPermissions,
+ use_independent_chat_permissions: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to set default chat permissions for all members. The bot must be an administrator in the group or a supergroup for this to work and must have the *can_restrict_members* administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setchatpermissions
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param permissions: A JSON-serialized object for new default chat permissions
+ :param use_independent_chat_permissions: Pass :code:`True` if chat permissions are set independently. Otherwise, the *can_send_other_messages* and *can_add_web_page_previews* permissions will imply the *can_send_messages*, *can_send_audios*, *can_send_documents*, *can_send_photos*, *can_send_videos*, *can_send_video_notes*, and *can_send_voice_notes* permissions; the *can_send_polls* permission will imply the *can_send_messages* permission.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetChatPermissions(
+ chat_id=chat_id,
+ permissions=permissions,
+ use_independent_chat_permissions=use_independent_chat_permissions,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_chat_photo(
+ self,
+ chat_id: ChatIdUnion,
+ photo: InputFile,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to set a new profile photo for the chat. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setchatphoto
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param photo: New chat photo, uploaded using multipart/form-data
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetChatPhoto(
+ chat_id=chat_id,
+ photo=photo,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_chat_sticker_set(
+ self,
+ chat_id: ChatIdUnion,
+ sticker_set_name: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to set a new group sticker set for a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Use the field *can_set_sticker_set* optionally returned in :class:`aiogram.methods.get_chat.GetChat` requests to check if the bot can use this method. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setchatstickerset
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param sticker_set_name: Name of the sticker set to be set as the group sticker set
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetChatStickerSet(
+ chat_id=chat_id,
+ sticker_set_name=sticker_set_name,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_chat_title(
+ self,
+ chat_id: ChatIdUnion,
+ title: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the title of a chat. Titles can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setchattitle
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param title: New chat title, 1-128 characters
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetChatTitle(
+ chat_id=chat_id,
+ title=title,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_game_score(
+ self,
+ user_id: int,
+ score: int,
+ force: Optional[bool] = None,
+ disable_edit_message: Optional[bool] = None,
+ chat_id: Optional[int] = None,
+ message_id: Optional[int] = None,
+ inline_message_id: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Union[Message, bool]:
+ """
+ Use this method to set the score of the specified user in a game message. On success, if the message is not an inline message, the :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned. Returns an error, if the new score is not greater than the user's current score in the chat and *force* is :code:`False`.
+
+ Source: https://core.telegram.org/bots/api#setgamescore
+
+ :param user_id: User identifier
+ :param score: New score, must be non-negative
+ :param force: Pass :code:`True` if the high score is allowed to decrease. This can be useful when fixing mistakes or banning cheaters
+ :param disable_edit_message: Pass :code:`True` if the game message should not be automatically edited to include the current scoreboard
+ :param chat_id: Required if *inline_message_id* is not specified. Unique identifier for the target chat
+ :param message_id: Required if *inline_message_id* is not specified. Identifier of the sent message
+ :param inline_message_id: Required if *chat_id* and *message_id* are not specified. Identifier of the inline message
+ :param request_timeout: Request timeout
+ :return: Returns an error, if the new score is not greater than the user's current score in the chat and *force* is :code:`False`.
+ """
+
+ call = SetGameScore(
+ user_id=user_id,
+ score=score,
+ force=force,
+ disable_edit_message=disable_edit_message,
+ chat_id=chat_id,
+ message_id=message_id,
+ inline_message_id=inline_message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_my_commands(
+ self,
+ commands: list[BotCommand],
+ scope: Optional[BotCommandScopeUnion] = None,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the list of the bot's commands. See `this manual `_ for more details about bot commands. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setmycommands
+
+ :param commands: A JSON-serialized list of bot commands to be set as the list of the bot's commands. At most 100 commands can be specified.
+ :param scope: A JSON-serialized object, describing scope of users for which the commands are relevant. Defaults to :class:`aiogram.types.bot_command_scope_default.BotCommandScopeDefault`.
+ :param language_code: A two-letter ISO 639-1 language code. If empty, commands will be applied to all users from the given scope, for whose language there are no dedicated commands
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetMyCommands(
+ commands=commands,
+ scope=scope,
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_my_default_administrator_rights(
+ self,
+ rights: Optional[ChatAdministratorRights] = None,
+ for_channels: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the default administrator rights requested by the bot when it's added as an administrator to groups or channels. These rights will be suggested to users, but they are free to modify the list before adding the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setmydefaultadministratorrights
+
+ :param rights: A JSON-serialized object describing new default administrator rights. If not specified, the default administrator rights will be cleared.
+ :param for_channels: Pass :code:`True` to change the default administrator rights of the bot in channels. Otherwise, the default administrator rights of the bot for groups and supergroups will be changed.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetMyDefaultAdministratorRights(
+ rights=rights,
+ for_channels=for_channels,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_passport_data_errors(
+ self,
+ user_id: int,
+ errors: list[PassportElementErrorUnion],
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Informs a user that some of the Telegram Passport elements they provided contains errors. The user will not be able to re-submit their Passport to you until the errors are fixed (the contents of the field for which you returned the error must change). Returns :code:`True` on success.
+ Use this if the data submitted by the user doesn't satisfy the standards your service requires for any reason. For example, if a birthday date seems invalid, a submitted document is blurry, a scan shows evidence of tampering, etc. Supply some details in the error message to make sure the user knows how to correct the issues.
+
+ Source: https://core.telegram.org/bots/api#setpassportdataerrors
+
+ :param user_id: User identifier
+ :param errors: A JSON-serialized array describing the errors
+ :param request_timeout: Request timeout
+ :return: Supply some details in the error message to make sure the user knows how to correct the issues.
+ """
+
+ call = SetPassportDataErrors(
+ user_id=user_id,
+ errors=errors,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_sticker_position_in_set(
+ self,
+ sticker: str,
+ position: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to move a sticker in a set created by the bot to a specific position. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setstickerpositioninset
+
+ :param sticker: File identifier of the sticker
+ :param position: New sticker position in the set, zero-based
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetStickerPositionInSet(
+ sticker=sticker,
+ position=position,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_webhook(
+ self,
+ url: str,
+ certificate: Optional[InputFile] = None,
+ ip_address: Optional[str] = None,
+ max_connections: Optional[int] = None,
+ allowed_updates: Optional[list[str]] = None,
+ drop_pending_updates: Optional[bool] = None,
+ secret_token: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to specify a URL and receive incoming updates via an outgoing webhook. Whenever there is an update for the bot, we will send an HTTPS POST request to the specified URL, containing a JSON-serialized :class:`aiogram.types.update.Update`. In case of an unsuccessful request (a request with response `HTTP status code `_ different from :code:`2XY`), we will repeat the request and give up after a reasonable amount of attempts. Returns :code:`True` on success.
+ If you'd like to make sure that the webhook was set by you, you can specify secret data in the parameter *secret_token*. If specified, the request will contain a header 'X-Telegram-Bot-Api-Secret-Token' with the secret token as content.
+
+ **Notes**
+
+ **1.** You will not be able to receive updates using :class:`aiogram.methods.get_updates.GetUpdates` for as long as an outgoing webhook is set up.
+
+ **2.** To use a self-signed certificate, you need to upload your `public key certificate `_ using *certificate* parameter. Please upload as InputFile, sending a String will not work.
+
+ **3.** Ports currently supported *for webhooks*: **443, 80, 88, 8443**.
+ If you're having any trouble setting up webhooks, please check out this `amazing guide to webhooks `_.
+
+ Source: https://core.telegram.org/bots/api#setwebhook
+
+ :param url: HTTPS URL to send updates to. Use an empty string to remove webhook integration
+ :param certificate: Upload your public key certificate so that the root certificate in use can be checked. See our `self-signed guide `_ for details.
+ :param ip_address: The fixed IP address which will be used to send webhook requests instead of the IP address resolved through DNS
+ :param max_connections: The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to *40*. Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput.
+ :param allowed_updates: A JSON-serialized list of the update types you want your bot to receive. For example, specify :code:`["message", "edited_channel_post", "callback_query"]` to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all update types except *chat_member*, *message_reaction*, and *message_reaction_count* (default). If not specified, the previous setting will be used.
+ :param drop_pending_updates: Pass :code:`True` to drop all pending updates
+ :param secret_token: A secret token to be sent in a header 'X-Telegram-Bot-Api-Secret-Token' in every webhook request, 1-256 characters. Only characters :code:`A-Z`, :code:`a-z`, :code:`0-9`, :code:`_` and :code:`-` are allowed. The header is useful to ensure that the request comes from a webhook set by you.
+ :param request_timeout: Request timeout
+ :return: Please upload as InputFile, sending a String will not work.
+ """
+
+ call = SetWebhook(
+ url=url,
+ certificate=certificate,
+ ip_address=ip_address,
+ max_connections=max_connections,
+ allowed_updates=allowed_updates,
+ drop_pending_updates=drop_pending_updates,
+ secret_token=secret_token,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def stop_message_live_location(
+ self,
+ business_connection_id: Optional[str] = None,
+ chat_id: Optional[ChatIdUnion] = None,
+ message_id: Optional[int] = None,
+ inline_message_id: Optional[str] = None,
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Union[Message, bool]:
+ """
+ Use this method to stop updating a live location message before *live_period* expires. On success, if the message is not an inline message, the edited :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned.
+
+ Source: https://core.telegram.org/bots/api#stopmessagelivelocation
+
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message to be edited was sent
+ :param chat_id: Required if *inline_message_id* is not specified. Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Required if *inline_message_id* is not specified. Identifier of the message with live location to stop
+ :param inline_message_id: Required if *chat_id* and *message_id* are not specified. Identifier of the inline message
+ :param reply_markup: A JSON-serialized object for a new `inline keyboard `_.
+ :param request_timeout: Request timeout
+ :return: On success, if the message is not an inline message, the edited :class:`aiogram.types.message.Message` is returned, otherwise :code:`True` is returned.
+ """
+
+ call = StopMessageLiveLocation(
+ business_connection_id=business_connection_id,
+ chat_id=chat_id,
+ message_id=message_id,
+ inline_message_id=inline_message_id,
+ reply_markup=reply_markup,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def stop_poll(
+ self,
+ chat_id: ChatIdUnion,
+ message_id: int,
+ business_connection_id: Optional[str] = None,
+ reply_markup: Optional[InlineKeyboardMarkup] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Poll:
+ """
+ Use this method to stop a poll which was sent by the bot. On success, the stopped :class:`aiogram.types.poll.Poll` is returned.
+
+ Source: https://core.telegram.org/bots/api#stoppoll
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Identifier of the original message with the poll
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message to be edited was sent
+ :param reply_markup: A JSON-serialized object for a new message `inline keyboard `_.
+ :param request_timeout: Request timeout
+ :return: On success, the stopped :class:`aiogram.types.poll.Poll` is returned.
+ """
+
+ call = StopPoll(
+ chat_id=chat_id,
+ message_id=message_id,
+ business_connection_id=business_connection_id,
+ reply_markup=reply_markup,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def unban_chat_member(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ only_if_banned: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to unban a previously banned user in a supergroup or channel. The user will **not** return to the group or channel automatically, but will be able to join via link, etc. The bot must be an administrator for this to work. By default, this method guarantees that after the call the user is not a member of the chat, but will be able to join it. So if the user is a member of the chat they will also be **removed** from the chat. If you don't want this, use the parameter *only_if_banned*. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#unbanchatmember
+
+ :param chat_id: Unique identifier for the target group or username of the target supergroup or channel (in the format :code:`@channelusername`)
+ :param user_id: Unique identifier of the target user
+ :param only_if_banned: Do nothing if the user is not banned
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = UnbanChatMember(
+ chat_id=chat_id,
+ user_id=user_id,
+ only_if_banned=only_if_banned,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def unban_chat_sender_chat(
+ self,
+ chat_id: ChatIdUnion,
+ sender_chat_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to unban a previously banned channel chat in a supergroup or channel. The bot must be an administrator for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#unbanchatsenderchat
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param sender_chat_id: Unique identifier of the target sender chat
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = UnbanChatSenderChat(
+ chat_id=chat_id,
+ sender_chat_id=sender_chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def unpin_all_chat_messages(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to clear the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#unpinallchatmessages
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = UnpinAllChatMessages(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def unpin_all_forum_topic_messages(
+ self,
+ chat_id: ChatIdUnion,
+ message_thread_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to clear the list of pinned messages in a forum topic. The bot must be an administrator in the chat for this to work and must have the *can_pin_messages* administrator right in the supergroup. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#unpinallforumtopicmessages
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param message_thread_id: Unique identifier for the target message thread of the forum topic
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = UnpinAllForumTopicMessages(
+ chat_id=chat_id,
+ message_thread_id=message_thread_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def unpin_chat_message(
+ self,
+ chat_id: ChatIdUnion,
+ business_connection_id: Optional[str] = None,
+ message_id: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to remove a message from the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#unpinchatmessage
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be unpinned
+ :param message_id: Identifier of the message to unpin. Required if *business_connection_id* is specified. If not specified, the most recent pinned message (by sending date) will be unpinned.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = UnpinChatMessage(
+ chat_id=chat_id,
+ business_connection_id=business_connection_id,
+ message_id=message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def upload_sticker_file(
+ self,
+ user_id: int,
+ sticker: InputFile,
+ sticker_format: str,
+ request_timeout: Optional[int] = None,
+ ) -> File:
+ """
+ Use this method to upload a file with a sticker for later use in the :class:`aiogram.methods.create_new_sticker_set.CreateNewStickerSet`, :class:`aiogram.methods.add_sticker_to_set.AddStickerToSet`, or :class:`aiogram.methods.replace_sticker_in_set.ReplaceStickerInSet` methods (the file can be used multiple times). Returns the uploaded :class:`aiogram.types.file.File` on success.
+
+ Source: https://core.telegram.org/bots/api#uploadstickerfile
+
+ :param user_id: User identifier of sticker file owner
+ :param sticker: A file with the sticker in .WEBP, .PNG, .TGS, or .WEBM format. See `https://core.telegram.org/stickers `_`https://core.telegram.org/stickers `_ for technical requirements. :ref:`More information on Sending Files » `
+ :param sticker_format: Format of the sticker, must be one of 'static', 'animated', 'video'
+ :param request_timeout: Request timeout
+ :return: Returns the uploaded :class:`aiogram.types.file.File` on success.
+ """
+
+ call = UploadStickerFile(
+ user_id=user_id,
+ sticker=sticker,
+ sticker_format=sticker_format,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def close_general_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to close an open 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#closegeneralforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = CloseGeneralForumTopic(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_general_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ name: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#editgeneralforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param name: New topic name, 1-128 characters
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = EditGeneralForumTopic(
+ chat_id=chat_id,
+ name=name,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def hide_general_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights. The topic will be automatically closed if it was open. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#hidegeneralforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = HideGeneralForumTopic(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def reopen_general_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights. The topic will be automatically unhidden if it was hidden. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#reopengeneralforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = ReopenGeneralForumTopic(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def unhide_general_forum_topic(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#unhidegeneralforumtopic
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = UnhideGeneralForumTopic(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_sticker_set(
+ self,
+ name: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to delete a sticker set that was created by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletestickerset
+
+ :param name: Sticker set name
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteStickerSet(
+ name=name,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_my_description(
+ self,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> BotDescription:
+ """
+ Use this method to get the current bot description for the given user language. Returns :class:`aiogram.types.bot_description.BotDescription` on success.
+
+ Source: https://core.telegram.org/bots/api#getmydescription
+
+ :param language_code: A two-letter ISO 639-1 language code or an empty string
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.bot_description.BotDescription` on success.
+ """
+
+ call = GetMyDescription(
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_my_short_description(
+ self,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> BotShortDescription:
+ """
+ Use this method to get the current bot short description for the given user language. Returns :class:`aiogram.types.bot_short_description.BotShortDescription` on success.
+
+ Source: https://core.telegram.org/bots/api#getmyshortdescription
+
+ :param language_code: A two-letter ISO 639-1 language code or an empty string
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.bot_short_description.BotShortDescription` on success.
+ """
+
+ call = GetMyShortDescription(
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_custom_emoji_sticker_set_thumbnail(
+ self,
+ name: str,
+ custom_emoji_id: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to set the thumbnail of a custom emoji sticker set. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setcustomemojistickersetthumbnail
+
+ :param name: Sticker set name
+ :param custom_emoji_id: Custom emoji identifier of a sticker from the sticker set; pass an empty string to drop the thumbnail and use the first sticker as the thumbnail.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetCustomEmojiStickerSetThumbnail(
+ name=name,
+ custom_emoji_id=custom_emoji_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_my_description(
+ self,
+ description: Optional[str] = None,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setmydescription
+
+ :param description: New bot description; 0-512 characters. Pass an empty string to remove the dedicated description for the given language.
+ :param language_code: A two-letter ISO 639-1 language code. If empty, the description will be applied to all users for whose language there is no dedicated description.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetMyDescription(
+ description=description,
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_my_short_description(
+ self,
+ short_description: Optional[str] = None,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setmyshortdescription
+
+ :param short_description: New short description for the bot; 0-120 characters. Pass an empty string to remove the dedicated short description for the given language.
+ :param language_code: A two-letter ISO 639-1 language code. If empty, the short description will be applied to all users for whose language there is no dedicated short description.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetMyShortDescription(
+ short_description=short_description,
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_sticker_emoji_list(
+ self,
+ sticker: str,
+ emoji_list: list[str],
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the list of emoji assigned to a regular or custom emoji sticker. The sticker must belong to a sticker set created by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setstickeremojilist
+
+ :param sticker: File identifier of the sticker
+ :param emoji_list: A JSON-serialized list of 1-20 emoji associated with the sticker
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetStickerEmojiList(
+ sticker=sticker,
+ emoji_list=emoji_list,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_sticker_keywords(
+ self,
+ sticker: str,
+ keywords: Optional[list[str]] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change search keywords assigned to a regular or custom emoji sticker. The sticker must belong to a sticker set created by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setstickerkeywords
+
+ :param sticker: File identifier of the sticker
+ :param keywords: A JSON-serialized list of 0-20 search keywords for the sticker with total length of up to 64 characters
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetStickerKeywords(
+ sticker=sticker,
+ keywords=keywords,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_sticker_mask_position(
+ self,
+ sticker: str,
+ mask_position: Optional[MaskPosition] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the `mask position `_ of a mask sticker. The sticker must belong to a sticker set that was created by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setstickermaskposition
+
+ :param sticker: File identifier of the sticker
+ :param mask_position: A JSON-serialized object with the position where the mask should be placed on faces. Omit the parameter to remove the mask position.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetStickerMaskPosition(
+ sticker=sticker,
+ mask_position=mask_position,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_sticker_set_thumbnail(
+ self,
+ name: str,
+ user_id: int,
+ format: str,
+ thumbnail: Optional[InputFileUnion] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to set the thumbnail of a regular or mask sticker set. The format of the thumbnail file must match the format of the stickers in the set. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setstickersetthumbnail
+
+ :param name: Sticker set name
+ :param user_id: User identifier of the sticker set owner
+ :param format: Format of the thumbnail, must be one of 'static' for a **.WEBP** or **.PNG** image, 'animated' for a **.TGS** animation, or 'video' for a **.WEBM** video
+ :param thumbnail: A **.WEBP** or **.PNG** image with the thumbnail, must be up to 128 kilobytes in size and have a width and height of exactly 100px, or a **.TGS** animation with a thumbnail up to 32 kilobytes in size (see `https://core.telegram.org/stickers#animation-requirements `_`https://core.telegram.org/stickers#animation-requirements `_ for animated sticker technical requirements), or a **.WEBM** video with the thumbnail up to 32 kilobytes in size; see `https://core.telegram.org/stickers#video-requirements `_`https://core.telegram.org/stickers#video-requirements `_ for video sticker technical requirements. Pass a *file_id* as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. :ref:`More information on Sending Files » `. Animated and video sticker set thumbnails can't be uploaded via HTTP URL. If omitted, then the thumbnail is dropped and the first sticker is used as the thumbnail.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetStickerSetThumbnail(
+ name=name,
+ user_id=user_id,
+ format=format,
+ thumbnail=thumbnail,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_sticker_set_title(
+ self,
+ name: str,
+ title: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to set the title of a created sticker set. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setstickersettitle
+
+ :param name: Sticker set name
+ :param title: Sticker set title, 1-64 characters
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetStickerSetTitle(
+ name=name,
+ title=title,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_my_name(
+ self,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> BotName:
+ """
+ Use this method to get the current bot name for the given user language. Returns :class:`aiogram.types.bot_name.BotName` on success.
+
+ Source: https://core.telegram.org/bots/api#getmyname
+
+ :param language_code: A two-letter ISO 639-1 language code or an empty string
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.bot_name.BotName` on success.
+ """
+
+ call = GetMyName(
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_my_name(
+ self,
+ name: Optional[str] = None,
+ language_code: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the bot's name. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setmyname
+
+ :param name: New bot name; 0-64 characters. Pass an empty string to remove the dedicated name for the given language.
+ :param language_code: A two-letter ISO 639-1 language code. If empty, the name will be shown to all users for whose language there is no dedicated name.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetMyName(
+ name=name,
+ language_code=language_code,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def unpin_all_general_forum_topic_messages(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator in the chat for this to work and must have the *can_pin_messages* administrator right in the supergroup. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#unpinallgeneralforumtopicmessages
+
+ :param chat_id: Unique identifier for the target chat or username of the target supergroup (in the format :code:`@supergroupusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = UnpinAllGeneralForumTopicMessages(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def copy_messages(
+ self,
+ chat_id: ChatIdUnion,
+ from_chat_id: ChatIdUnion,
+ message_ids: list[int],
+ message_thread_id: Optional[int] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[bool] = None,
+ remove_caption: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> list[MessageId]:
+ """
+ Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz :class:`aiogram.methods.poll.Poll` can be copied only if the value of the field *correct_option_id* is known to the bot. The method is analogous to the method :class:`aiogram.methods.forward_messages.ForwardMessages`, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array of :class:`aiogram.types.message_id.MessageId` of the sent messages is returned.
+
+ Source: https://core.telegram.org/bots/api#copymessages
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param from_chat_id: Unique identifier for the chat where the original messages were sent (or channel username in the format :code:`@channelusername`)
+ :param message_ids: A JSON-serialized list of 1-100 identifiers of messages in the chat *from_chat_id* to copy. The identifiers must be specified in a strictly increasing order.
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param disable_notification: Sends the messages `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent messages from forwarding and saving
+ :param remove_caption: Pass :code:`True` to copy the messages without their captions
+ :param request_timeout: Request timeout
+ :return: On success, an array of :class:`aiogram.types.message_id.MessageId` of the sent messages is returned.
+ """
+
+ call = CopyMessages(
+ chat_id=chat_id,
+ from_chat_id=from_chat_id,
+ message_ids=message_ids,
+ message_thread_id=message_thread_id,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ remove_caption=remove_caption,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_messages(
+ self,
+ chat_id: ChatIdUnion,
+ message_ids: list[int],
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to delete multiple messages simultaneously. If some of the specified messages can't be found, they are skipped. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletemessages
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_ids: A JSON-serialized list of 1-100 identifiers of messages to delete. See :class:`aiogram.methods.delete_message.DeleteMessage` for limitations on which messages can be deleted
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteMessages(
+ chat_id=chat_id,
+ message_ids=message_ids,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def forward_messages(
+ self,
+ chat_id: ChatIdUnion,
+ from_chat_id: ChatIdUnion,
+ message_ids: list[int],
+ message_thread_id: Optional[int] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> list[MessageId]:
+ """
+ Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. On success, an array of :class:`aiogram.types.message_id.MessageId` of the sent messages is returned.
+
+ Source: https://core.telegram.org/bots/api#forwardmessages
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param from_chat_id: Unique identifier for the chat where the original messages were sent (or channel username in the format :code:`@channelusername`)
+ :param message_ids: A JSON-serialized list of 1-100 identifiers of messages in the chat *from_chat_id* to forward. The identifiers must be specified in a strictly increasing order.
+ :param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
+ :param disable_notification: Sends the messages `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the forwarded messages from forwarding and saving
+ :param request_timeout: Request timeout
+ :return: On success, an array of :class:`aiogram.types.message_id.MessageId` of the sent messages is returned.
+ """
+
+ call = ForwardMessages(
+ chat_id=chat_id,
+ from_chat_id=from_chat_id,
+ message_ids=message_ids,
+ message_thread_id=message_thread_id,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_user_chat_boosts(
+ self,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> UserChatBoosts:
+ """
+ Use this method to get the list of boosts added to a chat by a user. Requires administrator rights in the chat. Returns a :class:`aiogram.types.user_chat_boosts.UserChatBoosts` object.
+
+ Source: https://core.telegram.org/bots/api#getuserchatboosts
+
+ :param chat_id: Unique identifier for the chat or username of the channel (in the format :code:`@channelusername`)
+ :param user_id: Unique identifier of the target user
+ :param request_timeout: Request timeout
+ :return: Returns a :class:`aiogram.types.user_chat_boosts.UserChatBoosts` object.
+ """
+
+ call = GetUserChatBoosts(
+ chat_id=chat_id,
+ user_id=user_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_message_reaction(
+ self,
+ chat_id: ChatIdUnion,
+ message_id: int,
+ reaction: Optional[list[ReactionTypeUnion]] = None,
+ is_big: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to change the chosen reactions on a message. Service messages of some types can't be reacted to. Automatically forwarded messages from a channel to its discussion group have the same available reactions as messages in the channel. Bots can't use paid reactions. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setmessagereaction
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param message_id: Identifier of the target message. If the message belongs to a media group, the reaction is set to the first non-deleted message in the group instead.
+ :param reaction: A JSON-serialized list of reaction types to set on the message. Currently, as non-premium users, bots can set up to one reaction per message. A custom emoji reaction can be used if it is either already present on the message or explicitly allowed by chat administrators. Paid reactions can't be used by bots.
+ :param is_big: Pass :code:`True` to set the reaction with a big animation
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetMessageReaction(
+ chat_id=chat_id,
+ message_id=message_id,
+ reaction=reaction,
+ is_big=is_big,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_business_connection(
+ self,
+ business_connection_id: str,
+ request_timeout: Optional[int] = None,
+ ) -> BusinessConnection:
+ """
+ Use this method to get information about the connection of the bot with a business account. Returns a :class:`aiogram.types.business_connection.BusinessConnection` object on success.
+
+ Source: https://core.telegram.org/bots/api#getbusinessconnection
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param request_timeout: Request timeout
+ :return: Returns a :class:`aiogram.types.business_connection.BusinessConnection` object on success.
+ """
+
+ call = GetBusinessConnection(
+ business_connection_id=business_connection_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def replace_sticker_in_set(
+ self,
+ user_id: int,
+ name: str,
+ old_sticker: str,
+ sticker: InputSticker,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Use this method to replace an existing sticker in a sticker set with a new one. The method is equivalent to calling :class:`aiogram.methods.delete_sticker_from_set.DeleteStickerFromSet`, then :class:`aiogram.methods.add_sticker_to_set.AddStickerToSet`, then :class:`aiogram.methods.set_sticker_position_in_set.SetStickerPositionInSet`. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#replacestickerinset
+
+ :param user_id: User identifier of the sticker set owner
+ :param name: Sticker set name
+ :param old_sticker: File identifier of the replaced sticker
+ :param sticker: A JSON-serialized object with information about the added sticker. If exactly the same sticker had already been added to the set, then the set remains unchanged.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = ReplaceStickerInSet(
+ user_id=user_id,
+ name=name,
+ old_sticker=old_sticker,
+ sticker=sticker,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def refund_star_payment(
+ self,
+ user_id: int,
+ telegram_payment_charge_id: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Refunds a successful payment in `Telegram Stars `_. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#refundstarpayment
+
+ :param user_id: Identifier of the user whose payment will be refunded
+ :param telegram_payment_charge_id: Telegram payment identifier
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = RefundStarPayment(
+ user_id=user_id,
+ telegram_payment_charge_id=telegram_payment_charge_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_star_transactions(
+ self,
+ offset: Optional[int] = None,
+ limit: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> StarTransactions:
+ """
+ Returns the bot's Telegram Star transactions in chronological order. On success, returns a :class:`aiogram.types.star_transactions.StarTransactions` object.
+
+ Source: https://core.telegram.org/bots/api#getstartransactions
+
+ :param offset: Number of transactions to skip in the response
+ :param limit: The maximum number of transactions to be retrieved. Values between 1-100 are accepted. Defaults to 100.
+ :param request_timeout: Request timeout
+ :return: On success, returns a :class:`aiogram.types.star_transactions.StarTransactions` object.
+ """
+
+ call = GetStarTransactions(
+ offset=offset,
+ limit=limit,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_paid_media(
+ self,
+ chat_id: ChatIdUnion,
+ star_count: int,
+ media: list[InputPaidMediaUnion],
+ business_connection_id: Optional[str] = None,
+ payload: Optional[str] = None,
+ caption: Optional[str] = None,
+ parse_mode: Optional[str] = None,
+ caption_entities: Optional[list[MessageEntity]] = None,
+ show_caption_above_media: Optional[bool] = None,
+ disable_notification: Optional[bool] = None,
+ protect_content: Optional[bool] = None,
+ allow_paid_broadcast: Optional[bool] = None,
+ reply_parameters: Optional[ReplyParameters] = None,
+ reply_markup: Optional[ReplyMarkupUnion] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Message:
+ """
+ Use this method to send paid media. On success, the sent :class:`aiogram.types.message.Message` is returned.
+
+ Source: https://core.telegram.org/bots/api#sendpaidmedia
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`). If the chat is a channel, all Telegram Star proceeds from this media will be credited to the chat's balance. Otherwise, they will be credited to the bot's balance.
+ :param star_count: The number of Telegram Stars that must be paid to buy access to the media; 1-10000
+ :param media: A JSON-serialized array describing the media to be sent; up to 10 items
+ :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent
+ :param payload: Bot-defined paid media payload, 0-128 bytes. This will not be displayed to the user, use it for your internal processes.
+ :param caption: Media caption, 0-1024 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the media caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param show_caption_above_media: Pass :code:`True`, if the caption must be shown above the message media
+ :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound.
+ :param protect_content: Protects the contents of the sent message from forwarding and saving
+ :param allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits `_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
+ :param reply_parameters: Description of the message to reply to
+ :param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard `_, `custom reply keyboard `_, instructions to remove a reply keyboard or to force a reply from the user
+ :param request_timeout: Request timeout
+ :return: On success, the sent :class:`aiogram.types.message.Message` is returned.
+ """
+
+ call = SendPaidMedia(
+ chat_id=chat_id,
+ star_count=star_count,
+ media=media,
+ business_connection_id=business_connection_id,
+ payload=payload,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ show_caption_above_media=show_caption_above_media,
+ disable_notification=disable_notification,
+ protect_content=protect_content,
+ allow_paid_broadcast=allow_paid_broadcast,
+ reply_parameters=reply_parameters,
+ reply_markup=reply_markup,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def create_chat_subscription_invite_link(
+ self,
+ chat_id: ChatIdUnion,
+ subscription_period: DateTimeUnion,
+ subscription_price: int,
+ name: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> ChatInviteLink:
+ """
+ Use this method to create a `subscription invite link `_ for a channel chat. The bot must have the *can_invite_users* administrator rights. The link can be edited using the method :class:`aiogram.methods.edit_chat_subscription_invite_link.EditChatSubscriptionInviteLink` or revoked using the method :class:`aiogram.methods.revoke_chat_invite_link.RevokeChatInviteLink`. Returns the new invite link as a :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+
+ Source: https://core.telegram.org/bots/api#createchatsubscriptioninvitelink
+
+ :param chat_id: Unique identifier for the target channel chat or username of the target channel (in the format :code:`@channelusername`)
+ :param subscription_period: The number of seconds the subscription will be active for before the next payment. Currently, it must always be 2592000 (30 days).
+ :param subscription_price: The amount of Telegram Stars a user must pay initially and after each subsequent subscription period to be a member of the chat; 1-10000
+ :param name: Invite link name; 0-32 characters
+ :param request_timeout: Request timeout
+ :return: Returns the new invite link as a :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+ """
+
+ call = CreateChatSubscriptionInviteLink(
+ chat_id=chat_id,
+ subscription_period=subscription_period,
+ subscription_price=subscription_price,
+ name=name,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_chat_subscription_invite_link(
+ self,
+ chat_id: ChatIdUnion,
+ invite_link: str,
+ name: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> ChatInviteLink:
+ """
+ Use this method to edit a subscription invite link created by the bot. The bot must have the *can_invite_users* administrator rights. Returns the edited invite link as a :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+
+ Source: https://core.telegram.org/bots/api#editchatsubscriptioninvitelink
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param invite_link: The invite link to edit
+ :param name: Invite link name; 0-32 characters
+ :param request_timeout: Request timeout
+ :return: Returns the edited invite link as a :class:`aiogram.types.chat_invite_link.ChatInviteLink` object.
+ """
+
+ call = EditChatSubscriptionInviteLink(
+ chat_id=chat_id,
+ invite_link=invite_link,
+ name=name,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_user_star_subscription(
+ self,
+ user_id: int,
+ telegram_payment_charge_id: str,
+ is_canceled: bool,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Allows the bot to cancel or re-enable extension of a subscription paid in Telegram Stars. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#edituserstarsubscription
+
+ :param user_id: Identifier of the user whose subscription will be edited
+ :param telegram_payment_charge_id: Telegram payment identifier for the subscription
+ :param is_canceled: Pass :code:`True` to cancel extension of the user subscription; the subscription must be active up to the end of the current subscription period. Pass :code:`False` to allow the user to re-enable a subscription that was previously canceled by the bot.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = EditUserStarSubscription(
+ user_id=user_id,
+ telegram_payment_charge_id=telegram_payment_charge_id,
+ is_canceled=is_canceled,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_available_gifts(
+ self,
+ request_timeout: Optional[int] = None,
+ ) -> Gifts:
+ """
+ Returns the list of gifts that can be sent by the bot to users and channel chats. Requires no parameters. Returns a :class:`aiogram.types.gifts.Gifts` object.
+
+ Source: https://core.telegram.org/bots/api#getavailablegifts
+
+ :param request_timeout: Request timeout
+ :return: Returns a :class:`aiogram.types.gifts.Gifts` object.
+ """
+
+ call = GetAvailableGifts()
+ return await self(call, request_timeout=request_timeout)
+
+ async def save_prepared_inline_message(
+ self,
+ user_id: int,
+ result: InlineQueryResultUnion,
+ allow_user_chats: Optional[bool] = None,
+ allow_bot_chats: Optional[bool] = None,
+ allow_group_chats: Optional[bool] = None,
+ allow_channel_chats: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> PreparedInlineMessage:
+ """
+ Stores a message that can be sent by a user of a Mini App. Returns a :class:`aiogram.types.prepared_inline_message.PreparedInlineMessage` object.
+
+ Source: https://core.telegram.org/bots/api#savepreparedinlinemessage
+
+ :param user_id: Unique identifier of the target user that can use the prepared message
+ :param result: A JSON-serialized object describing the message to be sent
+ :param allow_user_chats: Pass :code:`True` if the message can be sent to private chats with users
+ :param allow_bot_chats: Pass :code:`True` if the message can be sent to private chats with bots
+ :param allow_group_chats: Pass :code:`True` if the message can be sent to group and supergroup chats
+ :param allow_channel_chats: Pass :code:`True` if the message can be sent to channel chats
+ :param request_timeout: Request timeout
+ :return: Returns a :class:`aiogram.types.prepared_inline_message.PreparedInlineMessage` object.
+ """
+
+ call = SavePreparedInlineMessage(
+ user_id=user_id,
+ result=result,
+ allow_user_chats=allow_user_chats,
+ allow_bot_chats=allow_bot_chats,
+ allow_group_chats=allow_group_chats,
+ allow_channel_chats=allow_channel_chats,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def send_gift(
+ self,
+ gift_id: str,
+ user_id: Optional[int] = None,
+ chat_id: Optional[ChatIdUnion] = None,
+ pay_for_upgrade: Optional[bool] = None,
+ text: Optional[str] = None,
+ text_parse_mode: Optional[str] = None,
+ text_entities: Optional[list[MessageEntity]] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Sends a gift to the given user or channel chat. The gift can't be converted to Telegram Stars by the receiver. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#sendgift
+
+ :param gift_id: Identifier of the gift
+ :param user_id: Required if *chat_id* is not specified. Unique identifier of the target user who will receive the gift.
+ :param chat_id: Required if *user_id* is not specified. Unique identifier for the chat or username of the channel (in the format :code:`@channelusername`) that will receive the gift.
+ :param pay_for_upgrade: Pass :code:`True` to pay for the gift upgrade from the bot's balance, thereby making the upgrade free for the receiver
+ :param text: Text that will be shown along with the gift; 0-128 characters
+ :param text_parse_mode: Mode for parsing entities in the text. See `formatting options `_ for more details. Entities other than 'bold', 'italic', 'underline', 'strikethrough', 'spoiler', and 'custom_emoji' are ignored.
+ :param text_entities: A JSON-serialized list of special entities that appear in the gift text. It can be specified instead of *text_parse_mode*. Entities other than 'bold', 'italic', 'underline', 'strikethrough', 'spoiler', and 'custom_emoji' are ignored.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SendGift(
+ gift_id=gift_id,
+ user_id=user_id,
+ chat_id=chat_id,
+ pay_for_upgrade=pay_for_upgrade,
+ text=text,
+ text_parse_mode=text_parse_mode,
+ text_entities=text_entities,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_user_emoji_status(
+ self,
+ user_id: int,
+ emoji_status_custom_emoji_id: Optional[str] = None,
+ emoji_status_expiration_date: Optional[DateTimeUnion] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Changes the emoji status for a given user that previously allowed the bot to manage their emoji status via the Mini App method `requestEmojiStatusAccess `_. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setuseremojistatus
+
+ :param user_id: Unique identifier of the target user
+ :param emoji_status_custom_emoji_id: Custom emoji identifier of the emoji status to set. Pass an empty string to remove the status.
+ :param emoji_status_expiration_date: Expiration date of the emoji status, if any
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetUserEmojiStatus(
+ user_id=user_id,
+ emoji_status_custom_emoji_id=emoji_status_custom_emoji_id,
+ emoji_status_expiration_date=emoji_status_expiration_date,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def remove_chat_verification(
+ self,
+ chat_id: ChatIdUnion,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Removes verification from a chat that is currently verified `on behalf of the organization `_ represented by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#removechatverification
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = RemoveChatVerification(
+ chat_id=chat_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def remove_user_verification(
+ self,
+ user_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Removes verification from a user who is currently verified `on behalf of the organization `_ represented by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#removeuserverification
+
+ :param user_id: Unique identifier of the target user
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = RemoveUserVerification(
+ user_id=user_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def verify_chat(
+ self,
+ chat_id: ChatIdUnion,
+ custom_description: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Verifies a chat `on behalf of the organization `_ which is represented by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#verifychat
+
+ :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
+ :param custom_description: Custom description for the verification; 0-70 characters. Must be empty if the organization isn't allowed to provide a custom verification description.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = VerifyChat(
+ chat_id=chat_id,
+ custom_description=custom_description,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def verify_user(
+ self,
+ user_id: int,
+ custom_description: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Verifies a user `on behalf of the organization `_ which is represented by the bot. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#verifyuser
+
+ :param user_id: Unique identifier of the target user
+ :param custom_description: Custom description for the verification; 0-70 characters. Must be empty if the organization isn't allowed to provide a custom verification description.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = VerifyUser(
+ user_id=user_id,
+ custom_description=custom_description,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def convert_gift_to_stars(
+ self,
+ business_connection_id: str,
+ owned_gift_id: str,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Converts a given regular gift to Telegram Stars. Requires the *can_convert_gifts_to_stars* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#convertgifttostars
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param owned_gift_id: Unique identifier of the regular gift that should be converted to Telegram Stars
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = ConvertGiftToStars(
+ business_connection_id=business_connection_id,
+ owned_gift_id=owned_gift_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_business_messages(
+ self,
+ business_connection_id: str,
+ message_ids: list[int],
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Delete messages on behalf of a business account. Requires the *can_delete_outgoing_messages* business bot right to delete messages sent by the bot itself, or the *can_delete_all_messages* business bot right to delete any message. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletebusinessmessages
+
+ :param business_connection_id: Unique identifier of the business connection on behalf of which to delete the messages
+ :param message_ids: A JSON-serialized list of 1-100 identifiers of messages to delete. All messages must be from the same chat. See :class:`aiogram.methods.delete_message.DeleteMessage` for limitations on which messages can be deleted
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteBusinessMessages(
+ business_connection_id=business_connection_id,
+ message_ids=message_ids,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def delete_story(
+ self,
+ business_connection_id: str,
+ story_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Deletes a story previously posted by the bot on behalf of a managed business account. Requires the *can_manage_stories* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#deletestory
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param story_id: Unique identifier of the story to delete
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = DeleteStory(
+ business_connection_id=business_connection_id,
+ story_id=story_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def edit_story(
+ self,
+ business_connection_id: str,
+ story_id: int,
+ content: InputStoryContentUnion,
+ caption: Optional[str] = None,
+ parse_mode: Optional[str] = None,
+ caption_entities: Optional[list[MessageEntity]] = None,
+ areas: Optional[list[StoryArea]] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Story:
+ """
+ Edits a story previously posted by the bot on behalf of a managed business account. Requires the *can_manage_stories* business bot right. Returns :class:`aiogram.types.story.Story` on success.
+
+ Source: https://core.telegram.org/bots/api#editstory
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param story_id: Unique identifier of the story to edit
+ :param content: Content of the story
+ :param caption: Caption of the story, 0-2048 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the story caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param areas: A JSON-serialized list of clickable areas to be shown on the story
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.story.Story` on success.
+ """
+
+ call = EditStory(
+ business_connection_id=business_connection_id,
+ story_id=story_id,
+ content=content,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ areas=areas,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_business_account_gifts(
+ self,
+ business_connection_id: str,
+ exclude_unsaved: Optional[bool] = None,
+ exclude_saved: Optional[bool] = None,
+ exclude_unlimited: Optional[bool] = None,
+ exclude_limited: Optional[bool] = None,
+ exclude_unique: Optional[bool] = None,
+ sort_by_price: Optional[bool] = None,
+ offset: Optional[str] = None,
+ limit: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> OwnedGifts:
+ """
+ Returns the gifts received and owned by a managed business account. Requires the *can_view_gifts_and_stars* business bot right. Returns :class:`aiogram.types.owned_gifts.OwnedGifts` on success.
+
+ Source: https://core.telegram.org/bots/api#getbusinessaccountgifts
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param exclude_unsaved: Pass True to exclude gifts that aren't saved to the account's profile page
+ :param exclude_saved: Pass True to exclude gifts that are saved to the account's profile page
+ :param exclude_unlimited: Pass True to exclude gifts that can be purchased an unlimited number of times
+ :param exclude_limited: Pass True to exclude gifts that can be purchased a limited number of times
+ :param exclude_unique: Pass True to exclude unique gifts
+ :param sort_by_price: Pass True to sort results by gift price instead of send date. Sorting is applied before pagination.
+ :param offset: Offset of the first entry to return as received from the previous request; use empty string to get the first chunk of results
+ :param limit: The maximum number of gifts to be returned; 1-100. Defaults to 100
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.owned_gifts.OwnedGifts` on success.
+ """
+
+ call = GetBusinessAccountGifts(
+ business_connection_id=business_connection_id,
+ exclude_unsaved=exclude_unsaved,
+ exclude_saved=exclude_saved,
+ exclude_unlimited=exclude_unlimited,
+ exclude_limited=exclude_limited,
+ exclude_unique=exclude_unique,
+ sort_by_price=sort_by_price,
+ offset=offset,
+ limit=limit,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def get_business_account_star_balance(
+ self,
+ business_connection_id: str,
+ request_timeout: Optional[int] = None,
+ ) -> StarAmount:
+ """
+ Returns the amount of Telegram Stars owned by a managed business account. Requires the *can_view_gifts_and_stars* business bot right. Returns :class:`aiogram.types.star_amount.StarAmount` on success.
+
+ Source: https://core.telegram.org/bots/api#getbusinessaccountstarbalance
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.star_amount.StarAmount` on success.
+ """
+
+ call = GetBusinessAccountStarBalance(
+ business_connection_id=business_connection_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def gift_premium_subscription(
+ self,
+ user_id: int,
+ month_count: int,
+ star_count: int,
+ text: Optional[str] = None,
+ text_parse_mode: Optional[str] = None,
+ text_entities: Optional[list[MessageEntity]] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Gifts a Telegram Premium subscription to the given user. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#giftpremiumsubscription
+
+ :param user_id: Unique identifier of the target user who will receive a Telegram Premium subscription
+ :param month_count: Number of months the Telegram Premium subscription will be active for the user; must be one of 3, 6, or 12
+ :param star_count: Number of Telegram Stars to pay for the Telegram Premium subscription; must be 1000 for 3 months, 1500 for 6 months, and 2500 for 12 months
+ :param text: Text that will be shown along with the service message about the subscription; 0-128 characters
+ :param text_parse_mode: Mode for parsing entities in the text. See `formatting options `_ for more details. Entities other than 'bold', 'italic', 'underline', 'strikethrough', 'spoiler', and 'custom_emoji' are ignored.
+ :param text_entities: A JSON-serialized list of special entities that appear in the gift text. It can be specified instead of *text_parse_mode*. Entities other than 'bold', 'italic', 'underline', 'strikethrough', 'spoiler', and 'custom_emoji' are ignored.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = GiftPremiumSubscription(
+ user_id=user_id,
+ month_count=month_count,
+ star_count=star_count,
+ text=text,
+ text_parse_mode=text_parse_mode,
+ text_entities=text_entities,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def post_story(
+ self,
+ business_connection_id: str,
+ content: InputStoryContentUnion,
+ active_period: int,
+ caption: Optional[str] = None,
+ parse_mode: Optional[str] = None,
+ caption_entities: Optional[list[MessageEntity]] = None,
+ areas: Optional[list[StoryArea]] = None,
+ post_to_chat_page: Optional[bool] = None,
+ protect_content: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> Story:
+ """
+ Posts a story on behalf of a managed business account. Requires the *can_manage_stories* business bot right. Returns :class:`aiogram.types.story.Story` on success.
+
+ Source: https://core.telegram.org/bots/api#poststory
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param content: Content of the story
+ :param active_period: Period after which the story is moved to the archive, in seconds; must be one of :code:`6 * 3600`, :code:`12 * 3600`, :code:`86400`, or :code:`2 * 86400`
+ :param caption: Caption of the story, 0-2048 characters after entities parsing
+ :param parse_mode: Mode for parsing entities in the story caption. See `formatting options `_ for more details.
+ :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
+ :param areas: A JSON-serialized list of clickable areas to be shown on the story
+ :param post_to_chat_page: Pass :code:`True` to keep the story accessible after it expires
+ :param protect_content: Pass :code:`True` if the content of the story must be protected from forwarding and screenshotting
+ :param request_timeout: Request timeout
+ :return: Returns :class:`aiogram.types.story.Story` on success.
+ """
+
+ call = PostStory(
+ business_connection_id=business_connection_id,
+ content=content,
+ active_period=active_period,
+ caption=caption,
+ parse_mode=parse_mode,
+ caption_entities=caption_entities,
+ areas=areas,
+ post_to_chat_page=post_to_chat_page,
+ protect_content=protect_content,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def read_business_message(
+ self,
+ business_connection_id: str,
+ chat_id: int,
+ message_id: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Marks incoming message as read on behalf of a business account. Requires the *can_read_messages* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#readbusinessmessage
+
+ :param business_connection_id: Unique identifier of the business connection on behalf of which to read the message
+ :param chat_id: Unique identifier of the chat in which the message was received. The chat must have been active in the last 24 hours.
+ :param message_id: Unique identifier of the message to mark as read
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = ReadBusinessMessage(
+ business_connection_id=business_connection_id,
+ chat_id=chat_id,
+ message_id=message_id,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def remove_business_account_profile_photo(
+ self,
+ business_connection_id: str,
+ is_public: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Removes the current profile photo of a managed business account. Requires the *can_edit_profile_photo* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#removebusinessaccountprofilephoto
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param is_public: Pass True to remove the public photo, which is visible even if the main photo is hidden by the business account's privacy settings. After the main photo is removed, the previous profile photo (if present) becomes the main photo.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = RemoveBusinessAccountProfilePhoto(
+ business_connection_id=business_connection_id,
+ is_public=is_public,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_business_account_bio(
+ self,
+ business_connection_id: str,
+ bio: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Changes the bio of a managed business account. Requires the *can_change_bio* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setbusinessaccountbio
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param bio: The new value of the bio for the business account; 0-140 characters
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetBusinessAccountBio(
+ business_connection_id=business_connection_id,
+ bio=bio,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_business_account_gift_settings(
+ self,
+ business_connection_id: str,
+ show_gift_button: bool,
+ accepted_gift_types: AcceptedGiftTypes,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Changes the privacy settings pertaining to incoming gifts in a managed business account. Requires the *can_change_gift_settings* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setbusinessaccountgiftsettings
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param show_gift_button: Pass True, if a button for sending a gift to the user or by the business account must always be shown in the input field
+ :param accepted_gift_types: Types of gifts accepted by the business account
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetBusinessAccountGiftSettings(
+ business_connection_id=business_connection_id,
+ show_gift_button=show_gift_button,
+ accepted_gift_types=accepted_gift_types,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_business_account_name(
+ self,
+ business_connection_id: str,
+ first_name: str,
+ last_name: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Changes the first and last name of a managed business account. Requires the *can_change_name* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setbusinessaccountname
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param first_name: The new value of the first name for the business account; 1-64 characters
+ :param last_name: The new value of the last name for the business account; 0-64 characters
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetBusinessAccountName(
+ business_connection_id=business_connection_id,
+ first_name=first_name,
+ last_name=last_name,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_business_account_profile_photo(
+ self,
+ business_connection_id: str,
+ photo: InputProfilePhotoUnion,
+ is_public: Optional[bool] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Changes the profile photo of a managed business account. Requires the *can_edit_profile_photo* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setbusinessaccountprofilephoto
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param photo: The new profile photo to set
+ :param is_public: Pass True to set the public photo, which will be visible even if the main photo is hidden by the business account's privacy settings. An account can have only one public photo.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetBusinessAccountProfilePhoto(
+ business_connection_id=business_connection_id,
+ photo=photo,
+ is_public=is_public,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def set_business_account_username(
+ self,
+ business_connection_id: str,
+ username: Optional[str] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Changes the username of a managed business account. Requires the *can_change_username* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#setbusinessaccountusername
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param username: The new value of the username for the business account; 0-32 characters
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = SetBusinessAccountUsername(
+ business_connection_id=business_connection_id,
+ username=username,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def transfer_business_account_stars(
+ self,
+ business_connection_id: str,
+ star_count: int,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Transfers Telegram Stars from the business account balance to the bot's balance. Requires the *can_transfer_stars* business bot right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#transferbusinessaccountstars
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param star_count: Number of Telegram Stars to transfer; 1-10000
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = TransferBusinessAccountStars(
+ business_connection_id=business_connection_id,
+ star_count=star_count,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def transfer_gift(
+ self,
+ business_connection_id: str,
+ owned_gift_id: str,
+ new_owner_chat_id: int,
+ star_count: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Transfers an owned unique gift to another user. Requires the *can_transfer_and_upgrade_gifts* business bot right. Requires *can_transfer_stars* business bot right if the transfer is paid. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#transfergift
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param owned_gift_id: Unique identifier of the regular gift that should be transferred
+ :param new_owner_chat_id: Unique identifier of the chat which will own the gift. The chat must be active in the last 24 hours.
+ :param star_count: The amount of Telegram Stars that will be paid for the transfer from the business account balance. If positive, then the *can_transfer_stars* business bot right is required.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = TransferGift(
+ business_connection_id=business_connection_id,
+ owned_gift_id=owned_gift_id,
+ new_owner_chat_id=new_owner_chat_id,
+ star_count=star_count,
+ )
+ return await self(call, request_timeout=request_timeout)
+
+ async def upgrade_gift(
+ self,
+ business_connection_id: str,
+ owned_gift_id: str,
+ keep_original_details: Optional[bool] = None,
+ star_count: Optional[int] = None,
+ request_timeout: Optional[int] = None,
+ ) -> bool:
+ """
+ Upgrades a given regular gift to a unique gift. Requires the *can_transfer_and_upgrade_gifts* business bot right. Additionally requires the *can_transfer_stars* business bot right if the upgrade is paid. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#upgradegift
+
+ :param business_connection_id: Unique identifier of the business connection
+ :param owned_gift_id: Unique identifier of the regular gift that should be upgraded to a unique one
+ :param keep_original_details: Pass True to keep the original gift text, sender and receiver in the upgraded gift
+ :param star_count: The amount of Telegram Stars that will be paid for the upgrade from the business account balance. If :code:`gift.prepaid_upgrade_star_count > 0`, then pass 0, otherwise, the *can_transfer_stars* business bot right is required and :code:`gift.upgrade_star_count` must be passed.
+ :param request_timeout: Request timeout
+ :return: Returns :code:`True` on success.
+ """
+
+ call = UpgradeGift(
+ business_connection_id=business_connection_id,
+ owned_gift_id=owned_gift_id,
+ keep_original_details=keep_original_details,
+ star_count=star_count,
+ )
+ return await self(call, request_timeout=request_timeout)
diff --git a/myenv/Lib/site-packages/aiogram/client/context_controller.py b/myenv/Lib/site-packages/aiogram/client/context_controller.py
new file mode 100644
index 0000000..97795a7
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/context_controller.py
@@ -0,0 +1,33 @@
+from typing import TYPE_CHECKING, Any, Optional
+
+from pydantic import BaseModel, PrivateAttr
+from typing_extensions import Self
+
+if TYPE_CHECKING:
+ from aiogram.client.bot import Bot
+
+
+class BotContextController(BaseModel):
+ _bot: Optional["Bot"] = PrivateAttr()
+
+ def model_post_init(self, __context: Any) -> None:
+ self._bot = __context.get("bot") if __context else None
+
+ def as_(self, bot: Optional["Bot"]) -> Self:
+ """
+ Bind object to a bot instance.
+
+ :param bot: Bot instance
+ :return: self
+ """
+ self._bot = bot
+ return self
+
+ @property
+ def bot(self) -> Optional["Bot"]:
+ """
+ Get bot instance.
+
+ :return: Bot instance
+ """
+ return self._bot
diff --git a/myenv/Lib/site-packages/aiogram/client/default.py b/myenv/Lib/site-packages/aiogram/client/default.py
new file mode 100644
index 0000000..78dd0aa
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/default.py
@@ -0,0 +1,80 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, Any, Optional
+
+from aiogram.utils.dataclass import dataclass_kwargs
+
+if TYPE_CHECKING:
+ from aiogram.types import LinkPreviewOptions
+
+
+# @dataclass ??
+class Default:
+ # Is not a dataclass because of JSON serialization.
+
+ __slots__ = ("_name",)
+
+ def __init__(self, name: str) -> None:
+ self._name = name
+
+ @property
+ def name(self) -> str:
+ return self._name
+
+ def __str__(self) -> str:
+ return f"Default({self._name!r})"
+
+ def __repr__(self) -> str:
+ return f"<{self}>"
+
+
+@dataclass(**dataclass_kwargs(slots=True, kw_only=True))
+class DefaultBotProperties:
+ """
+ Default bot properties.
+ """
+
+ parse_mode: Optional[str] = None
+ """Default parse mode for messages."""
+ disable_notification: Optional[bool] = None
+ """Sends the message silently. Users will receive a notification with no sound."""
+ protect_content: Optional[bool] = None
+ """Protects content from copying."""
+ allow_sending_without_reply: Optional[bool] = None
+ """Allows to send messages without reply."""
+ link_preview: Optional[LinkPreviewOptions] = None
+ """Link preview settings."""
+ link_preview_is_disabled: Optional[bool] = None
+ """Disables link preview."""
+ link_preview_prefer_small_media: Optional[bool] = None
+ """Prefer small media in link preview."""
+ link_preview_prefer_large_media: Optional[bool] = None
+ """Prefer large media in link preview."""
+ link_preview_show_above_text: Optional[bool] = None
+ """Show link preview above text."""
+ show_caption_above_media: Optional[bool] = None
+ """Show caption above media."""
+
+ def __post_init__(self) -> None:
+ has_any_link_preview_option = any(
+ (
+ self.link_preview_is_disabled,
+ self.link_preview_prefer_small_media,
+ self.link_preview_prefer_large_media,
+ self.link_preview_show_above_text,
+ )
+ )
+
+ if has_any_link_preview_option and self.link_preview is None:
+ from ..types import LinkPreviewOptions
+
+ self.link_preview = LinkPreviewOptions(
+ is_disabled=self.link_preview_is_disabled,
+ prefer_small_media=self.link_preview_prefer_small_media,
+ prefer_large_media=self.link_preview_prefer_large_media,
+ show_above_text=self.link_preview_show_above_text,
+ )
+
+ def __getitem__(self, item: str) -> Any:
+ return getattr(self, item, None)
diff --git a/myenv/Lib/site-packages/aiogram/client/session/__init__.py b/myenv/Lib/site-packages/aiogram/client/session/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram/client/session/aiohttp.py b/myenv/Lib/site-packages/aiogram/client/session/aiohttp.py
new file mode 100644
index 0000000..b832af6
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/session/aiohttp.py
@@ -0,0 +1,211 @@
+from __future__ import annotations
+
+import asyncio
+import ssl
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ AsyncGenerator,
+ Dict,
+ Iterable,
+ List,
+ Optional,
+ Tuple,
+ Type,
+ Union,
+ cast,
+)
+
+import certifi
+from aiohttp import BasicAuth, ClientError, ClientSession, FormData, TCPConnector
+from aiohttp.hdrs import USER_AGENT
+from aiohttp.http import SERVER_SOFTWARE
+
+from aiogram.__meta__ import __version__
+from aiogram.methods import TelegramMethod
+
+from ...exceptions import TelegramNetworkError
+from ...methods.base import TelegramType
+from ...types import InputFile
+from .base import BaseSession
+
+if TYPE_CHECKING:
+ from ..bot import Bot
+
+_ProxyBasic = Union[str, Tuple[str, BasicAuth]]
+_ProxyChain = Iterable[_ProxyBasic]
+_ProxyType = Union[_ProxyChain, _ProxyBasic]
+
+
+def _retrieve_basic(basic: _ProxyBasic) -> Dict[str, Any]:
+ from aiohttp_socks.utils import parse_proxy_url
+
+ proxy_auth: Optional[BasicAuth] = None
+
+ if isinstance(basic, str):
+ proxy_url = basic
+ else:
+ proxy_url, proxy_auth = basic
+
+ proxy_type, host, port, username, password = parse_proxy_url(proxy_url)
+ if isinstance(proxy_auth, BasicAuth):
+ username = proxy_auth.login
+ password = proxy_auth.password
+
+ return {
+ "proxy_type": proxy_type,
+ "host": host,
+ "port": port,
+ "username": username,
+ "password": password,
+ "rdns": True,
+ }
+
+
+def _prepare_connector(chain_or_plain: _ProxyType) -> Tuple[Type["TCPConnector"], Dict[str, Any]]:
+ from aiohttp_socks import ChainProxyConnector, ProxyConnector, ProxyInfo
+
+ # since tuple is Iterable(compatible with _ProxyChain) object, we assume that
+ # user wants chained proxies if tuple is a pair of string(url) and BasicAuth
+ if isinstance(chain_or_plain, str) or (
+ isinstance(chain_or_plain, tuple) and len(chain_or_plain) == 2
+ ):
+ chain_or_plain = cast(_ProxyBasic, chain_or_plain)
+ return ProxyConnector, _retrieve_basic(chain_or_plain)
+
+ chain_or_plain = cast(_ProxyChain, chain_or_plain)
+ infos: List[ProxyInfo] = []
+ for basic in chain_or_plain:
+ infos.append(ProxyInfo(**_retrieve_basic(basic)))
+
+ return ChainProxyConnector, {"proxy_infos": infos}
+
+
+class AiohttpSession(BaseSession):
+ def __init__(
+ self, proxy: Optional[_ProxyType] = None, limit: int = 100, **kwargs: Any
+ ) -> None:
+ """
+ Client session based on aiohttp.
+
+ :param proxy: The proxy to be used for requests. Default is None.
+ :param limit: The total number of simultaneous connections. Default is 100.
+ :param kwargs: Additional keyword arguments.
+ """
+ super().__init__(**kwargs)
+
+ self._session: Optional[ClientSession] = None
+ self._connector_type: Type[TCPConnector] = TCPConnector
+ self._connector_init: Dict[str, Any] = {
+ "ssl": ssl.create_default_context(cafile=certifi.where()),
+ "limit": limit,
+ "ttl_dns_cache": 3600, # Workaround for https://github.com/aiogram/aiogram/issues/1500
+ }
+ self._should_reset_connector = True # flag determines connector state
+ self._proxy: Optional[_ProxyType] = None
+
+ if proxy is not None:
+ try:
+ self._setup_proxy_connector(proxy)
+ except ImportError as exc: # pragma: no cover
+ raise RuntimeError(
+ "In order to use aiohttp client for proxy requests, install "
+ "https://pypi.org/project/aiohttp-socks/"
+ ) from exc
+
+ def _setup_proxy_connector(self, proxy: _ProxyType) -> None:
+ self._connector_type, self._connector_init = _prepare_connector(proxy)
+ self._proxy = proxy
+
+ @property
+ def proxy(self) -> Optional[_ProxyType]:
+ return self._proxy
+
+ @proxy.setter
+ def proxy(self, proxy: _ProxyType) -> None:
+ self._setup_proxy_connector(proxy)
+ self._should_reset_connector = True
+
+ async def create_session(self) -> ClientSession:
+ if self._should_reset_connector:
+ await self.close()
+
+ if self._session is None or self._session.closed:
+ self._session = ClientSession(
+ connector=self._connector_type(**self._connector_init),
+ headers={
+ USER_AGENT: f"{SERVER_SOFTWARE} aiogram/{__version__}",
+ },
+ )
+ self._should_reset_connector = False
+
+ return self._session
+
+ async def close(self) -> None:
+ if self._session is not None and not self._session.closed:
+ await self._session.close()
+
+ # Wait 250 ms for the underlying SSL connections to close
+ # https://docs.aiohttp.org/en/stable/client_advanced.html#graceful-shutdown
+ await asyncio.sleep(0.25)
+
+ def build_form_data(self, bot: Bot, method: TelegramMethod[TelegramType]) -> FormData:
+ form = FormData(quote_fields=False)
+ files: Dict[str, InputFile] = {}
+ for key, value in method.model_dump(warnings=False).items():
+ value = self.prepare_value(value, bot=bot, files=files)
+ if not value:
+ continue
+ form.add_field(key, value)
+ for key, value in files.items():
+ form.add_field(
+ key,
+ value.read(bot),
+ filename=value.filename or key,
+ )
+ return form
+
+ async def make_request(
+ self, bot: Bot, method: TelegramMethod[TelegramType], timeout: Optional[int] = None
+ ) -> TelegramType:
+ session = await self.create_session()
+
+ url = self.api.api_url(token=bot.token, method=method.__api_method__)
+ form = self.build_form_data(bot=bot, method=method)
+
+ try:
+ async with session.post(
+ url, data=form, timeout=self.timeout if timeout is None else timeout
+ ) as resp:
+ raw_result = await resp.text()
+ except asyncio.TimeoutError:
+ raise TelegramNetworkError(method=method, message="Request timeout error")
+ except ClientError as e:
+ raise TelegramNetworkError(method=method, message=f"{type(e).__name__}: {e}")
+ response = self.check_response(
+ bot=bot, method=method, status_code=resp.status, content=raw_result
+ )
+ return cast(TelegramType, response.result)
+
+ async def stream_content(
+ self,
+ url: str,
+ headers: Optional[Dict[str, Any]] = None,
+ timeout: int = 30,
+ chunk_size: int = 65536,
+ raise_for_status: bool = True,
+ ) -> AsyncGenerator[bytes, None]:
+ if headers is None:
+ headers = {}
+
+ session = await self.create_session()
+
+ async with session.get(
+ url, timeout=timeout, headers=headers, raise_for_status=raise_for_status
+ ) as resp:
+ async for chunk in resp.content.iter_chunked(chunk_size):
+ yield chunk
+
+ async def __aenter__(self) -> AiohttpSession:
+ await self.create_session()
+ return self
diff --git a/myenv/Lib/site-packages/aiogram/client/session/base.py b/myenv/Lib/site-packages/aiogram/client/session/base.py
new file mode 100644
index 0000000..82ec469
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/session/base.py
@@ -0,0 +1,265 @@
+from __future__ import annotations
+
+import abc
+import datetime
+import json
+import secrets
+from enum import Enum
+from http import HTTPStatus
+from types import TracebackType
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ AsyncGenerator,
+ Callable,
+ Dict,
+ Final,
+ Optional,
+ Type,
+ cast,
+)
+
+from pydantic import ValidationError
+
+from aiogram.exceptions import (
+ ClientDecodeError,
+ RestartingTelegram,
+ TelegramAPIError,
+ TelegramBadRequest,
+ TelegramConflictError,
+ TelegramEntityTooLarge,
+ TelegramForbiddenError,
+ TelegramMigrateToChat,
+ TelegramNotFound,
+ TelegramRetryAfter,
+ TelegramServerError,
+ TelegramUnauthorizedError,
+)
+
+from ...methods import Response, TelegramMethod
+from ...methods.base import TelegramType
+from ...types import InputFile, TelegramObject
+from ..default import Default
+from ..telegram import PRODUCTION, TelegramAPIServer
+from .middlewares.manager import RequestMiddlewareManager
+
+if TYPE_CHECKING:
+ from ..bot import Bot
+
+_JsonLoads = Callable[..., Any]
+_JsonDumps = Callable[..., str]
+
+DEFAULT_TIMEOUT: Final[float] = 60.0
+
+
+class BaseSession(abc.ABC):
+ """
+ This is base class for all HTTP sessions in aiogram.
+
+ If you want to create your own session, you must inherit from this class.
+ """
+
+ def __init__(
+ self,
+ api: TelegramAPIServer = PRODUCTION,
+ json_loads: _JsonLoads = json.loads,
+ json_dumps: _JsonDumps = json.dumps,
+ timeout: float = DEFAULT_TIMEOUT,
+ ) -> None:
+ """
+
+ :param api: Telegram Bot API URL patterns
+ :param json_loads: JSON loader
+ :param json_dumps: JSON dumper
+ :param timeout: Session scope request timeout
+ """
+ self.api = api
+ self.json_loads = json_loads
+ self.json_dumps = json_dumps
+ self.timeout = timeout
+
+ self.middleware = RequestMiddlewareManager()
+
+ def check_response(
+ self, bot: Bot, method: TelegramMethod[TelegramType], status_code: int, content: str
+ ) -> Response[TelegramType]:
+ """
+ Check response status
+ """
+ try:
+ json_data = self.json_loads(content)
+ except Exception as e:
+ # Handled error type can't be classified as specific error
+ # in due to decoder can be customized and raise any exception
+
+ raise ClientDecodeError("Failed to decode object", e, content)
+
+ try:
+ response_type = Response[method.__returning__] # type: ignore
+ response = response_type.model_validate(json_data, context={"bot": bot})
+ except ValidationError as e:
+ raise ClientDecodeError("Failed to deserialize object", e, json_data)
+
+ if HTTPStatus.OK <= status_code <= HTTPStatus.IM_USED and response.ok:
+ return response
+
+ description = cast(str, response.description)
+
+ if parameters := response.parameters:
+ if parameters.retry_after:
+ raise TelegramRetryAfter(
+ method=method, message=description, retry_after=parameters.retry_after
+ )
+ if parameters.migrate_to_chat_id:
+ raise TelegramMigrateToChat(
+ method=method,
+ message=description,
+ migrate_to_chat_id=parameters.migrate_to_chat_id,
+ )
+ if status_code == HTTPStatus.BAD_REQUEST:
+ raise TelegramBadRequest(method=method, message=description)
+ if status_code == HTTPStatus.NOT_FOUND:
+ raise TelegramNotFound(method=method, message=description)
+ if status_code == HTTPStatus.CONFLICT:
+ raise TelegramConflictError(method=method, message=description)
+ if status_code == HTTPStatus.UNAUTHORIZED:
+ raise TelegramUnauthorizedError(method=method, message=description)
+ if status_code == HTTPStatus.FORBIDDEN:
+ raise TelegramForbiddenError(method=method, message=description)
+ if status_code == HTTPStatus.REQUEST_ENTITY_TOO_LARGE:
+ raise TelegramEntityTooLarge(method=method, message=description)
+ if status_code >= HTTPStatus.INTERNAL_SERVER_ERROR:
+ if "restart" in description:
+ raise RestartingTelegram(method=method, message=description)
+ raise TelegramServerError(method=method, message=description)
+
+ raise TelegramAPIError(
+ method=method,
+ message=description,
+ )
+
+ @abc.abstractmethod
+ async def close(self) -> None: # pragma: no cover
+ """
+ Close client session
+ """
+ pass
+
+ @abc.abstractmethod
+ async def make_request(
+ self,
+ bot: Bot,
+ method: TelegramMethod[TelegramType],
+ timeout: Optional[int] = None,
+ ) -> TelegramType: # pragma: no cover
+ """
+ Make request to Telegram Bot API
+
+ :param bot: Bot instance
+ :param method: Method instance
+ :param timeout: Request timeout
+ :return:
+ :raise TelegramApiError:
+ """
+ pass
+
+ @abc.abstractmethod
+ async def stream_content(
+ self,
+ url: str,
+ headers: Optional[Dict[str, Any]] = None,
+ timeout: int = 30,
+ chunk_size: int = 65536,
+ raise_for_status: bool = True,
+ ) -> AsyncGenerator[bytes, None]: # pragma: no cover
+ """
+ Stream reader
+ """
+ yield b""
+
+ def prepare_value(
+ self,
+ value: Any,
+ bot: Bot,
+ files: Dict[str, Any],
+ _dumps_json: bool = True,
+ ) -> Any:
+ """
+ Prepare value before send
+ """
+ if value is None:
+ return None
+ if isinstance(value, str):
+ return value
+ if isinstance(value, Default):
+ default_value = bot.default[value.name]
+ return self.prepare_value(default_value, bot=bot, files=files, _dumps_json=_dumps_json)
+ if isinstance(value, InputFile):
+ key = secrets.token_urlsafe(10)
+ files[key] = value
+ return f"attach://{key}"
+ if isinstance(value, dict):
+ value = {
+ key: prepared_item
+ for key, item in value.items()
+ if (
+ prepared_item := self.prepare_value(
+ item, bot=bot, files=files, _dumps_json=False
+ )
+ )
+ is not None
+ }
+ if _dumps_json:
+ return self.json_dumps(value)
+ return value
+ if isinstance(value, list):
+ value = [
+ prepared_item
+ for item in value
+ if (
+ prepared_item := self.prepare_value(
+ item, bot=bot, files=files, _dumps_json=False
+ )
+ )
+ is not None
+ ]
+ if _dumps_json:
+ return self.json_dumps(value)
+ return value
+ if isinstance(value, datetime.timedelta):
+ now = datetime.datetime.now()
+ return str(round((now + value).timestamp()))
+ if isinstance(value, datetime.datetime):
+ return str(round(value.timestamp()))
+ if isinstance(value, Enum):
+ return self.prepare_value(value.value, bot=bot, files=files)
+ if isinstance(value, TelegramObject):
+ return self.prepare_value(
+ value.model_dump(warnings=False),
+ bot=bot,
+ files=files,
+ _dumps_json=_dumps_json,
+ )
+ if _dumps_json:
+ return self.json_dumps(value)
+ return value
+
+ async def __call__(
+ self,
+ bot: Bot,
+ method: TelegramMethod[TelegramType],
+ timeout: Optional[int] = None,
+ ) -> TelegramType:
+ middleware = self.middleware.wrap_middlewares(self.make_request, timeout=timeout)
+ return cast(TelegramType, await middleware(bot, method))
+
+ async def __aenter__(self) -> BaseSession:
+ return self
+
+ async def __aexit__(
+ self,
+ exc_type: Optional[Type[BaseException]],
+ exc_value: Optional[BaseException],
+ traceback: Optional[TracebackType],
+ ) -> None:
+ await self.close()
diff --git a/myenv/Lib/site-packages/aiogram/client/session/middlewares/__init__.py b/myenv/Lib/site-packages/aiogram/client/session/middlewares/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram/client/session/middlewares/base.py b/myenv/Lib/site-packages/aiogram/client/session/middlewares/base.py
new file mode 100644
index 0000000..c5f3e7c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/session/middlewares/base.py
@@ -0,0 +1,53 @@
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Protocol
+
+from aiogram.methods import Response, TelegramMethod
+from aiogram.methods.base import TelegramType
+
+if TYPE_CHECKING:
+ from ...bot import Bot
+
+
+class NextRequestMiddlewareType(Protocol[TelegramType]): # pragma: no cover
+ async def __call__(
+ self,
+ bot: "Bot",
+ method: TelegramMethod[TelegramType],
+ ) -> Response[TelegramType]:
+ pass
+
+
+class RequestMiddlewareType(Protocol): # pragma: no cover
+ async def __call__(
+ self,
+ make_request: NextRequestMiddlewareType[TelegramType],
+ bot: "Bot",
+ method: TelegramMethod[TelegramType],
+ ) -> Response[TelegramType]:
+ pass
+
+
+class BaseRequestMiddleware(ABC):
+ """
+ Generic middleware class
+ """
+
+ @abstractmethod
+ async def __call__(
+ self,
+ make_request: NextRequestMiddlewareType[TelegramType],
+ bot: "Bot",
+ method: TelegramMethod[TelegramType],
+ ) -> Response[TelegramType]:
+ """
+ Execute middleware
+
+ :param make_request: Wrapped make_request in middlewares chain
+ :param bot: bot for request making
+ :param method: Request method (Subclass of :class:`aiogram.methods.base.TelegramMethod`)
+
+ :return: :class:`aiogram.methods.Response`
+ """
+ pass
diff --git a/myenv/Lib/site-packages/aiogram/client/session/middlewares/manager.py b/myenv/Lib/site-packages/aiogram/client/session/middlewares/manager.py
new file mode 100644
index 0000000..2346715
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/session/middlewares/manager.py
@@ -0,0 +1,62 @@
+from __future__ import annotations
+
+from functools import partial
+from typing import Any, Callable, List, Optional, Sequence, Union, cast, overload
+
+from aiogram.client.session.middlewares.base import (
+ NextRequestMiddlewareType,
+ RequestMiddlewareType,
+)
+from aiogram.methods.base import TelegramType
+
+
+class RequestMiddlewareManager(Sequence[RequestMiddlewareType]):
+ def __init__(self) -> None:
+ self._middlewares: List[RequestMiddlewareType] = []
+
+ def register(
+ self,
+ middleware: RequestMiddlewareType,
+ ) -> RequestMiddlewareType:
+ self._middlewares.append(middleware)
+ return middleware
+
+ def unregister(self, middleware: RequestMiddlewareType) -> None:
+ self._middlewares.remove(middleware)
+
+ def __call__(
+ self,
+ middleware: Optional[RequestMiddlewareType] = None,
+ ) -> Union[
+ Callable[[RequestMiddlewareType], RequestMiddlewareType],
+ RequestMiddlewareType,
+ ]:
+ if middleware is None:
+ return self.register
+ return self.register(middleware)
+
+ @overload
+ def __getitem__(self, item: int) -> RequestMiddlewareType:
+ pass
+
+ @overload
+ def __getitem__(self, item: slice) -> Sequence[RequestMiddlewareType]:
+ pass
+
+ def __getitem__(
+ self, item: Union[int, slice]
+ ) -> Union[RequestMiddlewareType, Sequence[RequestMiddlewareType]]:
+ return self._middlewares[item]
+
+ def __len__(self) -> int:
+ return len(self._middlewares)
+
+ def wrap_middlewares(
+ self,
+ callback: NextRequestMiddlewareType[TelegramType],
+ **kwargs: Any,
+ ) -> NextRequestMiddlewareType[TelegramType]:
+ middleware = partial(callback, **kwargs)
+ for m in reversed(self._middlewares):
+ middleware = partial(m, middleware)
+ return cast(NextRequestMiddlewareType[TelegramType], middleware)
diff --git a/myenv/Lib/site-packages/aiogram/client/session/middlewares/request_logging.py b/myenv/Lib/site-packages/aiogram/client/session/middlewares/request_logging.py
new file mode 100644
index 0000000..af7b9d6
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/session/middlewares/request_logging.py
@@ -0,0 +1,37 @@
+import logging
+from typing import TYPE_CHECKING, Any, List, Optional, Type
+
+from aiogram import loggers
+from aiogram.methods import TelegramMethod
+from aiogram.methods.base import Response, TelegramType
+
+from .base import BaseRequestMiddleware, NextRequestMiddlewareType
+
+if TYPE_CHECKING:
+ from ...bot import Bot
+
+logger = logging.getLogger(__name__)
+
+
+class RequestLogging(BaseRequestMiddleware):
+ def __init__(self, ignore_methods: Optional[List[Type[TelegramMethod[Any]]]] = None):
+ """
+ Middleware for logging outgoing requests
+
+ :param ignore_methods: methods to ignore in logging middleware
+ """
+ self.ignore_methods = ignore_methods if ignore_methods else []
+
+ async def __call__(
+ self,
+ make_request: NextRequestMiddlewareType[TelegramType],
+ bot: "Bot",
+ method: TelegramMethod[TelegramType],
+ ) -> Response[TelegramType]:
+ if type(method) not in self.ignore_methods:
+ loggers.middlewares.info(
+ "Make request with method=%r by bot id=%d",
+ type(method).__name__,
+ bot.id,
+ )
+ return await make_request(bot, method)
diff --git a/myenv/Lib/site-packages/aiogram/client/telegram.py b/myenv/Lib/site-packages/aiogram/client/telegram.py
new file mode 100644
index 0000000..cfb3c49
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/client/telegram.py
@@ -0,0 +1,103 @@
+from abc import ABC, abstractmethod
+from dataclasses import dataclass
+from pathlib import Path
+from typing import Any, Union
+
+
+class FilesPathWrapper(ABC):
+ @abstractmethod
+ def to_local(self, path: Union[Path, str]) -> Union[Path, str]:
+ pass
+
+ @abstractmethod
+ def to_server(self, path: Union[Path, str]) -> Union[Path, str]:
+ pass
+
+
+class BareFilesPathWrapper(FilesPathWrapper):
+ def to_local(self, path: Union[Path, str]) -> Union[Path, str]:
+ return path
+
+ def to_server(self, path: Union[Path, str]) -> Union[Path, str]:
+ return path
+
+
+class SimpleFilesPathWrapper(FilesPathWrapper):
+ def __init__(self, server_path: Path, local_path: Path) -> None:
+ self.server_path = server_path
+ self.local_path = local_path
+
+ @classmethod
+ def _resolve(
+ cls, base1: Union[Path, str], base2: Union[Path, str], value: Union[Path, str]
+ ) -> Path:
+ relative = Path(value).relative_to(base1)
+ return base2 / relative
+
+ def to_local(self, path: Union[Path, str]) -> Union[Path, str]:
+ return self._resolve(base1=self.server_path, base2=self.local_path, value=path)
+
+ def to_server(self, path: Union[Path, str]) -> Union[Path, str]:
+ return self._resolve(base1=self.local_path, base2=self.server_path, value=path)
+
+
+@dataclass(frozen=True)
+class TelegramAPIServer:
+ """
+ Base config for API Endpoints
+ """
+
+ base: str
+ """Base URL"""
+ file: str
+ """Files URL"""
+ is_local: bool = False
+ """Mark this server is
+ in `local mode `_."""
+ wrap_local_file: FilesPathWrapper = BareFilesPathWrapper()
+ """Callback to wrap files path in local mode"""
+
+ def api_url(self, token: str, method: str) -> str:
+ """
+ Generate URL for API methods
+
+ :param token: Bot token
+ :param method: API method name (case insensitive)
+ :return: URL
+ """
+ return self.base.format(token=token, method=method)
+
+ def file_url(self, token: str, path: Union[str, Path]) -> str:
+ """
+ Generate URL for downloading files
+
+ :param token: Bot token
+ :param path: file path
+ :return: URL
+ """
+ return self.file.format(token=token, path=path)
+
+ @classmethod
+ def from_base(cls, base: str, **kwargs: Any) -> "TelegramAPIServer":
+ """
+ Use this method to auto-generate TelegramAPIServer instance from base URL
+
+ :param base: Base URL
+ :return: instance of :class:`TelegramAPIServer`
+ """
+ base = base.rstrip("/")
+ return cls(
+ base=f"{base}/bot{{token}}/{{method}}",
+ file=f"{base}/file/bot{{token}}/{{path}}",
+ **kwargs,
+ )
+
+
+PRODUCTION = TelegramAPIServer(
+ base="https://api.telegram.org/bot{token}/{method}",
+ file="https://api.telegram.org/file/bot{token}/{path}",
+)
+TEST = TelegramAPIServer(
+ base="https://api.telegram.org/bot{token}/test/{method}",
+ file="https://api.telegram.org/file/bot{token}/test/{path}",
+)
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/__init__.py b/myenv/Lib/site-packages/aiogram/dispatcher/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/dispatcher.py b/myenv/Lib/site-packages/aiogram/dispatcher/dispatcher.py
new file mode 100644
index 0000000..63fd33c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/dispatcher.py
@@ -0,0 +1,642 @@
+from __future__ import annotations
+
+import asyncio
+import contextvars
+import signal
+import warnings
+from asyncio import CancelledError, Event, Future, Lock
+from contextlib import suppress
+from typing import Any, AsyncGenerator, Awaitable, Dict, List, Optional, Set, Union
+
+from .. import loggers
+from ..client.bot import Bot
+from ..exceptions import TelegramAPIError
+from ..fsm.middleware import FSMContextMiddleware
+from ..fsm.storage.base import BaseEventIsolation, BaseStorage
+from ..fsm.storage.memory import DisabledEventIsolation, MemoryStorage
+from ..fsm.strategy import FSMStrategy
+from ..methods import GetUpdates, TelegramMethod
+from ..methods.base import TelegramType
+from ..types import Update, User
+from ..types.base import UNSET, UNSET_TYPE
+from ..types.update import UpdateTypeLookupError
+from ..utils.backoff import Backoff, BackoffConfig
+from .event.bases import UNHANDLED, SkipHandler
+from .event.telegram import TelegramEventObserver
+from .middlewares.error import ErrorsMiddleware
+from .middlewares.user_context import UserContextMiddleware
+from .router import Router
+
+DEFAULT_BACKOFF_CONFIG = BackoffConfig(min_delay=1.0, max_delay=5.0, factor=1.3, jitter=0.1)
+
+
+class Dispatcher(Router):
+ """
+ Root router
+ """
+
+ def __init__(
+ self,
+ *, # * - Preventing to pass instance of Bot to the FSM storage
+ storage: Optional[BaseStorage] = None,
+ fsm_strategy: FSMStrategy = FSMStrategy.USER_IN_CHAT,
+ events_isolation: Optional[BaseEventIsolation] = None,
+ disable_fsm: bool = False,
+ name: Optional[str] = None,
+ **kwargs: Any,
+ ) -> None:
+ """
+ Root router
+
+ :param storage: Storage for FSM
+ :param fsm_strategy: FSM strategy
+ :param events_isolation: Events isolation
+ :param disable_fsm: Disable FSM, note that if you disable FSM
+ then you should not use storage and events isolation
+ :param kwargs: Other arguments, will be passed as keyword arguments to handlers
+ """
+ super(Dispatcher, self).__init__(name=name)
+
+ if storage and not isinstance(storage, BaseStorage):
+ raise TypeError(
+ f"FSM storage should be instance of 'BaseStorage' not {type(storage).__name__}"
+ )
+
+ # Telegram API provides originally only one event type - Update
+ # For making easily interactions with events here is registered handler which helps
+ # to separate Update to different event types like Message, CallbackQuery etc.
+ self.update = self.observers["update"] = TelegramEventObserver(
+ router=self, event_name="update"
+ )
+ self.update.register(self._listen_update)
+
+ # Error handlers should work is out of all other functions
+ # and should be registered before all others middlewares
+ self.update.outer_middleware(ErrorsMiddleware(self))
+
+ # User context middleware makes small optimization for all other builtin
+ # middlewares via caching the user and chat instances in the event context
+ self.update.outer_middleware(UserContextMiddleware())
+
+ # FSM middleware should always be registered after User context middleware
+ # because here is used context from previous step
+ self.fsm = FSMContextMiddleware(
+ storage=storage or MemoryStorage(),
+ strategy=fsm_strategy,
+ events_isolation=events_isolation or DisabledEventIsolation(),
+ )
+ if not disable_fsm:
+ # Note that when FSM middleware is disabled, the event isolation is also disabled
+ # Because the isolation mechanism is a part of the FSM
+ self.update.outer_middleware(self.fsm)
+ self.shutdown.register(self.fsm.close)
+
+ self.workflow_data: Dict[str, Any] = kwargs
+ self._running_lock = Lock()
+ self._stop_signal: Optional[Event] = None
+ self._stopped_signal: Optional[Event] = None
+ self._handle_update_tasks: Set[asyncio.Task[Any]] = set()
+
+ def __getitem__(self, item: str) -> Any:
+ return self.workflow_data[item]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.workflow_data[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.workflow_data[key]
+
+ def get(self, key: str, /, default: Optional[Any] = None) -> Optional[Any]:
+ return self.workflow_data.get(key, default)
+
+ @property
+ def storage(self) -> BaseStorage:
+ return self.fsm.storage
+
+ @property
+ def parent_router(self) -> Optional[Router]:
+ """
+ Dispatcher has no parent router and can't be included to any other routers or dispatchers
+
+ :return:
+ """
+ return None # noqa: RET501
+
+ @parent_router.setter
+ def parent_router(self, value: Router) -> None:
+ """
+ Dispatcher is root Router then configuring parent router is not allowed
+
+ :param value:
+ :return:
+ """
+ raise RuntimeError("Dispatcher can not be attached to another Router.")
+
+ async def feed_update(self, bot: Bot, update: Update, **kwargs: Any) -> Any:
+ """
+ Main entry point for incoming updates
+ Response of this method can be used as Webhook response
+
+ :param bot:
+ :param update:
+ """
+ loop = asyncio.get_running_loop()
+ handled = False
+ start_time = loop.time()
+
+ if update.bot != bot:
+ # Re-mounting update to the current bot instance for making possible to
+ # use it in shortcuts.
+ # Here is update is re-created because we need to propagate context to
+ # all nested objects and attributes of the Update, but it
+ # is impossible without roundtrip to JSON :(
+ # The preferred way is that pass already mounted Bot instance to this update
+ # before call feed_update method
+ update = Update.model_validate(update.model_dump(), context={"bot": bot})
+
+ try:
+ response = await self.update.wrap_outer_middleware(
+ self.update.trigger,
+ update,
+ {
+ **self.workflow_data,
+ **kwargs,
+ "bot": bot,
+ },
+ )
+ handled = response is not UNHANDLED
+ return response
+ finally:
+ finish_time = loop.time()
+ duration = (finish_time - start_time) * 1000
+ loggers.event.info(
+ "Update id=%s is %s. Duration %d ms by bot id=%d",
+ update.update_id,
+ "handled" if handled else "not handled",
+ duration,
+ bot.id,
+ )
+
+ async def feed_raw_update(self, bot: Bot, update: Dict[str, Any], **kwargs: Any) -> Any:
+ """
+ Main entry point for incoming updates with automatic Dict->Update serializer
+
+ :param bot:
+ :param update:
+ :param kwargs:
+ """
+ parsed_update = Update.model_validate(update, context={"bot": bot})
+ return await self._feed_webhook_update(bot=bot, update=parsed_update, **kwargs)
+
+ @classmethod
+ async def _listen_updates(
+ cls,
+ bot: Bot,
+ polling_timeout: int = 30,
+ backoff_config: BackoffConfig = DEFAULT_BACKOFF_CONFIG,
+ allowed_updates: Optional[List[str]] = None,
+ ) -> AsyncGenerator[Update, None]:
+ """
+ Endless updates reader with correctly handling any server-side or connection errors.
+
+ So you may not worry that the polling will stop working.
+ """
+ backoff = Backoff(config=backoff_config)
+ get_updates = GetUpdates(timeout=polling_timeout, allowed_updates=allowed_updates)
+ kwargs = {}
+ if bot.session.timeout:
+ # Request timeout can be lower than session timeout and that's OK.
+ # To prevent false-positive TimeoutError we should wait longer than polling timeout
+ kwargs["request_timeout"] = int(bot.session.timeout + polling_timeout)
+ failed = False
+ while True:
+ try:
+ updates = await bot(get_updates, **kwargs)
+ except Exception as e:
+ failed = True
+ # In cases when Telegram Bot API was inaccessible don't need to stop polling
+ # process because some developers can't make auto-restarting of the script
+ loggers.dispatcher.error("Failed to fetch updates - %s: %s", type(e).__name__, e)
+ # And also backoff timeout is best practice to retry any network activity
+ loggers.dispatcher.warning(
+ "Sleep for %f seconds and try again... (tryings = %d, bot id = %d)",
+ backoff.next_delay,
+ backoff.counter,
+ bot.id,
+ )
+ await backoff.asleep()
+ continue
+
+ # In case when network connection was fixed let's reset the backoff
+ # to initial value and then process updates
+ if failed:
+ loggers.dispatcher.info(
+ "Connection established (tryings = %d, bot id = %d)",
+ backoff.counter,
+ bot.id,
+ )
+ backoff.reset()
+ failed = False
+
+ for update in updates:
+ yield update
+ # The getUpdates method returns the earliest 100 unconfirmed updates.
+ # To confirm an update, use the offset parameter when calling getUpdates
+ # All updates with update_id less than or equal to offset will be marked
+ # as confirmed on the server and will no longer be returned.
+ get_updates.offset = update.update_id + 1
+
+ async def _listen_update(self, update: Update, **kwargs: Any) -> Any:
+ """
+ Main updates listener
+
+ Workflow:
+ - Detect content type and propagate to observers in current router
+ - If no one filter is pass - propagate update to child routers as Update
+
+ :param update:
+ :param kwargs:
+ :return:
+ """
+ try:
+ update_type = update.event_type
+ event = update.event
+ except UpdateTypeLookupError as e:
+ warnings.warn(
+ "Detected unknown update type.\n"
+ "Seems like Telegram Bot API was updated and you have "
+ "installed not latest version of aiogram framework"
+ f"\nUpdate: {update.model_dump_json(exclude_unset=True)}",
+ RuntimeWarning,
+ )
+ raise SkipHandler() from e
+
+ kwargs.update(event_update=update)
+
+ return await self.propagate_event(update_type=update_type, event=event, **kwargs)
+
+ @classmethod
+ async def silent_call_request(cls, bot: Bot, result: TelegramMethod[Any]) -> None:
+ """
+ Simulate answer into WebHook
+
+ :param bot:
+ :param result:
+ :return:
+ """
+ try:
+ await bot(result)
+ except TelegramAPIError as e:
+ # In due to WebHook mechanism doesn't allow getting response for
+ # requests called in answer to WebHook request.
+ # Need to skip unsuccessful responses.
+ # For debugging here is added logging.
+ loggers.event.error("Failed to make answer: %s: %s", e.__class__.__name__, e)
+
+ async def _process_update(
+ self, bot: Bot, update: Update, call_answer: bool = True, **kwargs: Any
+ ) -> bool:
+ """
+ Propagate update to event listeners
+
+ :param bot: instance of Bot
+ :param update: instance of Update
+ :param call_answer: need to execute response as Telegram method (like answer into webhook)
+ :param kwargs: contextual data for middlewares, filters and handlers
+ :return: status
+ """
+ try:
+ response = await self.feed_update(bot, update, **kwargs)
+ if call_answer and isinstance(response, TelegramMethod):
+ await self.silent_call_request(bot=bot, result=response)
+ return response is not UNHANDLED
+
+ except Exception as e:
+ loggers.event.exception(
+ "Cause exception while process update id=%d by bot id=%d\n%s: %s",
+ update.update_id,
+ bot.id,
+ e.__class__.__name__,
+ e,
+ )
+ return True # because update was processed but unsuccessful
+
+ async def _process_with_semaphore(
+ self, handle_update: Awaitable[bool], semaphore: asyncio.Semaphore
+ ) -> bool:
+ """
+ Process update with semaphore to limit concurrent tasks
+
+ :param handle_update: Coroutine that processes the update
+ :param semaphore: Semaphore to limit concurrent tasks
+ :return: bool indicating the result of the update processing
+ """
+ try:
+ return await handle_update
+ finally:
+ semaphore.release()
+
+ async def _polling(
+ self,
+ bot: Bot,
+ polling_timeout: int = 30,
+ handle_as_tasks: bool = True,
+ backoff_config: BackoffConfig = DEFAULT_BACKOFF_CONFIG,
+ allowed_updates: Optional[List[str]] = None,
+ tasks_concurrency_limit: Optional[int] = None,
+ **kwargs: Any,
+ ) -> None:
+ """
+ Internal polling process
+
+ :param bot:
+ :param polling_timeout: Long-polling wait time
+ :param handle_as_tasks: Run task for each event and no wait result
+ :param backoff_config: backoff-retry config
+ :param allowed_updates: List of the update types you want your bot to receive
+ :param tasks_concurrency_limit: Maximum number of concurrent updates to process
+ (None = no limit), used only if handle_as_tasks is True
+ :param kwargs:
+ :return:
+ """
+ user: User = await bot.me()
+ loggers.dispatcher.info(
+ "Run polling for bot @%s id=%d - %r", user.username, bot.id, user.full_name
+ )
+
+ # Create semaphore if tasks_concurrency_limit is specified
+ semaphore = None
+ if tasks_concurrency_limit is not None and handle_as_tasks:
+ semaphore = asyncio.Semaphore(tasks_concurrency_limit)
+
+ try:
+ async for update in self._listen_updates(
+ bot,
+ polling_timeout=polling_timeout,
+ backoff_config=backoff_config,
+ allowed_updates=allowed_updates,
+ ):
+ handle_update = self._process_update(bot=bot, update=update, **kwargs)
+ if handle_as_tasks:
+ if semaphore:
+ # Use semaphore to limit concurrent tasks
+ await semaphore.acquire()
+ handle_update_task = asyncio.create_task(
+ self._process_with_semaphore(handle_update, semaphore)
+ )
+ else:
+ handle_update_task = asyncio.create_task(handle_update)
+
+ self._handle_update_tasks.add(handle_update_task)
+ handle_update_task.add_done_callback(self._handle_update_tasks.discard)
+ else:
+ await handle_update
+ finally:
+ loggers.dispatcher.info(
+ "Polling stopped for bot @%s id=%d - %r", user.username, bot.id, user.full_name
+ )
+
+ async def _feed_webhook_update(self, bot: Bot, update: Update, **kwargs: Any) -> Any:
+ """
+ The same with `Dispatcher.process_update()` but returns real response instead of bool
+ """
+ try:
+ return await self.feed_update(bot, update, **kwargs)
+ except Exception as e:
+ loggers.event.exception(
+ "Cause exception while process update id=%d by bot id=%d\n%s: %s",
+ update.update_id,
+ bot.id,
+ e.__class__.__name__,
+ e,
+ )
+ raise
+
+ async def feed_webhook_update(
+ self, bot: Bot, update: Union[Update, Dict[str, Any]], _timeout: float = 55, **kwargs: Any
+ ) -> Optional[TelegramMethod[TelegramType]]:
+ if not isinstance(update, Update): # Allow to use raw updates
+ update = Update.model_validate(update, context={"bot": bot})
+
+ ctx = contextvars.copy_context()
+ loop = asyncio.get_running_loop()
+ waiter = loop.create_future()
+
+ def release_waiter(*_: Any) -> None:
+ if not waiter.done():
+ waiter.set_result(None)
+
+ timeout_handle = loop.call_later(_timeout, release_waiter)
+
+ process_updates: Future[Any] = asyncio.ensure_future(
+ self._feed_webhook_update(bot=bot, update=update, **kwargs)
+ )
+ process_updates.add_done_callback(release_waiter, context=ctx)
+
+ def process_response(task: Future[Any]) -> None:
+ warnings.warn(
+ "Detected slow response into webhook.\n"
+ "Telegram is waiting for response only first 60 seconds and then re-send update.\n"
+ "For preventing this situation response into webhook returned immediately "
+ "and handler is moved to background and still processing update.",
+ RuntimeWarning,
+ )
+ try:
+ result = task.result()
+ except Exception as e:
+ raise e
+ if isinstance(result, TelegramMethod):
+ asyncio.ensure_future(self.silent_call_request(bot=bot, result=result))
+
+ try:
+ try:
+ await waiter
+ except CancelledError: # pragma: no cover
+ process_updates.remove_done_callback(release_waiter)
+ process_updates.cancel()
+ raise
+
+ if process_updates.done():
+ # TODO: handle exceptions
+ response: Any = process_updates.result()
+ if isinstance(response, TelegramMethod):
+ return response
+
+ else:
+ process_updates.remove_done_callback(release_waiter)
+ process_updates.add_done_callback(process_response, context=ctx)
+
+ finally:
+ timeout_handle.cancel()
+
+ return None
+
+ async def stop_polling(self) -> None:
+ """
+ Execute this method if you want to stop polling programmatically
+
+ :return:
+ """
+ if not self._running_lock.locked():
+ raise RuntimeError("Polling is not started")
+ if not self._stop_signal or not self._stopped_signal:
+ return
+ self._stop_signal.set()
+ await self._stopped_signal.wait()
+
+ def _signal_stop_polling(self, sig: signal.Signals) -> None:
+ if not self._running_lock.locked():
+ return
+
+ loggers.dispatcher.warning("Received %s signal", sig.name)
+ if not self._stop_signal:
+ return
+ self._stop_signal.set()
+
+ async def start_polling(
+ self,
+ *bots: Bot,
+ polling_timeout: int = 10,
+ handle_as_tasks: bool = True,
+ backoff_config: BackoffConfig = DEFAULT_BACKOFF_CONFIG,
+ allowed_updates: Optional[Union[List[str], UNSET_TYPE]] = UNSET,
+ handle_signals: bool = True,
+ close_bot_session: bool = True,
+ tasks_concurrency_limit: Optional[int] = None,
+ **kwargs: Any,
+ ) -> None:
+ """
+ Polling runner
+
+ :param bots: Bot instances (one or more)
+ :param polling_timeout: Long-polling wait time
+ :param handle_as_tasks: Run task for each event and no wait result
+ :param backoff_config: backoff-retry config
+ :param allowed_updates: List of the update types you want your bot to receive
+ By default, all used update types are enabled (resolved from handlers)
+ :param handle_signals: handle signals (SIGINT/SIGTERM)
+ :param close_bot_session: close bot sessions on shutdown
+ :param tasks_concurrency_limit: Maximum number of concurrent updates to process
+ (None = no limit), used only if handle_as_tasks is True
+ :param kwargs: contextual data
+ :return:
+ """
+ if not bots:
+ raise ValueError("At least one bot instance is required to start polling")
+ if "bot" in kwargs:
+ raise ValueError(
+ "Keyword argument 'bot' is not acceptable, "
+ "the bot instance should be passed as positional argument"
+ )
+
+ async with self._running_lock: # Prevent to run this method twice at a once
+ if self._stop_signal is None:
+ self._stop_signal = Event()
+ if self._stopped_signal is None:
+ self._stopped_signal = Event()
+
+ if allowed_updates is UNSET:
+ allowed_updates = self.resolve_used_update_types()
+
+ self._stop_signal.clear()
+ self._stopped_signal.clear()
+
+ if handle_signals:
+ loop = asyncio.get_running_loop()
+ with suppress(NotImplementedError): # pragma: no cover
+ # Signals handling is not supported on Windows
+ # It also can't be covered on Windows
+ loop.add_signal_handler(
+ signal.SIGTERM, self._signal_stop_polling, signal.SIGTERM
+ )
+ loop.add_signal_handler(
+ signal.SIGINT, self._signal_stop_polling, signal.SIGINT
+ )
+
+ workflow_data = {
+ "dispatcher": self,
+ "bots": bots,
+ **self.workflow_data,
+ **kwargs,
+ }
+ if "bot" in workflow_data:
+ workflow_data.pop("bot")
+
+ await self.emit_startup(bot=bots[-1], **workflow_data)
+ loggers.dispatcher.info("Start polling")
+ try:
+ tasks: List[asyncio.Task[Any]] = [
+ asyncio.create_task(
+ self._polling(
+ bot=bot,
+ handle_as_tasks=handle_as_tasks,
+ polling_timeout=polling_timeout,
+ backoff_config=backoff_config,
+ allowed_updates=allowed_updates,
+ tasks_concurrency_limit=tasks_concurrency_limit,
+ **workflow_data,
+ )
+ )
+ for bot in bots
+ ]
+ tasks.append(asyncio.create_task(self._stop_signal.wait()))
+ done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
+
+ for task in pending:
+ # (mostly) Graceful shutdown unfinished tasks
+ task.cancel()
+ with suppress(CancelledError):
+ await task
+ # Wait finished tasks to propagate unhandled exceptions
+ await asyncio.gather(*done)
+
+ finally:
+ loggers.dispatcher.info("Polling stopped")
+ try:
+ await self.emit_shutdown(bot=bots[-1], **workflow_data)
+ finally:
+ if close_bot_session:
+ await asyncio.gather(*(bot.session.close() for bot in bots))
+ self._stopped_signal.set()
+
+ def run_polling(
+ self,
+ *bots: Bot,
+ polling_timeout: int = 10,
+ handle_as_tasks: bool = True,
+ backoff_config: BackoffConfig = DEFAULT_BACKOFF_CONFIG,
+ allowed_updates: Optional[Union[List[str], UNSET_TYPE]] = UNSET,
+ handle_signals: bool = True,
+ close_bot_session: bool = True,
+ tasks_concurrency_limit: Optional[int] = None,
+ **kwargs: Any,
+ ) -> None:
+ """
+ Run many bots with polling
+
+ :param bots: Bot instances (one or more)
+ :param polling_timeout: Long-polling wait time
+ :param handle_as_tasks: Run task for each event and no wait result
+ :param backoff_config: backoff-retry config
+ :param allowed_updates: List of the update types you want your bot to receive
+ :param handle_signals: handle signals (SIGINT/SIGTERM)
+ :param close_bot_session: close bot sessions on shutdown
+ :param tasks_concurrency_limit: Maximum number of concurrent updates to process
+ (None = no limit), used only if handle_as_tasks is True
+ :param kwargs: contextual data
+ :return:
+ """
+ with suppress(KeyboardInterrupt):
+ return asyncio.run(
+ self.start_polling(
+ *bots,
+ **kwargs,
+ polling_timeout=polling_timeout,
+ handle_as_tasks=handle_as_tasks,
+ backoff_config=backoff_config,
+ allowed_updates=allowed_updates,
+ handle_signals=handle_signals,
+ close_bot_session=close_bot_session,
+ tasks_concurrency_limit=tasks_concurrency_limit,
+ )
+ )
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/event/__init__.py b/myenv/Lib/site-packages/aiogram/dispatcher/event/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/event/bases.py b/myenv/Lib/site-packages/aiogram/dispatcher/event/bases.py
new file mode 100644
index 0000000..1765683
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/event/bases.py
@@ -0,0 +1,35 @@
+from __future__ import annotations
+
+from typing import Any, Awaitable, Callable, Dict, NoReturn, Optional, TypeVar, Union
+from unittest.mock import sentinel
+
+from ...types import TelegramObject
+from ..middlewares.base import BaseMiddleware
+
+MiddlewareEventType = TypeVar("MiddlewareEventType", bound=TelegramObject)
+NextMiddlewareType = Callable[[MiddlewareEventType, Dict[str, Any]], Awaitable[Any]]
+MiddlewareType = Union[
+ BaseMiddleware,
+ Callable[
+ [NextMiddlewareType[MiddlewareEventType], MiddlewareEventType, Dict[str, Any]],
+ Awaitable[Any],
+ ],
+]
+
+UNHANDLED = sentinel.UNHANDLED
+REJECTED = sentinel.REJECTED
+
+
+class SkipHandler(Exception):
+ pass
+
+
+class CancelHandler(Exception):
+ pass
+
+
+def skip(message: Optional[str] = None) -> NoReturn:
+ """
+ Raise an SkipHandler
+ """
+ raise SkipHandler(message or "Event skipped")
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/event/event.py b/myenv/Lib/site-packages/aiogram/dispatcher/event/event.py
new file mode 100644
index 0000000..3cbcffe
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/event/event.py
@@ -0,0 +1,53 @@
+from __future__ import annotations
+
+from typing import Any, Callable, List
+
+from .handler import CallbackType, HandlerObject
+
+
+class EventObserver:
+ """
+ Simple events observer
+
+ Is used for managing events is not related with Telegram
+ (For example startup/shutdown processes)
+
+ Handlers can be registered via decorator or method
+
+ .. code-block:: python
+
+ .register(my_handler)
+
+ .. code-block:: python
+
+ @()
+ async def my_handler(*args, **kwargs): ...
+ """
+
+ def __init__(self) -> None:
+ self.handlers: List[HandlerObject] = []
+
+ def register(self, callback: CallbackType) -> None:
+ """
+ Register callback with filters
+ """
+ self.handlers.append(HandlerObject(callback=callback))
+
+ async def trigger(self, *args: Any, **kwargs: Any) -> None:
+ """
+ Propagate event to handlers.
+ Handler will be called when all its filters is pass.
+ """
+ for handler in self.handlers:
+ await handler.call(*args, **kwargs)
+
+ def __call__(self) -> Callable[[CallbackType], CallbackType]:
+ """
+ Decorator for registering event handlers
+ """
+
+ def wrapper(callback: CallbackType) -> CallbackType:
+ self.register(callback)
+ return callback
+
+ return wrapper
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/event/handler.py b/myenv/Lib/site-packages/aiogram/dispatcher/event/handler.py
new file mode 100644
index 0000000..b95cc96
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/event/handler.py
@@ -0,0 +1,95 @@
+import asyncio
+import contextvars
+import inspect
+import warnings
+from dataclasses import dataclass, field
+from functools import partial
+from typing import Any, Callable, Dict, List, Optional, Set, Tuple
+
+from magic_filter.magic import MagicFilter as OriginalMagicFilter
+
+from aiogram.dispatcher.flags import extract_flags_from_object
+from aiogram.filters.base import Filter
+from aiogram.handlers import BaseHandler
+from aiogram.utils.magic_filter import MagicFilter
+from aiogram.utils.warnings import Recommendation
+
+CallbackType = Callable[..., Any]
+
+
+@dataclass
+class CallableObject:
+ callback: CallbackType
+ awaitable: bool = field(init=False)
+ params: Set[str] = field(init=False)
+ varkw: bool = field(init=False)
+
+ def __post_init__(self) -> None:
+ callback = inspect.unwrap(self.callback)
+ self.awaitable = inspect.isawaitable(callback) or inspect.iscoroutinefunction(callback)
+ spec = inspect.getfullargspec(callback)
+ self.params = {*spec.args, *spec.kwonlyargs}
+ self.varkw = spec.varkw is not None
+
+ def _prepare_kwargs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
+ if self.varkw:
+ return kwargs
+
+ return {k: kwargs[k] for k in self.params if k in kwargs}
+
+ async def call(self, *args: Any, **kwargs: Any) -> Any:
+ wrapped = partial(self.callback, *args, **self._prepare_kwargs(kwargs))
+ if self.awaitable:
+ return await wrapped()
+ return await asyncio.to_thread(wrapped)
+
+
+@dataclass
+class FilterObject(CallableObject):
+ magic: Optional[MagicFilter] = None
+
+ def __post_init__(self) -> None:
+ if isinstance(self.callback, OriginalMagicFilter):
+ # MagicFilter instance is callable but generates
+ # only "CallOperation" instead of applying the filter
+ self.magic = self.callback
+ self.callback = self.callback.resolve
+ if not isinstance(self.magic, MagicFilter):
+ # Issue: https://github.com/aiogram/aiogram/issues/990
+ warnings.warn(
+ category=Recommendation,
+ message="You are using F provided by magic_filter package directly, "
+ "but it lacks `.as_()` extension."
+ "\n Please change the import statement: from `from magic_filter import F` "
+ "to `from aiogram import F` to silence this warning.",
+ stacklevel=6,
+ )
+
+ super(FilterObject, self).__post_init__()
+
+ if isinstance(self.callback, Filter):
+ self.awaitable = True
+
+
+@dataclass
+class HandlerObject(CallableObject):
+ filters: Optional[List[FilterObject]] = None
+ flags: Dict[str, Any] = field(default_factory=dict)
+
+ def __post_init__(self) -> None:
+ super(HandlerObject, self).__post_init__()
+ callback = inspect.unwrap(self.callback)
+ if inspect.isclass(callback) and issubclass(callback, BaseHandler):
+ self.awaitable = True
+ self.flags.update(extract_flags_from_object(callback))
+
+ async def check(self, *args: Any, **kwargs: Any) -> Tuple[bool, Dict[str, Any]]:
+ if not self.filters:
+ return True, kwargs
+ for event_filter in self.filters:
+ check = await event_filter.call(*args, **kwargs)
+ if not check:
+ return False, kwargs
+ if isinstance(check, dict):
+ kwargs.update(check)
+ return True, kwargs
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/event/telegram.py b/myenv/Lib/site-packages/aiogram/dispatcher/event/telegram.py
new file mode 100644
index 0000000..b0ed407
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/event/telegram.py
@@ -0,0 +1,141 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
+
+from aiogram.dispatcher.middlewares.manager import MiddlewareManager
+
+from ...exceptions import UnsupportedKeywordArgument
+from ...filters.base import Filter
+from ...types import TelegramObject
+from .bases import UNHANDLED, MiddlewareType, SkipHandler
+from .handler import CallbackType, FilterObject, HandlerObject
+
+if TYPE_CHECKING:
+ from aiogram.dispatcher.router import Router
+
+
+class TelegramEventObserver:
+ """
+ Event observer for Telegram events
+
+ Here you can register handler with filter.
+ This observer will stop event propagation when first handler is pass.
+ """
+
+ def __init__(self, router: Router, event_name: str) -> None:
+ self.router: Router = router
+ self.event_name: str = event_name
+
+ self.handlers: List[HandlerObject] = []
+
+ self.middleware = MiddlewareManager()
+ self.outer_middleware = MiddlewareManager()
+
+ # Re-used filters check method from already implemented handler object
+ # with dummy callback which never will be used
+ self._handler = HandlerObject(callback=lambda: True, filters=[])
+
+ def filter(self, *filters: CallbackType) -> None:
+ """
+ Register filter for all handlers of this event observer
+
+ :param filters: positional filters
+ """
+ if self._handler.filters is None:
+ self._handler.filters = []
+ self._handler.filters.extend([FilterObject(filter_) for filter_ in filters])
+
+ def _resolve_middlewares(self) -> List[MiddlewareType[TelegramObject]]:
+ middlewares: List[MiddlewareType[TelegramObject]] = []
+ for router in reversed(tuple(self.router.chain_head)):
+ observer = router.observers.get(self.event_name)
+ if observer:
+ middlewares.extend(observer.middleware)
+
+ return middlewares
+
+ def register(
+ self,
+ callback: CallbackType,
+ *filters: CallbackType,
+ flags: Optional[Dict[str, Any]] = None,
+ **kwargs: Any,
+ ) -> CallbackType:
+ """
+ Register event handler
+ """
+ if kwargs:
+ raise UnsupportedKeywordArgument(
+ "Passing any additional keyword arguments to the registrar method "
+ "is not supported.\n"
+ "This error may be caused when you are trying to register filters like in 2.x "
+ "version of this framework, if it's true just look at correspoding "
+ "documentation pages.\n"
+ f"Please remove the {set(kwargs.keys())} arguments from this call.\n"
+ )
+
+ if flags is None:
+ flags = {}
+
+ for item in filters:
+ if isinstance(item, Filter):
+ item.update_handler_flags(flags=flags)
+
+ self.handlers.append(
+ HandlerObject(
+ callback=callback,
+ filters=[FilterObject(filter_) for filter_ in filters],
+ flags=flags,
+ )
+ )
+
+ return callback
+
+ def wrap_outer_middleware(
+ self, callback: Any, event: TelegramObject, data: Dict[str, Any]
+ ) -> Any:
+ wrapped_outer = self.middleware.wrap_middlewares(
+ self.outer_middleware,
+ callback,
+ )
+ return wrapped_outer(event, data)
+
+ def check_root_filters(self, event: TelegramObject, **kwargs: Any) -> Any:
+ return self._handler.check(event, **kwargs)
+
+ async def trigger(self, event: TelegramObject, **kwargs: Any) -> Any:
+ """
+ Propagate event to handlers and stops propagation on first match.
+ Handler will be called when all its filters are pass.
+ """
+ for handler in self.handlers:
+ kwargs["handler"] = handler
+ result, data = await handler.check(event, **kwargs)
+ if result:
+ kwargs.update(data)
+ try:
+ wrapped_inner = self.outer_middleware.wrap_middlewares(
+ self._resolve_middlewares(),
+ handler.call,
+ )
+ return await wrapped_inner(event, kwargs)
+ except SkipHandler:
+ continue
+
+ return UNHANDLED
+
+ def __call__(
+ self,
+ *filters: CallbackType,
+ flags: Optional[Dict[str, Any]] = None,
+ **kwargs: Any,
+ ) -> Callable[[CallbackType], CallbackType]:
+ """
+ Decorator for registering event handlers
+ """
+
+ def wrapper(callback: CallbackType) -> CallbackType:
+ self.register(callback, *filters, flags=flags, **kwargs)
+ return callback
+
+ return wrapper
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/flags.py b/myenv/Lib/site-packages/aiogram/dispatcher/flags.py
new file mode 100644
index 0000000..aad8a29
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/flags.py
@@ -0,0 +1,127 @@
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union, cast, overload
+
+from magic_filter import AttrDict, MagicFilter
+
+if TYPE_CHECKING:
+ from aiogram.dispatcher.event.handler import HandlerObject
+
+
+@dataclass(frozen=True)
+class Flag:
+ name: str
+ value: Any
+
+
+@dataclass(frozen=True)
+class FlagDecorator:
+ flag: Flag
+
+ @classmethod
+ def _with_flag(cls, flag: Flag) -> "FlagDecorator":
+ return cls(flag)
+
+ def _with_value(self, value: Any) -> "FlagDecorator":
+ new_flag = Flag(self.flag.name, value)
+ return self._with_flag(new_flag)
+
+ @overload
+ def __call__(self, value: Callable[..., Any], /) -> Callable[..., Any]: # type: ignore
+ pass
+
+ @overload
+ def __call__(self, value: Any, /) -> "FlagDecorator":
+ pass
+
+ @overload
+ def __call__(self, **kwargs: Any) -> "FlagDecorator":
+ pass
+
+ def __call__(
+ self,
+ value: Optional[Any] = None,
+ **kwargs: Any,
+ ) -> Union[Callable[..., Any], "FlagDecorator"]:
+ if value and kwargs:
+ raise ValueError("The arguments `value` and **kwargs can not be used together")
+
+ if value is not None and callable(value):
+ value.aiogram_flag = {
+ **extract_flags_from_object(value),
+ self.flag.name: self.flag.value,
+ }
+ return cast(Callable[..., Any], value)
+ return self._with_value(AttrDict(kwargs) if value is None else value)
+
+
+if TYPE_CHECKING:
+
+ class _ChatActionFlagProtocol(FlagDecorator):
+ def __call__( # type: ignore[override]
+ self,
+ action: str = ...,
+ interval: float = ...,
+ initial_sleep: float = ...,
+ **kwargs: Any,
+ ) -> FlagDecorator:
+ pass
+
+
+class FlagGenerator:
+ def __getattr__(self, name: str) -> FlagDecorator:
+ if name[0] == "_":
+ raise AttributeError("Flag name must NOT start with underscore")
+ return FlagDecorator(Flag(name, True))
+
+ if TYPE_CHECKING:
+ chat_action: _ChatActionFlagProtocol
+
+
+def extract_flags_from_object(obj: Any) -> Dict[str, Any]:
+ if not hasattr(obj, "aiogram_flag"):
+ return {}
+ return cast(Dict[str, Any], obj.aiogram_flag)
+
+
+def extract_flags(handler: Union["HandlerObject", Dict[str, Any]]) -> Dict[str, Any]:
+ """
+ Extract flags from handler or middleware context data
+
+ :param handler: handler object or data
+ :return: dictionary with all handler flags
+ """
+ if isinstance(handler, dict) and "handler" in handler:
+ handler = handler["handler"]
+ if hasattr(handler, "flags"):
+ return handler.flags
+ return {}
+
+
+def get_flag(
+ handler: Union["HandlerObject", Dict[str, Any]],
+ name: str,
+ *,
+ default: Optional[Any] = None,
+) -> Any:
+ """
+ Get flag by name
+
+ :param handler: handler object or data
+ :param name: name of the flag
+ :param default: default value (None)
+ :return: value of the flag or default
+ """
+ flags = extract_flags(handler)
+ return flags.get(name, default)
+
+
+def check_flags(handler: Union["HandlerObject", Dict[str, Any]], magic: MagicFilter) -> Any:
+ """
+ Check flags via magic filter
+
+ :param handler: handler object or data
+ :param magic: instance of the magic
+ :return: the result of magic filter check
+ """
+ flags = extract_flags(handler)
+ return magic.resolve(AttrDict(flags))
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/__init__.py b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/base.py b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/base.py
new file mode 100644
index 0000000..15b0b4a
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/base.py
@@ -0,0 +1,29 @@
+from abc import ABC, abstractmethod
+from typing import Any, Awaitable, Callable, Dict, TypeVar
+
+from aiogram.types import TelegramObject
+
+T = TypeVar("T")
+
+
+class BaseMiddleware(ABC):
+ """
+ Generic middleware class
+ """
+
+ @abstractmethod
+ async def __call__(
+ self,
+ handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
+ event: TelegramObject,
+ data: Dict[str, Any],
+ ) -> Any: # pragma: no cover
+ """
+ Execute middleware
+
+ :param handler: Wrapped handler in middlewares chain
+ :param event: Incoming event (Subclass of :class:`aiogram.types.base.TelegramObject`)
+ :param data: Contextual data. Will be mapped to handler arguments
+ :return: :class:`Any`
+ """
+ pass
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/data.py b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/data.py
new file mode 100644
index 0000000..c13797f
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/data.py
@@ -0,0 +1,97 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, TypedDict
+
+from typing_extensions import NotRequired
+
+if TYPE_CHECKING:
+ from aiogram import Bot, Dispatcher, Router
+ from aiogram.dispatcher.event.handler import HandlerObject
+ from aiogram.dispatcher.middlewares.user_context import EventContext
+ from aiogram.fsm.context import FSMContext
+ from aiogram.fsm.storage.base import BaseStorage
+ from aiogram.types import Chat, Update, User
+ from aiogram.utils.i18n import I18n, I18nMiddleware
+
+
+class DispatcherData(TypedDict, total=False):
+ """
+ Dispatcher and bot related data.
+ """
+
+ dispatcher: Dispatcher
+ """Instance of the Dispatcher from which the handler was called."""
+ bot: Bot
+ """Bot that received the update."""
+ bots: NotRequired[list[Bot]]
+ """List of all bots in the Dispatcher. Used only in polling mode."""
+ event_update: Update
+ """Update object that triggered the handler."""
+ event_router: Router
+ """Router that was used to find the handler."""
+ handler: NotRequired[HandlerObject]
+ """Handler object that was called.
+ Available only in the handler itself and inner middlewares."""
+
+
+class UserContextData(TypedDict, total=False):
+ """
+ Event context related data about user and chat.
+ """
+
+ event_context: EventContext
+ """Event context object that contains user and chat data."""
+ event_from_user: NotRequired[User]
+ """User object that triggered the handler."""
+ event_chat: NotRequired[Chat]
+ """Chat object that triggered the handler.
+ .. deprecated:: 3.5.0
+ Use :attr:`event_context.chat` instead."""
+ event_thread_id: NotRequired[int]
+ """Thread ID of the chat that triggered the handler.
+ .. deprecated:: 3.5.0
+ Use :attr:`event_context.chat` instead."""
+ event_business_connection_id: NotRequired[str]
+ """Business connection ID of the chat that triggered the handler.
+ .. deprecated:: 3.5.0
+ Use :attr:`event_context.business_connection_id` instead."""
+
+
+class FSMData(TypedDict, total=False):
+ """
+ FSM related data.
+ """
+
+ fsm_storage: BaseStorage
+ """Storage used for FSM."""
+ state: NotRequired[FSMContext]
+ """Current state of the FSM."""
+ raw_state: NotRequired[str | None]
+ """Raw state of the FSM."""
+
+
+class I18nData(TypedDict, total=False):
+ """
+ I18n related data.
+
+ Is not included by default, you need to add it to your own Data class if you need it.
+ """
+
+ i18n: I18n
+ """I18n object."""
+ i18n_middleware: I18nMiddleware
+ """I18n middleware."""
+
+
+class MiddlewareData(
+ DispatcherData,
+ UserContextData,
+ FSMData,
+ # I18nData, # Disabled by default, add it if you need it to your own Data class.
+ total=False,
+):
+ """
+ Data passed to the handler by the middlewares.
+
+ You can add your own data by extending this class.
+ """
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/error.py b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/error.py
new file mode 100644
index 0000000..4b68c0b
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/error.py
@@ -0,0 +1,36 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, cast
+
+from ...types import TelegramObject, Update
+from ...types.error_event import ErrorEvent
+from ..event.bases import UNHANDLED, CancelHandler, SkipHandler
+from .base import BaseMiddleware
+
+if TYPE_CHECKING:
+ from ..router import Router
+
+
+class ErrorsMiddleware(BaseMiddleware):
+ def __init__(self, router: Router):
+ self.router = router
+
+ async def __call__(
+ self,
+ handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
+ event: TelegramObject,
+ data: Dict[str, Any],
+ ) -> Any:
+ try:
+ return await handler(event, data)
+ except (SkipHandler, CancelHandler): # pragma: no cover
+ raise
+ except Exception as e:
+ response = await self.router.propagate_event(
+ update_type="error",
+ event=ErrorEvent(update=cast(Update, event), exception=e),
+ **data,
+ )
+ if response is not UNHANDLED:
+ return response
+ raise
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/manager.py b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/manager.py
new file mode 100644
index 0000000..bcad4de
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/manager.py
@@ -0,0 +1,65 @@
+import functools
+from typing import Any, Callable, Dict, List, Optional, Sequence, Union, overload
+
+from aiogram.dispatcher.event.bases import (
+ MiddlewareEventType,
+ MiddlewareType,
+ NextMiddlewareType,
+)
+from aiogram.dispatcher.event.handler import CallbackType
+from aiogram.types import TelegramObject
+
+
+class MiddlewareManager(Sequence[MiddlewareType[TelegramObject]]):
+ def __init__(self) -> None:
+ self._middlewares: List[MiddlewareType[TelegramObject]] = []
+
+ def register(
+ self,
+ middleware: MiddlewareType[TelegramObject],
+ ) -> MiddlewareType[TelegramObject]:
+ self._middlewares.append(middleware)
+ return middleware
+
+ def unregister(self, middleware: MiddlewareType[TelegramObject]) -> None:
+ self._middlewares.remove(middleware)
+
+ def __call__(
+ self,
+ middleware: Optional[MiddlewareType[TelegramObject]] = None,
+ ) -> Union[
+ Callable[[MiddlewareType[TelegramObject]], MiddlewareType[TelegramObject]],
+ MiddlewareType[TelegramObject],
+ ]:
+ if middleware is None:
+ return self.register
+ return self.register(middleware)
+
+ @overload
+ def __getitem__(self, item: int) -> MiddlewareType[TelegramObject]:
+ pass
+
+ @overload
+ def __getitem__(self, item: slice) -> Sequence[MiddlewareType[TelegramObject]]:
+ pass
+
+ def __getitem__(
+ self, item: Union[int, slice]
+ ) -> Union[MiddlewareType[TelegramObject], Sequence[MiddlewareType[TelegramObject]]]:
+ return self._middlewares[item]
+
+ def __len__(self) -> int:
+ return len(self._middlewares)
+
+ @staticmethod
+ def wrap_middlewares(
+ middlewares: Sequence[MiddlewareType[MiddlewareEventType]], handler: CallbackType
+ ) -> NextMiddlewareType[MiddlewareEventType]:
+ @functools.wraps(handler)
+ def handler_wrapper(event: TelegramObject, kwargs: Dict[str, Any]) -> Any:
+ return handler(event, **kwargs)
+
+ middleware = handler_wrapper
+ for m in reversed(middlewares):
+ middleware = functools.partial(m, middleware) # type: ignore[assignment]
+ return middleware
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/user_context.py b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/user_context.py
new file mode 100644
index 0000000..68e4b4a
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/middlewares/user_context.py
@@ -0,0 +1,182 @@
+from dataclasses import dataclass
+from typing import Any, Awaitable, Callable, Dict, Optional
+
+from aiogram.dispatcher.middlewares.base import BaseMiddleware
+from aiogram.types import (
+ Chat,
+ ChatBoostSourcePremium,
+ InaccessibleMessage,
+ TelegramObject,
+ Update,
+ User,
+)
+
+EVENT_CONTEXT_KEY = "event_context"
+
+EVENT_FROM_USER_KEY = "event_from_user"
+EVENT_CHAT_KEY = "event_chat"
+EVENT_THREAD_ID_KEY = "event_thread_id"
+
+
+@dataclass(frozen=True)
+class EventContext:
+ chat: Optional[Chat] = None
+ user: Optional[User] = None
+ thread_id: Optional[int] = None
+ business_connection_id: Optional[str] = None
+
+ @property
+ def user_id(self) -> Optional[int]:
+ return self.user.id if self.user else None
+
+ @property
+ def chat_id(self) -> Optional[int]:
+ return self.chat.id if self.chat else None
+
+
+class UserContextMiddleware(BaseMiddleware):
+ async def __call__(
+ self,
+ handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
+ event: TelegramObject,
+ data: Dict[str, Any],
+ ) -> Any:
+ if not isinstance(event, Update):
+ raise RuntimeError("UserContextMiddleware got an unexpected event type!")
+ event_context = data[EVENT_CONTEXT_KEY] = self.resolve_event_context(event=event)
+
+ # Backward compatibility
+ if event_context.user is not None:
+ data[EVENT_FROM_USER_KEY] = event_context.user
+ if event_context.chat is not None:
+ data[EVENT_CHAT_KEY] = event_context.chat
+ if event_context.thread_id is not None:
+ data[EVENT_THREAD_ID_KEY] = event_context.thread_id
+
+ return await handler(event, data)
+
+ @classmethod
+ def resolve_event_context(cls, event: Update) -> EventContext:
+ """
+ Resolve chat and user instance from Update object
+ """
+ if event.message:
+ return EventContext(
+ chat=event.message.chat,
+ user=event.message.from_user,
+ thread_id=(
+ event.message.message_thread_id if event.message.is_topic_message else None
+ ),
+ )
+ if event.edited_message:
+ return EventContext(
+ chat=event.edited_message.chat,
+ user=event.edited_message.from_user,
+ thread_id=(
+ event.edited_message.message_thread_id
+ if event.edited_message.is_topic_message
+ else None
+ ),
+ )
+ if event.channel_post:
+ return EventContext(chat=event.channel_post.chat)
+ if event.edited_channel_post:
+ return EventContext(chat=event.edited_channel_post.chat)
+ if event.inline_query:
+ return EventContext(user=event.inline_query.from_user)
+ if event.chosen_inline_result:
+ return EventContext(user=event.chosen_inline_result.from_user)
+ if event.callback_query:
+ callback_query_message = event.callback_query.message
+ if callback_query_message:
+ return EventContext(
+ chat=callback_query_message.chat,
+ user=event.callback_query.from_user,
+ thread_id=(
+ callback_query_message.message_thread_id
+ if not isinstance(callback_query_message, InaccessibleMessage)
+ and callback_query_message.is_topic_message
+ else None
+ ),
+ business_connection_id=(
+ callback_query_message.business_connection_id
+ if not isinstance(callback_query_message, InaccessibleMessage)
+ else None
+ ),
+ )
+ return EventContext(user=event.callback_query.from_user)
+ if event.shipping_query:
+ return EventContext(user=event.shipping_query.from_user)
+ if event.pre_checkout_query:
+ return EventContext(user=event.pre_checkout_query.from_user)
+ if event.poll_answer:
+ return EventContext(
+ chat=event.poll_answer.voter_chat,
+ user=event.poll_answer.user,
+ )
+ if event.my_chat_member:
+ return EventContext(
+ chat=event.my_chat_member.chat, user=event.my_chat_member.from_user
+ )
+ if event.chat_member:
+ return EventContext(chat=event.chat_member.chat, user=event.chat_member.from_user)
+ if event.chat_join_request:
+ return EventContext(
+ chat=event.chat_join_request.chat, user=event.chat_join_request.from_user
+ )
+ if event.message_reaction:
+ return EventContext(
+ chat=event.message_reaction.chat,
+ user=event.message_reaction.user,
+ )
+ if event.message_reaction_count:
+ return EventContext(chat=event.message_reaction_count.chat)
+ if event.chat_boost:
+ # We only check the premium source, because only it has a sender user,
+ # other sources have a user, but it is not the sender, but the recipient
+ if isinstance(event.chat_boost.boost.source, ChatBoostSourcePremium):
+ return EventContext(
+ chat=event.chat_boost.chat,
+ user=event.chat_boost.boost.source.user,
+ )
+
+ return EventContext(chat=event.chat_boost.chat)
+ if event.removed_chat_boost:
+ return EventContext(chat=event.removed_chat_boost.chat)
+ if event.deleted_business_messages:
+ return EventContext(
+ chat=event.deleted_business_messages.chat,
+ business_connection_id=event.deleted_business_messages.business_connection_id,
+ )
+ if event.business_connection:
+ return EventContext(
+ user=event.business_connection.user,
+ business_connection_id=event.business_connection.id,
+ )
+ if event.business_message:
+ return EventContext(
+ chat=event.business_message.chat,
+ user=event.business_message.from_user,
+ thread_id=(
+ event.business_message.message_thread_id
+ if event.business_message.is_topic_message
+ else None
+ ),
+ business_connection_id=event.business_message.business_connection_id,
+ )
+ if event.edited_business_message:
+ return EventContext(
+ chat=event.edited_business_message.chat,
+ user=event.edited_business_message.from_user,
+ thread_id=(
+ event.edited_business_message.message_thread_id
+ if event.edited_business_message.is_topic_message
+ else None
+ ),
+ business_connection_id=event.edited_business_message.business_connection_id,
+ )
+ if event.purchased_paid_media:
+ return EventContext(
+ user=event.purchased_paid_media.from_user,
+ )
+ return EventContext()
diff --git a/myenv/Lib/site-packages/aiogram/dispatcher/router.py b/myenv/Lib/site-packages/aiogram/dispatcher/router.py
new file mode 100644
index 0000000..9a2796b
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/dispatcher/router.py
@@ -0,0 +1,275 @@
+from __future__ import annotations
+
+from typing import Any, Dict, Final, Generator, List, Optional, Set
+
+from ..types import TelegramObject
+from .event.bases import REJECTED, UNHANDLED
+from .event.event import EventObserver
+from .event.telegram import TelegramEventObserver
+
+INTERNAL_UPDATE_TYPES: Final[frozenset[str]] = frozenset({"update", "error"})
+
+
+class Router:
+ """
+ Router can route update, and it nested update types like messages, callback query,
+ polls and all other event types.
+
+ Event handlers can be registered in observer by two ways:
+
+ - By observer method - :obj:`router..register(handler, )`
+ - By decorator - :obj:`@router.()`
+ """
+
+ def __init__(self, *, name: Optional[str] = None) -> None:
+ """
+ :param name: Optional router name, can be useful for debugging
+ """
+
+ self.name = name or hex(id(self))
+
+ self._parent_router: Optional[Router] = None
+ self.sub_routers: List[Router] = []
+
+ # Observers
+ self.message = TelegramEventObserver(router=self, event_name="message")
+ self.edited_message = TelegramEventObserver(router=self, event_name="edited_message")
+ self.channel_post = TelegramEventObserver(router=self, event_name="channel_post")
+ self.edited_channel_post = TelegramEventObserver(
+ router=self, event_name="edited_channel_post"
+ )
+ self.inline_query = TelegramEventObserver(router=self, event_name="inline_query")
+ self.chosen_inline_result = TelegramEventObserver(
+ router=self, event_name="chosen_inline_result"
+ )
+ self.callback_query = TelegramEventObserver(router=self, event_name="callback_query")
+ self.shipping_query = TelegramEventObserver(router=self, event_name="shipping_query")
+ self.pre_checkout_query = TelegramEventObserver(
+ router=self, event_name="pre_checkout_query"
+ )
+ self.poll = TelegramEventObserver(router=self, event_name="poll")
+ self.poll_answer = TelegramEventObserver(router=self, event_name="poll_answer")
+ self.my_chat_member = TelegramEventObserver(router=self, event_name="my_chat_member")
+ self.chat_member = TelegramEventObserver(router=self, event_name="chat_member")
+ self.chat_join_request = TelegramEventObserver(router=self, event_name="chat_join_request")
+ self.message_reaction = TelegramEventObserver(router=self, event_name="message_reaction")
+ self.message_reaction_count = TelegramEventObserver(
+ router=self, event_name="message_reaction_count"
+ )
+ self.chat_boost = TelegramEventObserver(router=self, event_name="chat_boost")
+ self.removed_chat_boost = TelegramEventObserver(
+ router=self, event_name="removed_chat_boost"
+ )
+ self.deleted_business_messages = TelegramEventObserver(
+ router=self, event_name="deleted_business_messages"
+ )
+ self.business_connection = TelegramEventObserver(
+ router=self, event_name="business_connection"
+ )
+ self.edited_business_message = TelegramEventObserver(
+ router=self, event_name="edited_business_message"
+ )
+ self.business_message = TelegramEventObserver(router=self, event_name="business_message")
+ self.purchased_paid_media = TelegramEventObserver(
+ router=self, event_name="purchased_paid_media"
+ )
+
+ self.errors = self.error = TelegramEventObserver(router=self, event_name="error")
+
+ self.startup = EventObserver()
+ self.shutdown = EventObserver()
+
+ self.observers: Dict[str, TelegramEventObserver] = {
+ "message": self.message,
+ "edited_message": self.edited_message,
+ "channel_post": self.channel_post,
+ "edited_channel_post": self.edited_channel_post,
+ "inline_query": self.inline_query,
+ "chosen_inline_result": self.chosen_inline_result,
+ "callback_query": self.callback_query,
+ "shipping_query": self.shipping_query,
+ "pre_checkout_query": self.pre_checkout_query,
+ "poll": self.poll,
+ "poll_answer": self.poll_answer,
+ "my_chat_member": self.my_chat_member,
+ "chat_member": self.chat_member,
+ "chat_join_request": self.chat_join_request,
+ "message_reaction": self.message_reaction,
+ "message_reaction_count": self.message_reaction_count,
+ "chat_boost": self.chat_boost,
+ "removed_chat_boost": self.removed_chat_boost,
+ "deleted_business_messages": self.deleted_business_messages,
+ "business_connection": self.business_connection,
+ "edited_business_message": self.edited_business_message,
+ "business_message": self.business_message,
+ "purchased_paid_media": self.purchased_paid_media,
+ "error": self.errors,
+ }
+
+ def __str__(self) -> str:
+ return f"{type(self).__name__} {self.name!r}"
+
+ def __repr__(self) -> str:
+ return f"<{self}>"
+
+ def resolve_used_update_types(self, skip_events: Optional[Set[str]] = None) -> List[str]:
+ """
+ Resolve registered event names
+
+ Is useful for getting updates only for registered event types.
+
+ :param skip_events: skip specified event names
+ :return: set of registered names
+ """
+ handlers_in_use: Set[str] = set()
+ if skip_events is None:
+ skip_events = set()
+ skip_events = {*skip_events, *INTERNAL_UPDATE_TYPES}
+
+ for router in self.chain_tail:
+ for update_name, observer in router.observers.items():
+ if observer.handlers and update_name not in skip_events:
+ handlers_in_use.add(update_name)
+
+ return list(sorted(handlers_in_use)) # NOQA: C413
+
+ async def propagate_event(self, update_type: str, event: TelegramObject, **kwargs: Any) -> Any:
+ kwargs.update(event_router=self)
+ observer = self.observers.get(update_type)
+
+ async def _wrapped(telegram_event: TelegramObject, **data: Any) -> Any:
+ return await self._propagate_event(
+ observer=observer, update_type=update_type, event=telegram_event, **data
+ )
+
+ if observer:
+ return await observer.wrap_outer_middleware(_wrapped, event=event, data=kwargs)
+ return await _wrapped(event, **kwargs)
+
+ async def _propagate_event(
+ self,
+ observer: Optional[TelegramEventObserver],
+ update_type: str,
+ event: TelegramObject,
+ **kwargs: Any,
+ ) -> Any:
+ response = UNHANDLED
+ if observer:
+ # Check globally defined filters before any other handler will be checked.
+ # This check is placed here instead of `trigger` method to add possibility
+ # to pass context to handlers from global filters.
+ result, data = await observer.check_root_filters(event, **kwargs)
+ if not result:
+ return UNHANDLED
+ kwargs.update(data)
+
+ response = await observer.trigger(event, **kwargs)
+ if response is REJECTED: # pragma: no cover
+ # Possible only if some handler returns REJECTED
+ return UNHANDLED
+ if response is not UNHANDLED:
+ return response
+
+ for router in self.sub_routers:
+ response = await router.propagate_event(update_type=update_type, event=event, **kwargs)
+ if response is not UNHANDLED:
+ break
+
+ return response
+
+ @property
+ def chain_head(self) -> Generator[Router, None, None]:
+ router: Optional[Router] = self
+ while router:
+ yield router
+ router = router.parent_router
+
+ @property
+ def chain_tail(self) -> Generator[Router, None, None]:
+ yield self
+ for router in self.sub_routers:
+ yield from router.chain_tail
+
+ @property
+ def parent_router(self) -> Optional[Router]:
+ return self._parent_router
+
+ @parent_router.setter
+ def parent_router(self, router: Router) -> None:
+ """
+ Internal property setter of parent router fot this router.
+ Do not use this method in own code.
+ All routers should be included via `include_router` method.
+
+ Self- and circular- referencing are not allowed here
+
+ :param router:
+ """
+ if not isinstance(router, Router):
+ raise ValueError(f"router should be instance of Router not {type(router).__name__!r}")
+ if self._parent_router:
+ raise RuntimeError(f"Router is already attached to {self._parent_router!r}")
+ if self == router:
+ raise RuntimeError("Self-referencing routers is not allowed")
+
+ parent: Optional[Router] = router
+ while parent is not None:
+ if parent == self:
+ raise RuntimeError("Circular referencing of Router is not allowed")
+
+ parent = parent.parent_router
+
+ self._parent_router = router
+ router.sub_routers.append(self)
+
+ def include_routers(self, *routers: Router) -> None:
+ """
+ Attach multiple routers.
+
+ :param routers:
+ :return:
+ """
+ if not routers:
+ raise ValueError("At least one router must be provided")
+ for router in routers:
+ self.include_router(router)
+
+ def include_router(self, router: Router) -> Router:
+ """
+ Attach another router.
+
+ :param router:
+ :return:
+ """
+ if not isinstance(router, Router):
+ raise ValueError(
+ f"router should be instance of Router not {type(router).__class__.__name__}"
+ )
+ router.parent_router = self
+ return router
+
+ async def emit_startup(self, *args: Any, **kwargs: Any) -> None:
+ """
+ Recursively call startup callbacks
+
+ :param args:
+ :param kwargs:
+ :return:
+ """
+ kwargs.update(router=self)
+ await self.startup.trigger(*args, **kwargs)
+ for router in self.sub_routers:
+ await router.emit_startup(*args, **kwargs)
+
+ async def emit_shutdown(self, *args: Any, **kwargs: Any) -> None:
+ """
+ Recursively call shutdown callbacks to graceful shutdown
+
+ :param args:
+ :param kwargs:
+ :return:
+ """
+ kwargs.update(router=self)
+ await self.shutdown.trigger(*args, **kwargs)
+ for router in self.sub_routers:
+ await router.emit_shutdown(*args, **kwargs)
diff --git a/myenv/Lib/site-packages/aiogram/enums/__init__.py b/myenv/Lib/site-packages/aiogram/enums/__init__.py
new file mode 100644
index 0000000..aa9d6b4
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/__init__.py
@@ -0,0 +1,71 @@
+from .bot_command_scope_type import BotCommandScopeType
+from .chat_action import ChatAction
+from .chat_boost_source_type import ChatBoostSourceType
+from .chat_member_status import ChatMemberStatus
+from .chat_type import ChatType
+from .content_type import ContentType
+from .currency import Currency
+from .dice_emoji import DiceEmoji
+from .encrypted_passport_element import EncryptedPassportElement
+from .inline_query_result_type import InlineQueryResultType
+from .input_media_type import InputMediaType
+from .input_paid_media_type import InputPaidMediaType
+from .input_profile_photo_type import InputProfilePhotoType
+from .input_story_content_type import InputStoryContentType
+from .keyboard_button_poll_type_type import KeyboardButtonPollTypeType
+from .mask_position_point import MaskPositionPoint
+from .menu_button_type import MenuButtonType
+from .message_entity_type import MessageEntityType
+from .message_origin_type import MessageOriginType
+from .owned_gift_type import OwnedGiftType
+from .paid_media_type import PaidMediaType
+from .parse_mode import ParseMode
+from .passport_element_error_type import PassportElementErrorType
+from .poll_type import PollType
+from .reaction_type_type import ReactionTypeType
+from .revenue_withdrawal_state_type import RevenueWithdrawalStateType
+from .sticker_format import StickerFormat
+from .sticker_type import StickerType
+from .story_area_type_type import StoryAreaTypeType
+from .topic_icon_color import TopicIconColor
+from .transaction_partner_type import TransactionPartnerType
+from .transaction_partner_user_transaction_type_enum import (
+ TransactionPartnerUserTransactionTypeEnum,
+)
+from .update_type import UpdateType
+
+__all__ = (
+ "BotCommandScopeType",
+ "ChatAction",
+ "ChatBoostSourceType",
+ "ChatMemberStatus",
+ "ChatType",
+ "ContentType",
+ "Currency",
+ "DiceEmoji",
+ "EncryptedPassportElement",
+ "InlineQueryResultType",
+ "InputMediaType",
+ "InputPaidMediaType",
+ "InputProfilePhotoType",
+ "InputStoryContentType",
+ "KeyboardButtonPollTypeType",
+ "MaskPositionPoint",
+ "MenuButtonType",
+ "MessageEntityType",
+ "MessageOriginType",
+ "OwnedGiftType",
+ "PaidMediaType",
+ "ParseMode",
+ "PassportElementErrorType",
+ "PollType",
+ "ReactionTypeType",
+ "RevenueWithdrawalStateType",
+ "StickerFormat",
+ "StickerType",
+ "StoryAreaTypeType",
+ "TopicIconColor",
+ "TransactionPartnerType",
+ "TransactionPartnerUserTransactionTypeEnum",
+ "UpdateType",
+)
diff --git a/myenv/Lib/site-packages/aiogram/enums/bot_command_scope_type.py b/myenv/Lib/site-packages/aiogram/enums/bot_command_scope_type.py
new file mode 100644
index 0000000..f099431
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/bot_command_scope_type.py
@@ -0,0 +1,17 @@
+from enum import Enum
+
+
+class BotCommandScopeType(str, Enum):
+ """
+ This object represents the scope to which bot commands are applied.
+
+ Source: https://core.telegram.org/bots/api#botcommandscope
+ """
+
+ DEFAULT = "default"
+ ALL_PRIVATE_CHATS = "all_private_chats"
+ ALL_GROUP_CHATS = "all_group_chats"
+ ALL_CHAT_ADMINISTRATORS = "all_chat_administrators"
+ CHAT = "chat"
+ CHAT_ADMINISTRATORS = "chat_administrators"
+ CHAT_MEMBER = "chat_member"
diff --git a/myenv/Lib/site-packages/aiogram/enums/chat_action.py b/myenv/Lib/site-packages/aiogram/enums/chat_action.py
new file mode 100644
index 0000000..4402b5b
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/chat_action.py
@@ -0,0 +1,32 @@
+from enum import Enum
+
+
+class ChatAction(str, Enum):
+ """
+ This object represents bot actions.
+
+ Choose one, depending on what the user is about to receive:
+
+ - typing for text messages,
+ - upload_photo for photos,
+ - record_video or upload_video for videos,
+ - record_voice or upload_voice for voice notes,
+ - upload_document for general files,
+ - choose_sticker for stickers,
+ - find_location for location data,
+ - record_video_note or upload_video_note for video notes.
+
+ Source: https://core.telegram.org/bots/api#sendchataction
+ """
+
+ TYPING = "typing"
+ UPLOAD_PHOTO = "upload_photo"
+ RECORD_VIDEO = "record_video"
+ UPLOAD_VIDEO = "upload_video"
+ RECORD_VOICE = "record_voice"
+ UPLOAD_VOICE = "upload_voice"
+ UPLOAD_DOCUMENT = "upload_document"
+ CHOOSE_STICKER = "choose_sticker"
+ FIND_LOCATION = "find_location"
+ RECORD_VIDEO_NOTE = "record_video_note"
+ UPLOAD_VIDEO_NOTE = "upload_video_note"
diff --git a/myenv/Lib/site-packages/aiogram/enums/chat_boost_source_type.py b/myenv/Lib/site-packages/aiogram/enums/chat_boost_source_type.py
new file mode 100644
index 0000000..c95c31d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/chat_boost_source_type.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class ChatBoostSourceType(str, Enum):
+ """
+ This object represents a type of chat boost source.
+
+ Source: https://core.telegram.org/bots/api#chatboostsource
+ """
+
+ PREMIUM = "premium"
+ GIFT_CODE = "gift_code"
+ GIVEAWAY = "giveaway"
diff --git a/myenv/Lib/site-packages/aiogram/enums/chat_member_status.py b/myenv/Lib/site-packages/aiogram/enums/chat_member_status.py
new file mode 100644
index 0000000..db6f921
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/chat_member_status.py
@@ -0,0 +1,16 @@
+from enum import Enum
+
+
+class ChatMemberStatus(str, Enum):
+ """
+ This object represents chat member status.
+
+ Source: https://core.telegram.org/bots/api#chatmember
+ """
+
+ CREATOR = "creator"
+ ADMINISTRATOR = "administrator"
+ MEMBER = "member"
+ RESTRICTED = "restricted"
+ LEFT = "left"
+ KICKED = "kicked"
diff --git a/myenv/Lib/site-packages/aiogram/enums/chat_type.py b/myenv/Lib/site-packages/aiogram/enums/chat_type.py
new file mode 100644
index 0000000..10dccc8
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/chat_type.py
@@ -0,0 +1,15 @@
+from enum import Enum
+
+
+class ChatType(str, Enum):
+ """
+ This object represents a chat type
+
+ Source: https://core.telegram.org/bots/api#chat
+ """
+
+ SENDER = "sender"
+ PRIVATE = "private"
+ GROUP = "group"
+ SUPERGROUP = "supergroup"
+ CHANNEL = "channel"
diff --git a/myenv/Lib/site-packages/aiogram/enums/content_type.py b/myenv/Lib/site-packages/aiogram/enums/content_type.py
new file mode 100644
index 0000000..96472c4
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/content_type.py
@@ -0,0 +1,69 @@
+from enum import Enum
+
+
+class ContentType(str, Enum):
+ """
+ This object represents a type of content in message
+ """
+
+ UNKNOWN = "unknown"
+ ANY = "any"
+ TEXT = "text"
+ ANIMATION = "animation"
+ AUDIO = "audio"
+ DOCUMENT = "document"
+ PAID_MEDIA = "paid_media"
+ PHOTO = "photo"
+ STICKER = "sticker"
+ STORY = "story"
+ VIDEO = "video"
+ VIDEO_NOTE = "video_note"
+ VOICE = "voice"
+ CONTACT = "contact"
+ DICE = "dice"
+ GAME = "game"
+ POLL = "poll"
+ VENUE = "venue"
+ LOCATION = "location"
+ NEW_CHAT_MEMBERS = "new_chat_members"
+ LEFT_CHAT_MEMBER = "left_chat_member"
+ NEW_CHAT_TITLE = "new_chat_title"
+ NEW_CHAT_PHOTO = "new_chat_photo"
+ DELETE_CHAT_PHOTO = "delete_chat_photo"
+ GROUP_CHAT_CREATED = "group_chat_created"
+ SUPERGROUP_CHAT_CREATED = "supergroup_chat_created"
+ CHANNEL_CHAT_CREATED = "channel_chat_created"
+ MESSAGE_AUTO_DELETE_TIMER_CHANGED = "message_auto_delete_timer_changed"
+ MIGRATE_TO_CHAT_ID = "migrate_to_chat_id"
+ MIGRATE_FROM_CHAT_ID = "migrate_from_chat_id"
+ PINNED_MESSAGE = "pinned_message"
+ INVOICE = "invoice"
+ SUCCESSFUL_PAYMENT = "successful_payment"
+ REFUNDED_PAYMENT = "refunded_payment"
+ USERS_SHARED = "users_shared"
+ CHAT_SHARED = "chat_shared"
+ GIFT = "gift"
+ UNIQUE_GIFT = "unique_gift"
+ CONNECTED_WEBSITE = "connected_website"
+ WRITE_ACCESS_ALLOWED = "write_access_allowed"
+ PASSPORT_DATA = "passport_data"
+ PROXIMITY_ALERT_TRIGGERED = "proximity_alert_triggered"
+ BOOST_ADDED = "boost_added"
+ CHAT_BACKGROUND_SET = "chat_background_set"
+ FORUM_TOPIC_CREATED = "forum_topic_created"
+ FORUM_TOPIC_EDITED = "forum_topic_edited"
+ FORUM_TOPIC_CLOSED = "forum_topic_closed"
+ FORUM_TOPIC_REOPENED = "forum_topic_reopened"
+ GENERAL_FORUM_TOPIC_HIDDEN = "general_forum_topic_hidden"
+ GENERAL_FORUM_TOPIC_UNHIDDEN = "general_forum_topic_unhidden"
+ GIVEAWAY_CREATED = "giveaway_created"
+ GIVEAWAY = "giveaway"
+ GIVEAWAY_WINNERS = "giveaway_winners"
+ GIVEAWAY_COMPLETED = "giveaway_completed"
+ PAID_MESSAGE_PRICE_CHANGED = "paid_message_price_changed"
+ VIDEO_CHAT_SCHEDULED = "video_chat_scheduled"
+ VIDEO_CHAT_STARTED = "video_chat_started"
+ VIDEO_CHAT_ENDED = "video_chat_ended"
+ VIDEO_CHAT_PARTICIPANTS_INVITED = "video_chat_participants_invited"
+ WEB_APP_DATA = "web_app_data"
+ USER_SHARED = "user_shared"
diff --git a/myenv/Lib/site-packages/aiogram/enums/currency.py b/myenv/Lib/site-packages/aiogram/enums/currency.py
new file mode 100644
index 0000000..563651b
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/currency.py
@@ -0,0 +1,96 @@
+from enum import Enum
+
+
+class Currency(str, Enum):
+ """
+ Currencies supported by Telegram Bot API
+
+ Source: https://core.telegram.org/bots/payments#supported-currencies
+ """
+
+ AED = "AED"
+ AFN = "AFN"
+ ALL = "ALL"
+ AMD = "AMD"
+ ARS = "ARS"
+ AUD = "AUD"
+ AZN = "AZN"
+ BAM = "BAM"
+ BDT = "BDT"
+ BGN = "BGN"
+ BND = "BND"
+ BOB = "BOB"
+ BRL = "BRL"
+ BYN = "BYN"
+ CAD = "CAD"
+ CHF = "CHF"
+ CLP = "CLP"
+ CNY = "CNY"
+ COP = "COP"
+ CRC = "CRC"
+ CZK = "CZK"
+ DKK = "DKK"
+ DOP = "DOP"
+ DZD = "DZD"
+ EGP = "EGP"
+ ETB = "ETB"
+ EUR = "EUR"
+ GBP = "GBP"
+ GEL = "GEL"
+ GTQ = "GTQ"
+ HKD = "HKD"
+ HNL = "HNL"
+ HRK = "HRK"
+ HUF = "HUF"
+ IDR = "IDR"
+ ILS = "ILS"
+ INR = "INR"
+ ISK = "ISK"
+ JMD = "JMD"
+ JPY = "JPY"
+ KES = "KES"
+ KGS = "KGS"
+ KRW = "KRW"
+ KZT = "KZT"
+ LBP = "LBP"
+ LKR = "LKR"
+ MAD = "MAD"
+ MDL = "MDL"
+ MNT = "MNT"
+ MUR = "MUR"
+ MVR = "MVR"
+ MXN = "MXN"
+ MYR = "MYR"
+ MZN = "MZN"
+ NGN = "NGN"
+ NIO = "NIO"
+ NOK = "NOK"
+ NPR = "NPR"
+ NZD = "NZD"
+ PAB = "PAB"
+ PEN = "PEN"
+ PHP = "PHP"
+ PKR = "PKR"
+ PLN = "PLN"
+ PYG = "PYG"
+ QAR = "QAR"
+ RON = "RON"
+ RSD = "RSD"
+ RUB = "RUB"
+ SAR = "SAR"
+ SEK = "SEK"
+ SGD = "SGD"
+ THB = "THB"
+ TJS = "TJS"
+ TRY = "TRY"
+ TTD = "TTD"
+ TWD = "TWD"
+ TZS = "TZS"
+ UAH = "UAH"
+ UGX = "UGX"
+ USD = "USD"
+ UYU = "UYU"
+ UZS = "UZS"
+ VND = "VND"
+ YER = "YER"
+ ZAR = "ZAR"
diff --git a/myenv/Lib/site-packages/aiogram/enums/dice_emoji.py b/myenv/Lib/site-packages/aiogram/enums/dice_emoji.py
new file mode 100644
index 0000000..6851932
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/dice_emoji.py
@@ -0,0 +1,16 @@
+from enum import Enum
+
+
+class DiceEmoji(str, Enum):
+ """
+ Emoji on which the dice throw animation is based
+
+ Source: https://core.telegram.org/bots/api#dice
+ """
+
+ DICE = "🎲"
+ DART = "🎯"
+ BASKETBALL = "🏀"
+ FOOTBALL = "⚽"
+ SLOT_MACHINE = "🎰"
+ BOWLING = "🎳"
diff --git a/myenv/Lib/site-packages/aiogram/enums/encrypted_passport_element.py b/myenv/Lib/site-packages/aiogram/enums/encrypted_passport_element.py
new file mode 100644
index 0000000..ebb4b2e
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/encrypted_passport_element.py
@@ -0,0 +1,23 @@
+from enum import Enum
+
+
+class EncryptedPassportElement(str, Enum):
+ """
+ This object represents type of encrypted passport element.
+
+ Source: https://core.telegram.org/bots/api#encryptedpassportelement
+ """
+
+ PERSONAL_DETAILS = "personal_details"
+ PASSPORT = "passport"
+ DRIVER_LICENSE = "driver_license"
+ IDENTITY_CARD = "identity_card"
+ INTERNAL_PASSPORT = "internal_passport"
+ ADDRESS = "address"
+ UTILITY_BILL = "utility_bill"
+ BANK_STATEMENT = "bank_statement"
+ RENTAL_AGREEMENT = "rental_agreement"
+ PASSPORT_REGISTRATION = "passport_registration"
+ TEMPORARY_REGISTRATION = "temporary_registration"
+ PHONE_NUMBER = "phone_number"
+ EMAIL = "email"
diff --git a/myenv/Lib/site-packages/aiogram/enums/inline_query_result_type.py b/myenv/Lib/site-packages/aiogram/enums/inline_query_result_type.py
new file mode 100644
index 0000000..ae20045
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/inline_query_result_type.py
@@ -0,0 +1,23 @@
+from enum import Enum
+
+
+class InlineQueryResultType(str, Enum):
+ """
+ Type of inline query result
+
+ Source: https://core.telegram.org/bots/api#inlinequeryresult
+ """
+
+ AUDIO = "audio"
+ DOCUMENT = "document"
+ GIF = "gif"
+ MPEG4_GIF = "mpeg4_gif"
+ PHOTO = "photo"
+ STICKER = "sticker"
+ VIDEO = "video"
+ VOICE = "voice"
+ ARTICLE = "article"
+ CONTACT = "contact"
+ GAME = "game"
+ LOCATION = "location"
+ VENUE = "venue"
diff --git a/myenv/Lib/site-packages/aiogram/enums/input_media_type.py b/myenv/Lib/site-packages/aiogram/enums/input_media_type.py
new file mode 100644
index 0000000..30741dd
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/input_media_type.py
@@ -0,0 +1,15 @@
+from enum import Enum
+
+
+class InputMediaType(str, Enum):
+ """
+ This object represents input media type
+
+ Source: https://core.telegram.org/bots/api#inputmedia
+ """
+
+ ANIMATION = "animation"
+ AUDIO = "audio"
+ DOCUMENT = "document"
+ PHOTO = "photo"
+ VIDEO = "video"
diff --git a/myenv/Lib/site-packages/aiogram/enums/input_paid_media_type.py b/myenv/Lib/site-packages/aiogram/enums/input_paid_media_type.py
new file mode 100644
index 0000000..fc132e2
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/input_paid_media_type.py
@@ -0,0 +1,12 @@
+from enum import Enum
+
+
+class InputPaidMediaType(str, Enum):
+ """
+ This object represents the type of a media in a paid message.
+
+ Source: https://core.telegram.org/bots/api#inputpaidmedia
+ """
+
+ PHOTO = "photo"
+ VIDEO = "video"
diff --git a/myenv/Lib/site-packages/aiogram/enums/input_profile_photo_type.py b/myenv/Lib/site-packages/aiogram/enums/input_profile_photo_type.py
new file mode 100644
index 0000000..08eccbd
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/input_profile_photo_type.py
@@ -0,0 +1,12 @@
+from enum import Enum
+
+
+class InputProfilePhotoType(str, Enum):
+ """
+ This object represents input profile photo type
+
+ Source: https://core.telegram.org/bots/api#inputprofilephoto
+ """
+
+ STATIC = "static"
+ ANIMATED = "animated"
diff --git a/myenv/Lib/site-packages/aiogram/enums/input_story_content_type.py b/myenv/Lib/site-packages/aiogram/enums/input_story_content_type.py
new file mode 100644
index 0000000..78c887a
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/input_story_content_type.py
@@ -0,0 +1,12 @@
+from enum import Enum
+
+
+class InputStoryContentType(str, Enum):
+ """
+ This object represents input story content photo type.
+
+ Source: https://core.telegram.org/bots/api#inputstorycontentphoto
+ """
+
+ PHOTO = "photo"
+ VIDEO = "video"
diff --git a/myenv/Lib/site-packages/aiogram/enums/keyboard_button_poll_type_type.py b/myenv/Lib/site-packages/aiogram/enums/keyboard_button_poll_type_type.py
new file mode 100644
index 0000000..b6b692f
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/keyboard_button_poll_type_type.py
@@ -0,0 +1,12 @@
+from enum import Enum
+
+
+class KeyboardButtonPollTypeType(str, Enum):
+ """
+ This object represents type of a poll, which is allowed to be created and sent when the corresponding button is pressed.
+
+ Source: https://core.telegram.org/bots/api#keyboardbuttonpolltype
+ """
+
+ QUIZ = "quiz"
+ REGULAR = "regular"
diff --git a/myenv/Lib/site-packages/aiogram/enums/mask_position_point.py b/myenv/Lib/site-packages/aiogram/enums/mask_position_point.py
new file mode 100644
index 0000000..348ae00
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/mask_position_point.py
@@ -0,0 +1,14 @@
+from enum import Enum
+
+
+class MaskPositionPoint(str, Enum):
+ """
+ The part of the face relative to which the mask should be placed.
+
+ Source: https://core.telegram.org/bots/api#maskposition
+ """
+
+ FOREHEAD = "forehead"
+ EYES = "eyes"
+ MOUTH = "mouth"
+ CHIN = "chin"
diff --git a/myenv/Lib/site-packages/aiogram/enums/menu_button_type.py b/myenv/Lib/site-packages/aiogram/enums/menu_button_type.py
new file mode 100644
index 0000000..4c1015b
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/menu_button_type.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class MenuButtonType(str, Enum):
+ """
+ This object represents an type of Menu button
+
+ Source: https://core.telegram.org/bots/api#menubuttondefault
+ """
+
+ DEFAULT = "default"
+ COMMANDS = "commands"
+ WEB_APP = "web_app"
diff --git a/myenv/Lib/site-packages/aiogram/enums/message_entity_type.py b/myenv/Lib/site-packages/aiogram/enums/message_entity_type.py
new file mode 100644
index 0000000..b67dc03
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/message_entity_type.py
@@ -0,0 +1,29 @@
+from enum import Enum
+
+
+class MessageEntityType(str, Enum):
+ """
+ This object represents type of message entity
+
+ Source: https://core.telegram.org/bots/api#messageentity
+ """
+
+ MENTION = "mention"
+ HASHTAG = "hashtag"
+ CASHTAG = "cashtag"
+ BOT_COMMAND = "bot_command"
+ URL = "url"
+ EMAIL = "email"
+ PHONE_NUMBER = "phone_number"
+ BOLD = "bold"
+ ITALIC = "italic"
+ UNDERLINE = "underline"
+ STRIKETHROUGH = "strikethrough"
+ SPOILER = "spoiler"
+ BLOCKQUOTE = "blockquote"
+ EXPANDABLE_BLOCKQUOTE = "expandable_blockquote"
+ CODE = "code"
+ PRE = "pre"
+ TEXT_LINK = "text_link"
+ TEXT_MENTION = "text_mention"
+ CUSTOM_EMOJI = "custom_emoji"
diff --git a/myenv/Lib/site-packages/aiogram/enums/message_origin_type.py b/myenv/Lib/site-packages/aiogram/enums/message_origin_type.py
new file mode 100644
index 0000000..9543665
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/message_origin_type.py
@@ -0,0 +1,14 @@
+from enum import Enum
+
+
+class MessageOriginType(str, Enum):
+ """
+ This object represents origin of a message.
+
+ Source: https://core.telegram.org/bots/api#messageorigin
+ """
+
+ USER = "user"
+ HIDDEN_USER = "hidden_user"
+ CHAT = "chat"
+ CHANNEL = "channel"
diff --git a/myenv/Lib/site-packages/aiogram/enums/owned_gift_type.py b/myenv/Lib/site-packages/aiogram/enums/owned_gift_type.py
new file mode 100644
index 0000000..ec0545d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/owned_gift_type.py
@@ -0,0 +1,12 @@
+from enum import Enum
+
+
+class OwnedGiftType(str, Enum):
+ """
+ This object represents owned gift type
+
+ Source: https://core.telegram.org/bots/api#ownedgift
+ """
+
+ REGULAR = "regular"
+ UNIQUE = "unique"
diff --git a/myenv/Lib/site-packages/aiogram/enums/paid_media_type.py b/myenv/Lib/site-packages/aiogram/enums/paid_media_type.py
new file mode 100644
index 0000000..930028f
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/paid_media_type.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class PaidMediaType(str, Enum):
+ """
+ This object represents the type of a media in a paid message.
+
+ Source: https://core.telegram.org/bots/api#paidmedia
+ """
+
+ PHOTO = "photo"
+ PREVIEW = "preview"
+ VIDEO = "video"
diff --git a/myenv/Lib/site-packages/aiogram/enums/parse_mode.py b/myenv/Lib/site-packages/aiogram/enums/parse_mode.py
new file mode 100644
index 0000000..f17dd98
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/parse_mode.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class ParseMode(str, Enum):
+ """
+ Formatting options
+
+ Source: https://core.telegram.org/bots/api#formatting-options
+ """
+
+ MARKDOWN_V2 = "MarkdownV2"
+ MARKDOWN = "Markdown"
+ HTML = "HTML"
diff --git a/myenv/Lib/site-packages/aiogram/enums/passport_element_error_type.py b/myenv/Lib/site-packages/aiogram/enums/passport_element_error_type.py
new file mode 100644
index 0000000..cdcb480
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/passport_element_error_type.py
@@ -0,0 +1,19 @@
+from enum import Enum
+
+
+class PassportElementErrorType(str, Enum):
+ """
+ This object represents a passport element error type.
+
+ Source: https://core.telegram.org/bots/api#passportelementerror
+ """
+
+ DATA = "data"
+ FRONT_SIDE = "front_side"
+ REVERSE_SIDE = "reverse_side"
+ SELFIE = "selfie"
+ FILE = "file"
+ FILES = "files"
+ TRANSLATION_FILE = "translation_file"
+ TRANSLATION_FILES = "translation_files"
+ UNSPECIFIED = "unspecified"
diff --git a/myenv/Lib/site-packages/aiogram/enums/poll_type.py b/myenv/Lib/site-packages/aiogram/enums/poll_type.py
new file mode 100644
index 0000000..039d600
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/poll_type.py
@@ -0,0 +1,12 @@
+from enum import Enum
+
+
+class PollType(str, Enum):
+ """
+ This object represents poll type
+
+ Source: https://core.telegram.org/bots/api#poll
+ """
+
+ REGULAR = "regular"
+ QUIZ = "quiz"
diff --git a/myenv/Lib/site-packages/aiogram/enums/reaction_type_type.py b/myenv/Lib/site-packages/aiogram/enums/reaction_type_type.py
new file mode 100644
index 0000000..f4b7c34
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/reaction_type_type.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class ReactionTypeType(str, Enum):
+ """
+ This object represents reaction type.
+
+ Source: https://core.telegram.org/bots/api#reactiontype
+ """
+
+ EMOJI = "emoji"
+ CUSTOM_EMOJI = "custom_emoji"
+ PAID = "paid"
diff --git a/myenv/Lib/site-packages/aiogram/enums/revenue_withdrawal_state_type.py b/myenv/Lib/site-packages/aiogram/enums/revenue_withdrawal_state_type.py
new file mode 100644
index 0000000..89a9a04
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/revenue_withdrawal_state_type.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class RevenueWithdrawalStateType(str, Enum):
+ """
+ This object represents a revenue withdrawal state type
+
+ Source: https://core.telegram.org/bots/api#revenuewithdrawalstate
+ """
+
+ FAILED = "failed"
+ PENDING = "pending"
+ SUCCEEDED = "succeeded"
diff --git a/myenv/Lib/site-packages/aiogram/enums/sticker_format.py b/myenv/Lib/site-packages/aiogram/enums/sticker_format.py
new file mode 100644
index 0000000..6c9441d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/sticker_format.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class StickerFormat(str, Enum):
+ """
+ Format of the sticker
+
+ Source: https://core.telegram.org/bots/api#createnewstickerset
+ """
+
+ STATIC = "static"
+ ANIMATED = "animated"
+ VIDEO = "video"
diff --git a/myenv/Lib/site-packages/aiogram/enums/sticker_type.py b/myenv/Lib/site-packages/aiogram/enums/sticker_type.py
new file mode 100644
index 0000000..748f85e
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/sticker_type.py
@@ -0,0 +1,13 @@
+from enum import Enum
+
+
+class StickerType(str, Enum):
+ """
+ The part of the face relative to which the mask should be placed.
+
+ Source: https://core.telegram.org/bots/api#maskposition
+ """
+
+ REGULAR = "regular"
+ MASK = "mask"
+ CUSTOM_EMOJI = "custom_emoji"
diff --git a/myenv/Lib/site-packages/aiogram/enums/story_area_type_type.py b/myenv/Lib/site-packages/aiogram/enums/story_area_type_type.py
new file mode 100644
index 0000000..8be3836
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/story_area_type_type.py
@@ -0,0 +1,15 @@
+from enum import Enum
+
+
+class StoryAreaTypeType(str, Enum):
+ """
+ This object represents input profile photo type
+
+ Source: https://core.telegram.org/bots/api#storyareatype
+ """
+
+ LOCATION = "location"
+ SUGGESTED_REACTION = "suggested_reaction"
+ LINK = "link"
+ WEATHER = "weather"
+ UNIQUE_GIFT = "unique_gift"
diff --git a/myenv/Lib/site-packages/aiogram/enums/topic_icon_color.py b/myenv/Lib/site-packages/aiogram/enums/topic_icon_color.py
new file mode 100644
index 0000000..f40ee71
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/topic_icon_color.py
@@ -0,0 +1,16 @@
+from enum import Enum
+
+
+class TopicIconColor(int, Enum):
+ """
+ Color of the topic icon in RGB format.
+
+ Source: https://github.com/telegramdesktop/tdesktop/blob/991fe491c5ae62705d77aa8fdd44a79caf639c45/Telegram/SourceFiles/data/data_forum_topic.cpp#L51-L56
+ """
+
+ BLUE = 0x6FB9F0
+ YELLOW = 0xFFD67E
+ VIOLET = 0xCB86DB
+ GREEN = 0x8EEE98
+ ROSE = 0xFF93B2
+ RED = 0xFB6F5F
diff --git a/myenv/Lib/site-packages/aiogram/enums/transaction_partner_type.py b/myenv/Lib/site-packages/aiogram/enums/transaction_partner_type.py
new file mode 100644
index 0000000..4f683e2
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/transaction_partner_type.py
@@ -0,0 +1,17 @@
+from enum import Enum
+
+
+class TransactionPartnerType(str, Enum):
+ """
+ This object represents a type of transaction partner.
+
+ Source: https://core.telegram.org/bots/api#transactionpartner
+ """
+
+ FRAGMENT = "fragment"
+ OTHER = "other"
+ USER = "user"
+ TELEGRAM_ADS = "telegram_ads"
+ TELEGRAM_API = "telegram_api"
+ AFFILIATE_PROGRAM = "affiliate_program"
+ CHAT = "chat"
diff --git a/myenv/Lib/site-packages/aiogram/enums/transaction_partner_user_transaction_type_enum.py b/myenv/Lib/site-packages/aiogram/enums/transaction_partner_user_transaction_type_enum.py
new file mode 100644
index 0000000..02cf2dc
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/transaction_partner_user_transaction_type_enum.py
@@ -0,0 +1,15 @@
+from enum import Enum
+
+
+class TransactionPartnerUserTransactionTypeEnum(str, Enum):
+ """
+ This object represents type of the transaction that were made by partner user.
+
+ Source: https://core.telegram.org/bots/api#transactionpartneruser
+ """
+
+ INVOICE_PAYMENT = "invoice_payment"
+ PAID_MEDIA_PAYMENT = "paid_media_payment"
+ GIFT_PURCHASE = "gift_purchase"
+ PREMIUM_PURCHASE = "premium_purchase"
+ BUSINESS_ACCOUNT_TRANSFER = "business_account_transfer"
diff --git a/myenv/Lib/site-packages/aiogram/enums/update_type.py b/myenv/Lib/site-packages/aiogram/enums/update_type.py
new file mode 100644
index 0000000..2629264
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/enums/update_type.py
@@ -0,0 +1,33 @@
+from enum import Enum
+
+
+class UpdateType(str, Enum):
+ """
+ This object represents the complete list of allowed update types
+
+ Source: https://core.telegram.org/bots/api#update
+ """
+
+ MESSAGE = "message"
+ EDITED_MESSAGE = "edited_message"
+ CHANNEL_POST = "channel_post"
+ EDITED_CHANNEL_POST = "edited_channel_post"
+ BUSINESS_CONNECTION = "business_connection"
+ BUSINESS_MESSAGE = "business_message"
+ EDITED_BUSINESS_MESSAGE = "edited_business_message"
+ DELETED_BUSINESS_MESSAGES = "deleted_business_messages"
+ MESSAGE_REACTION = "message_reaction"
+ MESSAGE_REACTION_COUNT = "message_reaction_count"
+ INLINE_QUERY = "inline_query"
+ CHOSEN_INLINE_RESULT = "chosen_inline_result"
+ CALLBACK_QUERY = "callback_query"
+ SHIPPING_QUERY = "shipping_query"
+ PRE_CHECKOUT_QUERY = "pre_checkout_query"
+ PURCHASED_PAID_MEDIA = "purchased_paid_media"
+ POLL = "poll"
+ POLL_ANSWER = "poll_answer"
+ MY_CHAT_MEMBER = "my_chat_member"
+ CHAT_MEMBER = "chat_member"
+ CHAT_JOIN_REQUEST = "chat_join_request"
+ CHAT_BOOST = "chat_boost"
+ REMOVED_CHAT_BOOST = "removed_chat_boost"
diff --git a/myenv/Lib/site-packages/aiogram/exceptions.py b/myenv/Lib/site-packages/aiogram/exceptions.py
new file mode 100644
index 0000000..d195aa7
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/exceptions.py
@@ -0,0 +1,199 @@
+from typing import Any, Optional
+
+from aiogram.methods import TelegramMethod
+from aiogram.methods.base import TelegramType
+from aiogram.utils.link import docs_url
+
+
+class AiogramError(Exception):
+ """
+ Base exception for all aiogram errors.
+ """
+
+
+class DetailedAiogramError(AiogramError):
+ """
+ Base exception for all aiogram errors with detailed message.
+ """
+
+ url: Optional[str] = None
+
+ def __init__(self, message: str) -> None:
+ self.message = message
+
+ def __str__(self) -> str:
+ message = self.message
+ if self.url:
+ message += f"\n(background on this error at: {self.url})"
+ return message
+
+ def __repr__(self) -> str:
+ return f"{type(self).__name__}('{self}')"
+
+
+class CallbackAnswerException(AiogramError):
+ """
+ Exception for callback answer.
+ """
+
+
+class SceneException(AiogramError):
+ """
+ Exception for scenes.
+ """
+
+
+class UnsupportedKeywordArgument(DetailedAiogramError):
+ """
+ Exception raised when a keyword argument is passed as filter.
+ """
+
+ url = docs_url("migration_2_to_3.html", fragment_="filtering-events")
+
+
+class TelegramAPIError(DetailedAiogramError):
+ """
+ Base exception for all Telegram API errors.
+ """
+
+ label: str = "Telegram server says"
+
+ def __init__(
+ self,
+ method: TelegramMethod[TelegramType],
+ message: str,
+ ) -> None:
+ super().__init__(message=message)
+ self.method = method
+
+ def __str__(self) -> str:
+ original_message = super().__str__()
+ return f"{self.label} - {original_message}"
+
+
+class TelegramNetworkError(TelegramAPIError):
+ """
+ Base exception for all Telegram network errors.
+ """
+
+ label = "HTTP Client says"
+
+
+class TelegramRetryAfter(TelegramAPIError):
+ """
+ Exception raised when flood control exceeds.
+ """
+
+ url = "https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this"
+
+ def __init__(
+ self,
+ method: TelegramMethod[TelegramType],
+ message: str,
+ retry_after: int,
+ ) -> None:
+ description = f"Flood control exceeded on method {type(method).__name__!r}"
+ if chat_id := getattr(method, "chat_id", None):
+ description += f" in chat {chat_id}"
+ description += f". Retry in {retry_after} seconds."
+ description += f"\nOriginal description: {message}"
+
+ super().__init__(method=method, message=description)
+ self.retry_after = retry_after
+
+
+class TelegramMigrateToChat(TelegramAPIError):
+ """
+ Exception raised when chat has been migrated to a supergroup.
+ """
+
+ url = "https://core.telegram.org/bots/api#responseparameters"
+
+ def __init__(
+ self,
+ method: TelegramMethod[TelegramType],
+ message: str,
+ migrate_to_chat_id: int,
+ ) -> None:
+ description = f"The group has been migrated to a supergroup with id {migrate_to_chat_id}"
+ if chat_id := getattr(method, "chat_id", None):
+ description += f" from {chat_id}"
+ description += f"\nOriginal description: {message}"
+ super().__init__(method=method, message=message)
+ self.migrate_to_chat_id = migrate_to_chat_id
+
+
+class TelegramBadRequest(TelegramAPIError):
+ """
+ Exception raised when request is malformed.
+ """
+
+
+class TelegramNotFound(TelegramAPIError):
+ """
+ Exception raised when chat, message, user, etc. not found.
+ """
+
+
+class TelegramConflictError(TelegramAPIError):
+ """
+ Exception raised when bot token is already used by another application in polling mode.
+ """
+
+
+class TelegramUnauthorizedError(TelegramAPIError):
+ """
+ Exception raised when bot token is invalid.
+ """
+
+
+class TelegramForbiddenError(TelegramAPIError):
+ """
+ Exception raised when bot is kicked from chat or etc.
+ """
+
+
+class TelegramServerError(TelegramAPIError):
+ """
+ Exception raised when Telegram server returns 5xx error.
+ """
+
+
+class RestartingTelegram(TelegramServerError):
+ """
+ Exception raised when Telegram server is restarting.
+
+ It seems like this error is not used by Telegram anymore,
+ but it's still here for backward compatibility.
+
+ Currently, you should expect that Telegram can raise RetryAfter (with timeout 5 seconds)
+ error instead of this one.
+ """
+
+
+class TelegramEntityTooLarge(TelegramNetworkError):
+ """
+ Exception raised when you are trying to send a file that is too large.
+ """
+
+ url = "https://core.telegram.org/bots/api#sending-files"
+
+
+class ClientDecodeError(AiogramError):
+ """
+ Exception raised when client can't decode response. (Malformed response, etc.)
+ """
+
+ def __init__(self, message: str, original: Exception, data: Any) -> None:
+ self.message = message
+ self.original = original
+ self.data = data
+
+ def __str__(self) -> str:
+ original_type = type(self.original)
+ return (
+ f"{self.message}\n"
+ f"Caused from error: "
+ f"{original_type.__module__}.{original_type.__name__}: {self.original}\n"
+ f"Content: {self.data}"
+ )
diff --git a/myenv/Lib/site-packages/aiogram/filters/__init__.py b/myenv/Lib/site-packages/aiogram/filters/__init__.py
new file mode 100644
index 0000000..bcadc17
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/__init__.py
@@ -0,0 +1,51 @@
+from .base import Filter
+from .chat_member_updated import (
+ ADMINISTRATOR,
+ CREATOR,
+ IS_ADMIN,
+ IS_MEMBER,
+ IS_NOT_MEMBER,
+ JOIN_TRANSITION,
+ KICKED,
+ LEAVE_TRANSITION,
+ LEFT,
+ MEMBER,
+ PROMOTED_TRANSITION,
+ RESTRICTED,
+ ChatMemberUpdatedFilter,
+)
+from .command import Command, CommandObject, CommandStart
+from .exception import ExceptionMessageFilter, ExceptionTypeFilter
+from .logic import and_f, invert_f, or_f
+from .magic_data import MagicData
+from .state import StateFilter
+
+BaseFilter = Filter
+
+__all__ = (
+ "Filter",
+ "BaseFilter",
+ "Command",
+ "CommandObject",
+ "CommandStart",
+ "ExceptionMessageFilter",
+ "ExceptionTypeFilter",
+ "StateFilter",
+ "MagicData",
+ "ChatMemberUpdatedFilter",
+ "CREATOR",
+ "ADMINISTRATOR",
+ "MEMBER",
+ "RESTRICTED",
+ "LEFT",
+ "KICKED",
+ "IS_MEMBER",
+ "IS_ADMIN",
+ "PROMOTED_TRANSITION",
+ "IS_NOT_MEMBER",
+ "JOIN_TRANSITION",
+ "LEAVE_TRANSITION",
+ "and_f",
+ "or_f",
+ "invert_f",
+)
diff --git a/myenv/Lib/site-packages/aiogram/filters/base.py b/myenv/Lib/site-packages/aiogram/filters/base.py
new file mode 100644
index 0000000..94f9b6d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/base.py
@@ -0,0 +1,55 @@
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Union
+
+if TYPE_CHECKING:
+ from aiogram.filters.logic import _InvertFilter
+
+
+class Filter(ABC):
+ """
+ If you want to register own filters like builtin filters you will need to write subclass
+ of this class with overriding the :code:`__call__`
+ method and adding filter attributes.
+ """
+
+ if TYPE_CHECKING:
+ # This checking type-hint is needed because mypy checks validity of overrides and raises:
+ # error: Signature of "__call__" incompatible with supertype "BaseFilter" [override]
+ # https://mypy.readthedocs.io/en/latest/error_code_list.html#check-validity-of-overrides-override
+ __call__: Callable[..., Awaitable[Union[bool, Dict[str, Any]]]]
+ else: # pragma: no cover
+
+ @abstractmethod
+ async def __call__(self, *args: Any, **kwargs: Any) -> Union[bool, Dict[str, Any]]:
+ """
+ This method should be overridden.
+
+ Accepts incoming event and should return boolean or dict.
+
+ :return: :class:`bool` or :class:`Dict[str, Any]`
+ """
+ pass
+
+ def __invert__(self) -> "_InvertFilter":
+ from aiogram.filters.logic import invert_f
+
+ return invert_f(self)
+
+ def update_handler_flags(self, flags: Dict[str, Any]) -> None:
+ """
+ Also if you want to extend handler flags with using this filter
+ you should implement this method
+
+ :param flags: existing flags, can be updated directly
+ """
+ pass
+
+ def _signature_to_string(self, *args: Any, **kwargs: Any) -> str:
+ items = [repr(arg) for arg in args]
+ items.extend([f"{k}={v!r}" for k, v in kwargs.items() if v is not None])
+
+ return f"{type(self).__name__}({', '.join(items)})"
+
+ def __await__(self): # type: ignore # pragma: no cover
+ # Is needed only for inspection and this method is never be called
+ return self.__call__
diff --git a/myenv/Lib/site-packages/aiogram/filters/callback_data.py b/myenv/Lib/site-packages/aiogram/filters/callback_data.py
new file mode 100644
index 0000000..e504d50
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/callback_data.py
@@ -0,0 +1,208 @@
+from __future__ import annotations
+
+import sys
+import types
+import typing
+from decimal import Decimal
+from enum import Enum
+from fractions import Fraction
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ ClassVar,
+ Dict,
+ Literal,
+ Optional,
+ Type,
+ TypeVar,
+ Union,
+)
+from uuid import UUID
+
+from magic_filter import MagicFilter
+from pydantic import BaseModel
+from pydantic.fields import FieldInfo
+from pydantic_core import PydanticUndefined
+
+from aiogram.filters.base import Filter
+from aiogram.types import CallbackQuery
+
+T = TypeVar("T", bound="CallbackData")
+
+MAX_CALLBACK_LENGTH: int = 64
+
+
+_UNION_TYPES = {typing.Union}
+if sys.version_info >= (3, 10): # pragma: no cover
+ _UNION_TYPES.add(types.UnionType)
+
+
+class CallbackDataException(Exception):
+ pass
+
+
+class CallbackData(BaseModel):
+ """
+ Base class for callback data wrapper
+
+ This class should be used as super-class of user-defined callbacks.
+
+ The class-keyword :code:`prefix` is required to define prefix
+ and also the argument :code:`sep` can be passed to define separator (default is :code:`:`).
+ """
+
+ if TYPE_CHECKING:
+ __separator__: ClassVar[str]
+ """Data separator (default is :code:`:`)"""
+ __prefix__: ClassVar[str]
+ """Callback prefix"""
+
+ def __init_subclass__(cls, **kwargs: Any) -> None:
+ if "prefix" not in kwargs:
+ raise ValueError(
+ f"prefix required, usage example: "
+ f"`class {cls.__name__}(CallbackData, prefix='my_callback'): ...`"
+ )
+ cls.__separator__ = kwargs.pop("sep", ":")
+ cls.__prefix__ = kwargs.pop("prefix")
+ if cls.__separator__ in cls.__prefix__:
+ raise ValueError(
+ f"Separator symbol {cls.__separator__!r} can not be used "
+ f"inside prefix {cls.__prefix__!r}"
+ )
+ super().__init_subclass__(**kwargs)
+
+ def _encode_value(self, key: str, value: Any) -> str:
+ if value is None:
+ return ""
+ if isinstance(value, Enum):
+ return str(value.value)
+ if isinstance(value, UUID):
+ return value.hex
+ if isinstance(value, bool):
+ return str(int(value))
+ if isinstance(value, (int, str, float, Decimal, Fraction)):
+ return str(value)
+ raise ValueError(
+ f"Attribute {key}={value!r} of type {type(value).__name__!r}"
+ f" can not be packed to callback data"
+ )
+
+ def pack(self) -> str:
+ """
+ Generate callback data string
+
+ :return: valid callback data for Telegram Bot API
+ """
+ result = [self.__prefix__]
+ for key, value in self.model_dump(mode="python").items():
+ encoded = self._encode_value(key, value)
+ if self.__separator__ in encoded:
+ raise ValueError(
+ f"Separator symbol {self.__separator__!r} can not be used "
+ f"in value {key}={encoded!r}"
+ )
+ result.append(encoded)
+ callback_data = self.__separator__.join(result)
+ if len(callback_data.encode()) > MAX_CALLBACK_LENGTH:
+ raise ValueError(
+ f"Resulted callback data is too long! "
+ f"len({callback_data!r}.encode()) > {MAX_CALLBACK_LENGTH}"
+ )
+ return callback_data
+
+ @classmethod
+ def unpack(cls: Type[T], value: str) -> T:
+ """
+ Parse callback data string
+
+ :param value: value from Telegram
+ :return: instance of CallbackData
+ """
+ prefix, *parts = value.split(cls.__separator__)
+ names = cls.model_fields.keys()
+ if len(parts) != len(names):
+ raise TypeError(
+ f"Callback data {cls.__name__!r} takes {len(names)} arguments "
+ f"but {len(parts)} were given"
+ )
+ if prefix != cls.__prefix__:
+ raise ValueError(f"Bad prefix ({prefix!r} != {cls.__prefix__!r})")
+ payload = {}
+ for k, v in zip(names, parts): # type: str, Optional[str]
+ if field := cls.model_fields.get(k):
+ if v == "" and _check_field_is_nullable(field) and field.default != "":
+ v = field.default if field.default is not PydanticUndefined else None
+ payload[k] = v
+ return cls(**payload)
+
+ @classmethod
+ def filter(cls, rule: Optional[MagicFilter] = None) -> CallbackQueryFilter:
+ """
+ Generates a filter for callback query with rule
+
+ :param rule: magic rule
+ :return: instance of filter
+ """
+ return CallbackQueryFilter(callback_data=cls, rule=rule)
+
+
+class CallbackQueryFilter(Filter):
+ """
+ This filter helps to handle callback query.
+
+ Should not be used directly, you should create the instance of this filter
+ via callback data instance
+ """
+
+ __slots__ = (
+ "callback_data",
+ "rule",
+ )
+
+ def __init__(
+ self,
+ *,
+ callback_data: Type[CallbackData],
+ rule: Optional[MagicFilter] = None,
+ ):
+ """
+ :param callback_data: Expected type of callback data
+ :param rule: Magic rule
+ """
+ self.callback_data = callback_data
+ self.rule = rule
+
+ def __str__(self) -> str:
+ return self._signature_to_string(
+ callback_data=self.callback_data,
+ rule=self.rule,
+ )
+
+ async def __call__(self, query: CallbackQuery) -> Union[Literal[False], Dict[str, Any]]:
+ if not isinstance(query, CallbackQuery) or not query.data:
+ return False
+ try:
+ callback_data = self.callback_data.unpack(query.data)
+ except (TypeError, ValueError):
+ return False
+
+ if self.rule is None or self.rule.resolve(callback_data):
+ return {"callback_data": callback_data}
+ return False
+
+
+def _check_field_is_nullable(field: FieldInfo) -> bool:
+ """
+ Check if the given field is nullable.
+
+ :param field: The FieldInfo object representing the field to check.
+ :return: True if the field is nullable, False otherwise.
+
+ """
+ if not field.is_required():
+ return True
+
+ return typing.get_origin(field.annotation) in _UNION_TYPES and type(None) in typing.get_args(
+ field.annotation
+ )
diff --git a/myenv/Lib/site-packages/aiogram/filters/chat_member_updated.py b/myenv/Lib/site-packages/aiogram/filters/chat_member_updated.py
new file mode 100644
index 0000000..23cf0e9
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/chat_member_updated.py
@@ -0,0 +1,204 @@
+from typing import Any, Dict, Optional, TypeVar, Union
+
+from aiogram.filters.base import Filter
+from aiogram.types import ChatMember, ChatMemberUpdated
+
+MarkerT = TypeVar("MarkerT", bound="_MemberStatusMarker")
+MarkerGroupT = TypeVar("MarkerGroupT", bound="_MemberStatusGroupMarker")
+TransitionT = TypeVar("TransitionT", bound="_MemberStatusTransition")
+
+
+class _MemberStatusMarker:
+ __slots__ = (
+ "name",
+ "is_member",
+ )
+
+ def __init__(self, name: str, *, is_member: Optional[bool] = None) -> None:
+ self.name = name
+ self.is_member = is_member
+
+ def __str__(self) -> str:
+ result = self.name.upper()
+ if self.is_member is not None:
+ result = ("+" if self.is_member else "-") + result
+ return result # noqa: RET504
+
+ def __pos__(self: MarkerT) -> MarkerT:
+ return type(self)(name=self.name, is_member=True)
+
+ def __neg__(self: MarkerT) -> MarkerT:
+ return type(self)(name=self.name, is_member=False)
+
+ def __or__(
+ self, other: Union["_MemberStatusMarker", "_MemberStatusGroupMarker"]
+ ) -> "_MemberStatusGroupMarker":
+ if isinstance(other, _MemberStatusMarker):
+ return _MemberStatusGroupMarker(self, other)
+ if isinstance(other, _MemberStatusGroupMarker):
+ return other | self
+ raise TypeError(
+ f"unsupported operand type(s) for |: "
+ f"{type(self).__name__!r} and {type(other).__name__!r}"
+ )
+
+ __ror__ = __or__
+
+ def __rshift__(
+ self, other: Union["_MemberStatusMarker", "_MemberStatusGroupMarker"]
+ ) -> "_MemberStatusTransition":
+ old = _MemberStatusGroupMarker(self)
+ if isinstance(other, _MemberStatusMarker):
+ return _MemberStatusTransition(old=old, new=_MemberStatusGroupMarker(other))
+ if isinstance(other, _MemberStatusGroupMarker):
+ return _MemberStatusTransition(old=old, new=other)
+ raise TypeError(
+ f"unsupported operand type(s) for >>: "
+ f"{type(self).__name__!r} and {type(other).__name__!r}"
+ )
+
+ def __lshift__(
+ self, other: Union["_MemberStatusMarker", "_MemberStatusGroupMarker"]
+ ) -> "_MemberStatusTransition":
+ new = _MemberStatusGroupMarker(self)
+ if isinstance(other, _MemberStatusMarker):
+ return _MemberStatusTransition(old=_MemberStatusGroupMarker(other), new=new)
+ if isinstance(other, _MemberStatusGroupMarker):
+ return _MemberStatusTransition(old=other, new=new)
+ raise TypeError(
+ f"unsupported operand type(s) for <<: "
+ f"{type(self).__name__!r} and {type(other).__name__!r}"
+ )
+
+ def __hash__(self) -> int:
+ return hash((self.name, self.is_member))
+
+ def check(self, *, member: ChatMember) -> bool:
+ # Not all member types have `is_member` attribute
+ is_member = getattr(member, "is_member", None)
+ status = getattr(member, "status", None)
+ if self.is_member is not None and is_member != self.is_member:
+ return False
+ return self.name == status
+
+
+class _MemberStatusGroupMarker:
+ __slots__ = ("statuses",)
+
+ def __init__(self, *statuses: _MemberStatusMarker) -> None:
+ if not statuses:
+ raise ValueError("Member status group should have at least one status included")
+ self.statuses = frozenset(statuses)
+
+ def __or__(
+ self: MarkerGroupT, other: Union["_MemberStatusMarker", "_MemberStatusGroupMarker"]
+ ) -> MarkerGroupT:
+ if isinstance(other, _MemberStatusMarker):
+ return type(self)(*self.statuses, other)
+ if isinstance(other, _MemberStatusGroupMarker):
+ return type(self)(*self.statuses, *other.statuses)
+ raise TypeError(
+ f"unsupported operand type(s) for |: "
+ f"{type(self).__name__!r} and {type(other).__name__!r}"
+ )
+
+ def __rshift__(
+ self, other: Union["_MemberStatusMarker", "_MemberStatusGroupMarker"]
+ ) -> "_MemberStatusTransition":
+ if isinstance(other, _MemberStatusMarker):
+ return _MemberStatusTransition(old=self, new=_MemberStatusGroupMarker(other))
+ if isinstance(other, _MemberStatusGroupMarker):
+ return _MemberStatusTransition(old=self, new=other)
+ raise TypeError(
+ f"unsupported operand type(s) for >>: "
+ f"{type(self).__name__!r} and {type(other).__name__!r}"
+ )
+
+ def __lshift__(
+ self, other: Union["_MemberStatusMarker", "_MemberStatusGroupMarker"]
+ ) -> "_MemberStatusTransition":
+ if isinstance(other, _MemberStatusMarker):
+ return _MemberStatusTransition(old=_MemberStatusGroupMarker(other), new=self)
+ if isinstance(other, _MemberStatusGroupMarker):
+ return _MemberStatusTransition(old=other, new=self)
+ raise TypeError(
+ f"unsupported operand type(s) for <<: "
+ f"{type(self).__name__!r} and {type(other).__name__!r}"
+ )
+
+ def __str__(self) -> str:
+ result = " | ".join(map(str, sorted(self.statuses, key=str)))
+ if len(self.statuses) != 1:
+ return f"({result})"
+ return result
+
+ def check(self, *, member: ChatMember) -> bool:
+ return any(status.check(member=member) for status in self.statuses)
+
+
+class _MemberStatusTransition:
+ __slots__ = (
+ "old",
+ "new",
+ )
+
+ def __init__(self, *, old: _MemberStatusGroupMarker, new: _MemberStatusGroupMarker) -> None:
+ self.old = old
+ self.new = new
+
+ def __str__(self) -> str:
+ return f"{self.old} >> {self.new}"
+
+ def __invert__(self: TransitionT) -> TransitionT:
+ return type(self)(old=self.new, new=self.old)
+
+ def check(self, *, old: ChatMember, new: ChatMember) -> bool:
+ return self.old.check(member=old) and self.new.check(member=new)
+
+
+CREATOR = _MemberStatusMarker("creator")
+ADMINISTRATOR = _MemberStatusMarker("administrator")
+MEMBER = _MemberStatusMarker("member")
+RESTRICTED = _MemberStatusMarker("restricted")
+LEFT = _MemberStatusMarker("left")
+KICKED = _MemberStatusMarker("kicked")
+
+IS_MEMBER = CREATOR | ADMINISTRATOR | MEMBER | +RESTRICTED
+IS_ADMIN = CREATOR | ADMINISTRATOR
+IS_NOT_MEMBER = LEFT | KICKED | -RESTRICTED
+
+JOIN_TRANSITION = IS_NOT_MEMBER >> IS_MEMBER
+LEAVE_TRANSITION = ~JOIN_TRANSITION
+PROMOTED_TRANSITION = (MEMBER | RESTRICTED | LEFT | KICKED) >> ADMINISTRATOR
+
+
+class ChatMemberUpdatedFilter(Filter):
+ __slots__ = ("member_status_changed",)
+
+ def __init__(
+ self,
+ member_status_changed: Union[
+ _MemberStatusMarker,
+ _MemberStatusGroupMarker,
+ _MemberStatusTransition,
+ ],
+ ):
+ self.member_status_changed = member_status_changed
+
+ def __str__(self) -> str:
+ return self._signature_to_string(
+ member_status_changed=self.member_status_changed,
+ )
+
+ async def __call__(self, member_updated: ChatMemberUpdated) -> Union[bool, Dict[str, Any]]:
+ old = member_updated.old_chat_member
+ new = member_updated.new_chat_member
+ rule = self.member_status_changed
+
+ if isinstance(rule, (_MemberStatusMarker, _MemberStatusGroupMarker)):
+ return rule.check(member=new)
+ if isinstance(rule, _MemberStatusTransition):
+ return rule.check(old=old, new=new)
+
+ # Impossible variant in due to pydantic validation
+ return False # pragma: no cover
diff --git a/myenv/Lib/site-packages/aiogram/filters/command.py b/myenv/Lib/site-packages/aiogram/filters/command.py
new file mode 100644
index 0000000..f52ac26
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/command.py
@@ -0,0 +1,298 @@
+from __future__ import annotations
+
+import re
+from dataclasses import dataclass, field, replace
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Dict,
+ Iterable,
+ Match,
+ Optional,
+ Pattern,
+ Sequence,
+ Union,
+ cast,
+)
+
+from magic_filter import MagicFilter
+
+from aiogram.filters.base import Filter
+from aiogram.types import BotCommand, Message
+from aiogram.utils.deep_linking import decode_payload
+
+if TYPE_CHECKING:
+ from aiogram import Bot
+
+# TODO: rm type ignore after py3.8 support expiration or mypy bug fix
+CommandPatternType = Union[str, re.Pattern, BotCommand] # type: ignore[type-arg]
+
+
+class CommandException(Exception):
+ pass
+
+
+class Command(Filter):
+ """
+ This filter can be helpful for handling commands from the text messages.
+
+ Works only with :class:`aiogram.types.message.Message` events which have the :code:`text`.
+ """
+
+ __slots__ = (
+ "commands",
+ "prefix",
+ "ignore_case",
+ "ignore_mention",
+ "magic",
+ )
+
+ def __init__(
+ self,
+ *values: CommandPatternType,
+ commands: Optional[Union[Sequence[CommandPatternType], CommandPatternType]] = None,
+ prefix: str = "/",
+ ignore_case: bool = False,
+ ignore_mention: bool = False,
+ magic: Optional[MagicFilter] = None,
+ ):
+ """
+ List of commands (string or compiled regexp patterns)
+
+ :param prefix: Prefix for command.
+ Prefix is always a single char but here you can pass all of allowed prefixes,
+ for example: :code:`"/!"` will work with commands prefixed
+ by :code:`"/"` or :code:`"!"`.
+ :param ignore_case: Ignore case (Does not work with regexp, use flags instead)
+ :param ignore_mention: Ignore bot mention. By default,
+ bot can not handle commands intended for other bots
+ :param magic: Validate command object via Magic filter after all checks done
+ """
+ if commands is None:
+ commands = []
+ if isinstance(commands, (str, re.Pattern, BotCommand)):
+ commands = [commands]
+
+ if not isinstance(commands, Iterable):
+ raise ValueError(
+ "Command filter only supports str, re.Pattern, BotCommand object"
+ " or their Iterable"
+ )
+
+ items = []
+ for command in (*values, *commands):
+ if isinstance(command, BotCommand):
+ command = command.command
+ if not isinstance(command, (str, re.Pattern)):
+ raise ValueError(
+ "Command filter only supports str, re.Pattern, BotCommand object"
+ " or their Iterable"
+ )
+ if ignore_case and isinstance(command, str):
+ command = command.casefold()
+ items.append(command)
+
+ if not items:
+ raise ValueError("At least one command should be specified")
+
+ self.commands = tuple(items)
+ self.prefix = prefix
+ self.ignore_case = ignore_case
+ self.ignore_mention = ignore_mention
+ self.magic = magic
+
+ def __str__(self) -> str:
+ return self._signature_to_string(
+ *self.commands,
+ prefix=self.prefix,
+ ignore_case=self.ignore_case,
+ ignore_mention=self.ignore_mention,
+ magic=self.magic,
+ )
+
+ def update_handler_flags(self, flags: Dict[str, Any]) -> None:
+ commands = flags.setdefault("commands", [])
+ commands.append(self)
+
+ async def __call__(self, message: Message, bot: Bot) -> Union[bool, Dict[str, Any]]:
+ if not isinstance(message, Message):
+ return False
+
+ text = message.text or message.caption
+ if not text:
+ return False
+
+ try:
+ command = await self.parse_command(text=text, bot=bot)
+ except CommandException:
+ return False
+ result = {"command": command}
+ if command.magic_result and isinstance(command.magic_result, dict):
+ result.update(command.magic_result)
+ return result
+
+ def extract_command(self, text: str) -> CommandObject:
+ # First step: separate command with arguments
+ # "/command@mention arg1 arg2" -> "/command@mention", ["arg1 arg2"]
+ try:
+ full_command, *args = text.split(maxsplit=1)
+ except ValueError:
+ raise CommandException("not enough values to unpack")
+
+ # Separate command into valuable parts
+ # "/command@mention" -> "/", ("command", "@", "mention")
+ prefix, (command, _, mention) = full_command[0], full_command[1:].partition("@")
+ return CommandObject(
+ prefix=prefix,
+ command=command,
+ mention=mention or None,
+ args=args[0] if args else None,
+ )
+
+ def validate_prefix(self, command: CommandObject) -> None:
+ if command.prefix not in self.prefix:
+ raise CommandException("Invalid command prefix")
+
+ async def validate_mention(self, bot: Bot, command: CommandObject) -> None:
+ if command.mention and not self.ignore_mention:
+ me = await bot.me()
+ if me.username and command.mention.lower() != me.username.lower():
+ raise CommandException("Mention did not match")
+
+ def validate_command(self, command: CommandObject) -> CommandObject:
+ for allowed_command in cast(Sequence[CommandPatternType], self.commands):
+ # Command can be presented as regexp pattern or raw string
+ # then need to validate that in different ways
+ if isinstance(allowed_command, Pattern): # Regexp
+ result = allowed_command.match(command.command)
+ if result:
+ return replace(command, regexp_match=result)
+
+ command_name = command.command
+ if self.ignore_case:
+ command_name = command_name.casefold()
+
+ if command_name == allowed_command: # String
+ return command
+ raise CommandException("Command did not match pattern")
+
+ async def parse_command(self, text: str, bot: Bot) -> CommandObject:
+ """
+ Extract command from the text and validate
+
+ :param text:
+ :param bot:
+ :return:
+ """
+ command = self.extract_command(text)
+ self.validate_prefix(command=command)
+ await self.validate_mention(bot=bot, command=command)
+ command = self.validate_command(command)
+ command = self.do_magic(command=command)
+ return command # noqa: RET504
+
+ def do_magic(self, command: CommandObject) -> Any:
+ if self.magic is None:
+ return command
+ result = self.magic.resolve(command)
+ if not result:
+ raise CommandException("Rejected via magic filter")
+ return replace(command, magic_result=result)
+
+
+@dataclass(frozen=True)
+class CommandObject:
+ """
+ Instance of this object is always has command and it prefix.
+ Can be passed as keyword argument **command** to the handler
+ """
+
+ prefix: str = "/"
+ """Command prefix"""
+ command: str = ""
+ """Command without prefix and mention"""
+ mention: Optional[str] = None
+ """Mention (if available)"""
+ args: Optional[str] = field(repr=False, default=None)
+ """Command argument"""
+ regexp_match: Optional[Match[str]] = field(repr=False, default=None)
+ """Will be presented match result if the command is presented as regexp in filter"""
+ magic_result: Optional[Any] = field(repr=False, default=None)
+
+ @property
+ def mentioned(self) -> bool:
+ """
+ This command has mention?
+ """
+ return bool(self.mention)
+
+ @property
+ def text(self) -> str:
+ """
+ Generate original text from object
+ """
+ line = self.prefix + self.command
+ if self.mention:
+ line += "@" + self.mention
+ if self.args:
+ line += " " + self.args
+ return line
+
+
+class CommandStart(Command):
+ def __init__(
+ self,
+ deep_link: bool = False,
+ deep_link_encoded: bool = False,
+ ignore_case: bool = False,
+ ignore_mention: bool = False,
+ magic: Optional[MagicFilter] = None,
+ ):
+ super().__init__(
+ "start",
+ prefix="/",
+ ignore_case=ignore_case,
+ ignore_mention=ignore_mention,
+ magic=magic,
+ )
+ self.deep_link = deep_link
+ self.deep_link_encoded = deep_link_encoded
+
+ def __str__(self) -> str:
+ return self._signature_to_string(
+ ignore_case=self.ignore_case,
+ ignore_mention=self.ignore_mention,
+ magic=self.magic,
+ deep_link=self.deep_link,
+ deep_link_encoded=self.deep_link_encoded,
+ )
+
+ async def parse_command(self, text: str, bot: Bot) -> CommandObject:
+ """
+ Extract command from the text and validate
+
+ :param text:
+ :param bot:
+ :return:
+ """
+ command = self.extract_command(text)
+ self.validate_prefix(command=command)
+ await self.validate_mention(bot=bot, command=command)
+ command = self.validate_command(command)
+ command = self.validate_deeplink(command=command)
+ command = self.do_magic(command=command)
+ return command # noqa: RET504
+
+ def validate_deeplink(self, command: CommandObject) -> CommandObject:
+ if not self.deep_link:
+ return command
+ if not command.args:
+ raise CommandException("Deep-link was missing")
+ args = command.args
+ if self.deep_link_encoded:
+ try:
+ args = decode_payload(args)
+ except UnicodeDecodeError as e:
+ raise CommandException(f"Failed to decode Base64: {e}")
+ return replace(command, args=args)
+ return command
diff --git a/myenv/Lib/site-packages/aiogram/filters/exception.py b/myenv/Lib/site-packages/aiogram/filters/exception.py
new file mode 100644
index 0000000..2530d75
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/exception.py
@@ -0,0 +1,55 @@
+import re
+from typing import Any, Dict, Pattern, Type, Union, cast
+
+from aiogram.filters.base import Filter
+from aiogram.types import TelegramObject
+from aiogram.types.error_event import ErrorEvent
+
+
+class ExceptionTypeFilter(Filter):
+ """
+ Allows to match exception by type
+ """
+
+ __slots__ = ("exceptions",)
+
+ def __init__(self, *exceptions: Type[Exception]):
+ """
+ :param exceptions: Exception type(s)
+ """
+ if not exceptions:
+ raise ValueError("At least one exception type is required")
+ self.exceptions = exceptions
+
+ async def __call__(self, obj: TelegramObject) -> Union[bool, Dict[str, Any]]:
+ return isinstance(cast(ErrorEvent, obj).exception, self.exceptions)
+
+
+class ExceptionMessageFilter(Filter):
+ """
+ Allow to match exception by message
+ """
+
+ __slots__ = ("pattern",)
+
+ def __init__(self, pattern: Union[str, Pattern[str]]):
+ """
+ :param pattern: Regexp pattern
+ """
+ if isinstance(pattern, str):
+ pattern = re.compile(pattern)
+ self.pattern = pattern
+
+ def __str__(self) -> str:
+ return self._signature_to_string(
+ pattern=self.pattern,
+ )
+
+ async def __call__(
+ self,
+ obj: TelegramObject,
+ ) -> Union[bool, Dict[str, Any]]:
+ result = self.pattern.match(str(cast(ErrorEvent, obj).exception))
+ if not result:
+ return False
+ return {"match_exception": result}
diff --git a/myenv/Lib/site-packages/aiogram/filters/logic.py b/myenv/Lib/site-packages/aiogram/filters/logic.py
new file mode 100644
index 0000000..7cd2503
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/logic.py
@@ -0,0 +1,77 @@
+from abc import ABC
+from typing import TYPE_CHECKING, Any, Dict, Union
+
+from aiogram.filters import Filter
+
+if TYPE_CHECKING:
+ from aiogram.dispatcher.event.handler import CallbackType, FilterObject
+
+
+class _LogicFilter(Filter, ABC):
+ pass
+
+
+class _InvertFilter(_LogicFilter):
+ __slots__ = ("target",)
+
+ def __init__(self, target: "FilterObject") -> None:
+ self.target = target
+
+ async def __call__(self, *args: Any, **kwargs: Any) -> Union[bool, Dict[str, Any]]:
+ return not bool(await self.target.call(*args, **kwargs))
+
+
+class _AndFilter(_LogicFilter):
+ __slots__ = ("targets",)
+
+ def __init__(self, *targets: "FilterObject") -> None:
+ self.targets = targets
+
+ async def __call__(self, *args: Any, **kwargs: Any) -> Union[bool, Dict[str, Any]]:
+ final_result = {}
+
+ for target in self.targets:
+ result = await target.call(*args, **kwargs)
+ if not result:
+ return False
+ if isinstance(result, dict):
+ final_result.update(result)
+
+ if final_result:
+ return final_result
+ return True
+
+
+class _OrFilter(_LogicFilter):
+ __slots__ = ("targets",)
+
+ def __init__(self, *targets: "FilterObject") -> None:
+ self.targets = targets
+
+ async def __call__(self, *args: Any, **kwargs: Any) -> Union[bool, Dict[str, Any]]:
+ for target in self.targets:
+ result = await target.call(*args, **kwargs)
+ if not result:
+ continue
+ if isinstance(result, dict):
+ return result
+ return bool(result)
+ return False
+
+
+def and_f(*targets: "CallbackType") -> _AndFilter:
+ from aiogram.dispatcher.event.handler import FilterObject
+
+ return _AndFilter(*(FilterObject(target) for target in targets))
+
+
+def or_f(*targets: "CallbackType") -> _OrFilter:
+ from aiogram.dispatcher.event.handler import FilterObject
+
+ return _OrFilter(*(FilterObject(target) for target in targets))
+
+
+def invert_f(target: "CallbackType") -> _InvertFilter:
+ from aiogram.dispatcher.event.handler import FilterObject
+
+ return _InvertFilter(FilterObject(target))
diff --git a/myenv/Lib/site-packages/aiogram/filters/magic_data.py b/myenv/Lib/site-packages/aiogram/filters/magic_data.py
new file mode 100644
index 0000000..5c0d474
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/magic_data.py
@@ -0,0 +1,27 @@
+from typing import Any
+
+from magic_filter import AttrDict, MagicFilter
+
+from aiogram.filters.base import Filter
+from aiogram.types import TelegramObject
+
+
+class MagicData(Filter):
+ """
+ This filter helps to filter event with contextual data
+ """
+
+ __slots__ = ("magic_data",)
+
+ def __init__(self, magic_data: MagicFilter) -> None:
+ self.magic_data = magic_data
+
+ async def __call__(self, event: TelegramObject, *args: Any, **kwargs: Any) -> Any:
+ return self.magic_data.resolve(
+ AttrDict({"event": event, **dict(enumerate(args)), **kwargs})
+ )
+
+ def __str__(self) -> str:
+ return self._signature_to_string(
+ magic_data=self.magic_data,
+ )
diff --git a/myenv/Lib/site-packages/aiogram/filters/state.py b/myenv/Lib/site-packages/aiogram/filters/state.py
new file mode 100644
index 0000000..82a141c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/filters/state.py
@@ -0,0 +1,43 @@
+from inspect import isclass
+from typing import Any, Dict, Optional, Sequence, Type, Union, cast
+
+from aiogram.filters.base import Filter
+from aiogram.fsm.state import State, StatesGroup
+from aiogram.types import TelegramObject
+
+StateType = Union[str, None, State, StatesGroup, Type[StatesGroup]]
+
+
+class StateFilter(Filter):
+ """
+ State filter
+ """
+
+ __slots__ = ("states",)
+
+ def __init__(self, *states: StateType) -> None:
+ if not states:
+ raise ValueError("At least one state is required")
+
+ self.states = states
+
+ def __str__(self) -> str:
+ return self._signature_to_string(
+ *self.states,
+ )
+
+ async def __call__(
+ self, obj: TelegramObject, raw_state: Optional[str] = None
+ ) -> Union[bool, Dict[str, Any]]:
+ allowed_states = cast(Sequence[StateType], self.states)
+ for allowed_state in allowed_states:
+ if isinstance(allowed_state, str) or allowed_state is None:
+ if allowed_state == "*" or raw_state == allowed_state:
+ return True
+ elif isinstance(allowed_state, (State, StatesGroup)):
+ if allowed_state(event=obj, raw_state=raw_state):
+ return True
+ elif isclass(allowed_state) and issubclass(allowed_state, StatesGroup):
+ if allowed_state()(event=obj, raw_state=raw_state):
+ return True
+ return False
diff --git a/myenv/Lib/site-packages/aiogram/fsm/__init__.py b/myenv/Lib/site-packages/aiogram/fsm/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram/fsm/context.py b/myenv/Lib/site-packages/aiogram/fsm/context.py
new file mode 100644
index 0000000..c9432c1
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/context.py
@@ -0,0 +1,41 @@
+from typing import Any, Dict, Optional, overload
+
+from aiogram.fsm.storage.base import BaseStorage, StateType, StorageKey
+
+
+class FSMContext:
+ def __init__(self, storage: BaseStorage, key: StorageKey) -> None:
+ self.storage = storage
+ self.key = key
+
+ async def set_state(self, state: StateType = None) -> None:
+ await self.storage.set_state(key=self.key, state=state)
+
+ async def get_state(self) -> Optional[str]:
+ return await self.storage.get_state(key=self.key)
+
+ async def set_data(self, data: Dict[str, Any]) -> None:
+ await self.storage.set_data(key=self.key, data=data)
+
+ async def get_data(self) -> Dict[str, Any]:
+ return await self.storage.get_data(key=self.key)
+
+ @overload
+ async def get_value(self, key: str) -> Optional[Any]: ...
+
+ @overload
+ async def get_value(self, key: str, default: Any) -> Any: ...
+
+ async def get_value(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
+ return await self.storage.get_value(storage_key=self.key, dict_key=key, default=default)
+
+ async def update_data(
+ self, data: Optional[Dict[str, Any]] = None, **kwargs: Any
+ ) -> Dict[str, Any]:
+ if data:
+ kwargs.update(data)
+ return await self.storage.update_data(key=self.key, data=kwargs)
+
+ async def clear(self) -> None:
+ await self.set_state(state=None)
+ await self.set_data({})
diff --git a/myenv/Lib/site-packages/aiogram/fsm/middleware.py b/myenv/Lib/site-packages/aiogram/fsm/middleware.py
new file mode 100644
index 0000000..de93457
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/middleware.py
@@ -0,0 +1,113 @@
+from typing import Any, Awaitable, Callable, Dict, Optional, cast
+
+from aiogram import Bot
+from aiogram.dispatcher.middlewares.base import BaseMiddleware
+from aiogram.dispatcher.middlewares.user_context import EVENT_CONTEXT_KEY, EventContext
+from aiogram.fsm.context import FSMContext
+from aiogram.fsm.storage.base import (
+ DEFAULT_DESTINY,
+ BaseEventIsolation,
+ BaseStorage,
+ StorageKey,
+)
+from aiogram.fsm.strategy import FSMStrategy, apply_strategy
+from aiogram.types import TelegramObject
+
+
+class FSMContextMiddleware(BaseMiddleware):
+ def __init__(
+ self,
+ storage: BaseStorage,
+ events_isolation: BaseEventIsolation,
+ strategy: FSMStrategy = FSMStrategy.USER_IN_CHAT,
+ ) -> None:
+ self.storage = storage
+ self.strategy = strategy
+ self.events_isolation = events_isolation
+
+ async def __call__(
+ self,
+ handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
+ event: TelegramObject,
+ data: Dict[str, Any],
+ ) -> Any:
+ bot: Bot = cast(Bot, data["bot"])
+ context = self.resolve_event_context(bot, data)
+ data["fsm_storage"] = self.storage
+ if context:
+ # Bugfix: https://github.com/aiogram/aiogram/issues/1317
+ # State should be loaded after lock is acquired
+ async with self.events_isolation.lock(key=context.key):
+ data.update({"state": context, "raw_state": await context.get_state()})
+ return await handler(event, data)
+ return await handler(event, data)
+
+ def resolve_event_context(
+ self,
+ bot: Bot,
+ data: Dict[str, Any],
+ destiny: str = DEFAULT_DESTINY,
+ ) -> Optional[FSMContext]:
+ event_context: EventContext = cast(EventContext, data.get(EVENT_CONTEXT_KEY))
+ return self.resolve_context(
+ bot=bot,
+ chat_id=event_context.chat_id,
+ user_id=event_context.user_id,
+ thread_id=event_context.thread_id,
+ business_connection_id=event_context.business_connection_id,
+ destiny=destiny,
+ )
+
+ def resolve_context(
+ self,
+ bot: Bot,
+ chat_id: Optional[int],
+ user_id: Optional[int],
+ thread_id: Optional[int] = None,
+ business_connection_id: Optional[str] = None,
+ destiny: str = DEFAULT_DESTINY,
+ ) -> Optional[FSMContext]:
+ if chat_id is None:
+ chat_id = user_id
+
+ if chat_id is not None and user_id is not None:
+ chat_id, user_id, thread_id = apply_strategy(
+ chat_id=chat_id,
+ user_id=user_id,
+ thread_id=thread_id,
+ strategy=self.strategy,
+ )
+ return self.get_context(
+ bot=bot,
+ chat_id=chat_id,
+ user_id=user_id,
+ thread_id=thread_id,
+ business_connection_id=business_connection_id,
+ destiny=destiny,
+ )
+ return None
+
+ def get_context(
+ self,
+ bot: Bot,
+ chat_id: int,
+ user_id: int,
+ thread_id: Optional[int] = None,
+ business_connection_id: Optional[str] = None,
+ destiny: str = DEFAULT_DESTINY,
+ ) -> FSMContext:
+ return FSMContext(
+ storage=self.storage,
+ key=StorageKey(
+ user_id=user_id,
+ chat_id=chat_id,
+ bot_id=bot.id,
+ thread_id=thread_id,
+ business_connection_id=business_connection_id,
+ destiny=destiny,
+ ),
+ )
+
+ async def close(self) -> None:
+ await self.storage.close()
+ await self.events_isolation.close()
diff --git a/myenv/Lib/site-packages/aiogram/fsm/scene.py b/myenv/Lib/site-packages/aiogram/fsm/scene.py
new file mode 100644
index 0000000..1344b4d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/scene.py
@@ -0,0 +1,952 @@
+from __future__ import annotations
+
+import inspect
+from collections import defaultdict
+from dataclasses import dataclass, replace
+from enum import Enum, auto
+from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, Union, overload
+
+from typing_extensions import Self
+
+from aiogram import loggers
+from aiogram.dispatcher.dispatcher import Dispatcher
+from aiogram.dispatcher.event.bases import NextMiddlewareType
+from aiogram.dispatcher.event.handler import CallableObject, CallbackType
+from aiogram.dispatcher.flags import extract_flags_from_object
+from aiogram.dispatcher.router import Router
+from aiogram.exceptions import SceneException
+from aiogram.filters import StateFilter
+from aiogram.fsm.context import FSMContext
+from aiogram.fsm.state import State
+from aiogram.fsm.storage.memory import MemoryStorageRecord
+from aiogram.types import TelegramObject, Update
+from aiogram.utils.class_attrs_resolver import (
+ ClassAttrsResolver,
+ get_sorted_mro_attrs_resolver,
+)
+
+
+class HistoryManager:
+ def __init__(self, state: FSMContext, destiny: str = "scenes_history", size: int = 10):
+ self._size = size
+ self._state = state
+ self._history_state = FSMContext(
+ storage=state.storage, key=replace(state.key, destiny=destiny)
+ )
+
+ async def push(self, state: Optional[str], data: Dict[str, Any]) -> None:
+ history_data = await self._history_state.get_data()
+ history = history_data.setdefault("history", [])
+ history.append({"state": state, "data": data})
+ if len(history) > self._size:
+ history = history[-self._size :]
+ loggers.scene.debug("Push state=%s data=%s to history", state, data)
+
+ await self._history_state.update_data(history=history)
+
+ async def pop(self) -> Optional[MemoryStorageRecord]:
+ history_data = await self._history_state.get_data()
+ history = history_data.setdefault("history", [])
+ if not history:
+ return None
+ record = history.pop()
+ state = record["state"]
+ data = record["data"]
+ if not history:
+ await self._history_state.set_data({})
+ else:
+ await self._history_state.update_data(history=history)
+ loggers.scene.debug("Pop state=%s data=%s from history", state, data)
+ return MemoryStorageRecord(state=state, data=data)
+
+ async def get(self) -> Optional[MemoryStorageRecord]:
+ history_data = await self._history_state.get_data()
+ history = history_data.setdefault("history", [])
+ if not history:
+ return None
+ return MemoryStorageRecord(**history[-1])
+
+ async def all(self) -> List[MemoryStorageRecord]:
+ history_data = await self._history_state.get_data()
+ history = history_data.setdefault("history", [])
+ return [MemoryStorageRecord(**item) for item in history]
+
+ async def clear(self) -> None:
+ loggers.scene.debug("Clear history")
+ await self._history_state.set_data({})
+
+ async def snapshot(self) -> None:
+ state = await self._state.get_state()
+ data = await self._state.get_data()
+ await self.push(state, data)
+
+ async def _set_state(self, state: Optional[str], data: Dict[str, Any]) -> None:
+ await self._state.set_state(state)
+ await self._state.set_data(data)
+
+ async def rollback(self) -> Optional[str]:
+ previous_state = await self.pop()
+ if not previous_state:
+ await self._set_state(None, {})
+ return None
+
+ loggers.scene.debug(
+ "Rollback to state=%s data=%s",
+ previous_state.state,
+ previous_state.data,
+ )
+ await self._set_state(previous_state.state, previous_state.data)
+ return previous_state.state
+
+
+class ObserverDecorator:
+ def __init__(
+ self,
+ name: str,
+ filters: tuple[CallbackType, ...],
+ action: SceneAction | None = None,
+ after: Optional[After] = None,
+ ) -> None:
+ self.name = name
+ self.filters = filters
+ self.action = action
+ self.after = after
+
+ def _wrap_filter(self, target: Type[Scene] | CallbackType) -> None:
+ handlers = getattr(target, "__aiogram_handler__", None)
+ if not handlers:
+ handlers = []
+ setattr(target, "__aiogram_handler__", handlers)
+
+ handlers.append(
+ HandlerContainer(
+ name=self.name,
+ handler=target,
+ filters=self.filters,
+ after=self.after,
+ )
+ )
+
+ def _wrap_action(self, target: CallbackType) -> None:
+ assert self.action is not None, "Scene action is not specified"
+
+ action = getattr(target, "__aiogram_action__", None)
+ if action is None:
+ action = defaultdict(dict)
+ setattr(target, "__aiogram_action__", action)
+ action[self.action][self.name] = CallableObject(target)
+
+ def __call__(self, target: CallbackType) -> CallbackType:
+ if inspect.isfunction(target):
+ if self.action is None:
+ self._wrap_filter(target)
+ else:
+ self._wrap_action(target)
+ else:
+ raise TypeError("Only function or method is allowed")
+ return target
+
+ def leave(self) -> ActionContainer:
+ return ActionContainer(self.name, self.filters, SceneAction.leave)
+
+ def enter(self, target: Type[Scene]) -> ActionContainer:
+ return ActionContainer(self.name, self.filters, SceneAction.enter, target)
+
+ def exit(self) -> ActionContainer:
+ return ActionContainer(self.name, self.filters, SceneAction.exit)
+
+ def back(self) -> ActionContainer:
+ return ActionContainer(self.name, self.filters, SceneAction.back)
+
+
+class SceneAction(Enum):
+ enter = auto()
+ leave = auto()
+ exit = auto()
+ back = auto()
+
+
+class ActionContainer:
+ def __init__(
+ self,
+ name: str,
+ filters: Tuple[CallbackType, ...],
+ action: SceneAction,
+ target: Optional[Union[Type[Scene], str]] = None,
+ ) -> None:
+ self.name = name
+ self.filters = filters
+ self.action = action
+ self.target = target
+
+ async def execute(self, wizard: SceneWizard) -> None:
+ if self.action == SceneAction.enter and self.target is not None:
+ await wizard.goto(self.target)
+ elif self.action == SceneAction.leave:
+ await wizard.leave()
+ elif self.action == SceneAction.exit:
+ await wizard.exit()
+ elif self.action == SceneAction.back:
+ await wizard.back()
+
+
+class HandlerContainer:
+ def __init__(
+ self,
+ name: str,
+ handler: CallbackType,
+ filters: Tuple[CallbackType, ...],
+ after: Optional[After] = None,
+ ) -> None:
+ self.name = name
+ self.handler = handler
+ self.filters = filters
+ self.after = after
+
+
+@dataclass()
+class SceneConfig:
+ state: Optional[str]
+ """Scene state"""
+ handlers: List[HandlerContainer]
+ """Scene handlers"""
+ actions: Dict[SceneAction, Dict[str, CallableObject]]
+ """Scene actions"""
+ reset_data_on_enter: Optional[bool] = None
+ """Reset scene data on enter"""
+ reset_history_on_enter: Optional[bool] = None
+ """Reset scene history on enter"""
+ callback_query_without_state: Optional[bool] = None
+ """Allow callback query without state"""
+ attrs_resolver: ClassAttrsResolver = get_sorted_mro_attrs_resolver
+ """
+ Attributes resolver.
+
+ .. danger::
+ This attribute should only be changed when you know what you are doing.
+
+ .. versionadded:: 3.19.0
+ """
+
+
+async def _empty_handler(*args: Any, **kwargs: Any) -> None:
+ pass
+
+
+class SceneHandlerWrapper:
+ def __init__(
+ self,
+ scene: Type[Scene],
+ handler: CallbackType,
+ after: Optional[After] = None,
+ ) -> None:
+ self.scene = scene
+ self.handler = CallableObject(handler)
+ self.after = after
+
+ async def __call__(
+ self,
+ event: TelegramObject,
+ **kwargs: Any,
+ ) -> Any:
+ state: FSMContext = kwargs["state"]
+ scenes: ScenesManager = kwargs["scenes"]
+ event_update: Update = kwargs["event_update"]
+ scene = self.scene(
+ wizard=SceneWizard(
+ scene_config=self.scene.__scene_config__,
+ manager=scenes,
+ state=state,
+ update_type=event_update.event_type,
+ event=event,
+ data=kwargs,
+ )
+ )
+
+ result = await self.handler.call(scene, event, **kwargs)
+
+ if self.after:
+ action_container = ActionContainer(
+ "after",
+ (),
+ self.after.action,
+ self.after.scene,
+ )
+ await action_container.execute(scene.wizard)
+ return result
+
+ def __await__(self) -> Self:
+ return self
+
+ def __str__(self) -> str:
+ result = f"SceneHandlerWrapper({self.scene}, {self.handler.callback}"
+ if self.after:
+ result += f", after={self.after}"
+ result += ")"
+ return result
+
+
+class Scene:
+ """
+ Represents a scene in a conversation flow.
+
+ A scene is a specific state in a conversation where certain actions can take place.
+
+ Each scene has a set of filters that determine when it should be triggered,
+ and a set of handlers that define the actions to be executed when the scene is active.
+
+ .. note::
+ This class is not meant to be used directly. Instead, it should be subclassed
+ to define custom scenes.
+ """
+
+ __scene_config__: ClassVar[SceneConfig]
+ """Scene configuration."""
+
+ def __init__(
+ self,
+ wizard: SceneWizard,
+ ) -> None:
+ self.wizard = wizard
+ self.wizard.scene = self
+
+ def __init_subclass__(cls, **kwargs: Any) -> None:
+ state_name = kwargs.pop("state", None)
+ reset_data_on_enter = kwargs.pop("reset_data_on_enter", None)
+ reset_history_on_enter = kwargs.pop("reset_history_on_enter", None)
+ callback_query_without_state = kwargs.pop("callback_query_without_state", None)
+ attrs_resolver = kwargs.pop("attrs_resolver", None)
+
+ super().__init_subclass__(**kwargs)
+
+ handlers: list[HandlerContainer] = []
+ actions: defaultdict[SceneAction, Dict[str, CallableObject]] = defaultdict(dict)
+
+ for base in cls.__bases__:
+ if not issubclass(base, Scene):
+ continue
+
+ parent_scene_config = getattr(base, "__scene_config__", None)
+ if not parent_scene_config:
+ continue
+
+ if reset_data_on_enter is None:
+ reset_data_on_enter = parent_scene_config.reset_data_on_enter
+ if reset_history_on_enter is None:
+ reset_history_on_enter = parent_scene_config.reset_history_on_enter
+ if callback_query_without_state is None:
+ callback_query_without_state = parent_scene_config.callback_query_without_state
+ if attrs_resolver is None:
+ attrs_resolver = parent_scene_config.attrs_resolver
+
+ if attrs_resolver is None:
+ attrs_resolver = get_sorted_mro_attrs_resolver
+
+ for name, value in attrs_resolver(cls):
+ if scene_handlers := getattr(value, "__aiogram_handler__", None):
+ handlers.extend(scene_handlers)
+ if isinstance(value, ObserverDecorator):
+ handlers.append(
+ HandlerContainer(
+ value.name,
+ _empty_handler,
+ value.filters,
+ after=value.after,
+ )
+ )
+ if hasattr(value, "__aiogram_action__"):
+ for action, action_handlers in value.__aiogram_action__.items():
+ actions[action].update(action_handlers)
+
+ cls.__scene_config__ = SceneConfig(
+ state=state_name,
+ handlers=handlers,
+ actions=dict(actions),
+ reset_data_on_enter=reset_data_on_enter,
+ reset_history_on_enter=reset_history_on_enter,
+ callback_query_without_state=callback_query_without_state,
+ attrs_resolver=attrs_resolver,
+ )
+
+ @classmethod
+ def add_to_router(cls, router: Router) -> None:
+ """
+ Adds the scene to the given router.
+
+ :param router:
+ :return:
+ """
+ scene_config = cls.__scene_config__
+ used_observers = set()
+
+ for handler in scene_config.handlers:
+ router.observers[handler.name].register(
+ SceneHandlerWrapper(
+ cls,
+ handler.handler,
+ after=handler.after,
+ ),
+ *handler.filters,
+ flags=extract_flags_from_object(handler.handler),
+ )
+ used_observers.add(handler.name)
+
+ for observer_name in used_observers:
+ if scene_config.callback_query_without_state and observer_name == "callback_query":
+ continue
+ router.observers[observer_name].filter(StateFilter(scene_config.state))
+
+ @classmethod
+ def as_router(cls, name: Optional[str] = None) -> Router:
+ """
+ Returns the scene as a router.
+
+ :return: new router
+ """
+ if name is None:
+ name = (
+ f"Scene '{cls.__module__}.{cls.__qualname__}' "
+ f"for state {cls.__scene_config__.state!r}"
+ )
+ router = Router(name=name)
+ cls.add_to_router(router)
+ return router
+
+ @classmethod
+ def as_handler(cls, **kwargs: Any) -> CallbackType:
+ """
+ Create an entry point handler for the scene, can be used to simplify the handler
+ that starts the scene.
+
+ >>> router.message.register(MyScene.as_handler(), Command("start"))
+ """
+
+ async def enter_to_scene_handler(event: TelegramObject, scenes: ScenesManager) -> None:
+ await scenes.enter(cls, **kwargs)
+
+ return enter_to_scene_handler
+
+
+class SceneWizard:
+ """
+ A class that represents a wizard for managing scenes in a Telegram bot.
+
+ Instance of this class is passed to each scene as a parameter.
+ So, you can use it to transition between scenes, get and set data, etc.
+
+ .. note::
+
+ This class is not meant to be used directly. Instead, it should be used
+ as a parameter in the scene constructor.
+
+ """
+
+ def __init__(
+ self,
+ scene_config: SceneConfig,
+ manager: ScenesManager,
+ state: FSMContext,
+ update_type: str,
+ event: TelegramObject,
+ data: Dict[str, Any],
+ ):
+ """
+ A class that represents a wizard for managing scenes in a Telegram bot.
+
+ :param scene_config: The configuration of the scene.
+ :param manager: The scene manager.
+ :param state: The FSMContext object for storing the state of the scene.
+ :param update_type: The type of the update event.
+ :param event: The TelegramObject represents the event.
+ :param data: Additional data for the scene.
+ """
+ self.scene_config = scene_config
+ self.manager = manager
+ self.state = state
+ self.update_type = update_type
+ self.event = event
+ self.data = data
+
+ self.scene: Optional[Scene] = None
+
+ async def enter(self, **kwargs: Any) -> None:
+ """
+ Enter method is used to transition into a scene in the SceneWizard class.
+ It sets the state, clears data and history if specified,
+ and triggers entering event of the scene.
+
+ :param kwargs: Additional keyword arguments.
+ :return: None
+ """
+ loggers.scene.debug("Entering scene %r", self.scene_config.state)
+ if self.scene_config.reset_data_on_enter:
+ await self.state.set_data({})
+ if self.scene_config.reset_history_on_enter:
+ await self.manager.history.clear()
+ await self.state.set_state(self.scene_config.state)
+ await self._on_action(SceneAction.enter, **kwargs)
+
+ async def leave(self, _with_history: bool = True, **kwargs: Any) -> None:
+ """
+ Leaves the current scene.
+ This method is used to exit a scene and transition to the next scene.
+
+ :param _with_history: Whether to include history in the snapshot. Defaults to True.
+ :param kwargs: Additional keyword arguments.
+ :return: None
+
+ """
+ loggers.scene.debug("Leaving scene %r", self.scene_config.state)
+ if _with_history:
+ await self.manager.history.snapshot()
+ await self._on_action(SceneAction.leave, **kwargs)
+
+ async def exit(self, **kwargs: Any) -> None:
+ """
+ Exit the current scene and enter the default scene/state.
+
+ :param kwargs: Additional keyword arguments.
+ :return: None
+ """
+ loggers.scene.debug("Exiting scene %r", self.scene_config.state)
+ await self.manager.history.clear()
+ await self._on_action(SceneAction.exit, **kwargs)
+ await self.manager.enter(None, _check_active=False, **kwargs)
+
+ async def back(self, **kwargs: Any) -> None:
+ """
+ This method is used to go back to the previous scene.
+
+ :param kwargs: Keyword arguments that can be passed to the method.
+ :return: None
+ """
+ loggers.scene.debug("Back to previous scene from scene %s", self.scene_config.state)
+ await self.leave(_with_history=False, **kwargs)
+ new_scene = await self.manager.history.rollback()
+ await self.manager.enter(new_scene, _check_active=False, **kwargs)
+
+ async def retake(self, **kwargs: Any) -> None:
+ """
+ This method allows to re-enter the current scene.
+
+ :param kwargs: Additional keyword arguments to pass to the scene.
+ :return: None
+ """
+ assert self.scene_config.state is not None, "Scene state is not specified"
+ await self.goto(self.scene_config.state, **kwargs)
+
+ async def goto(self, scene: Union[Type[Scene], str], **kwargs: Any) -> None:
+ """
+ The `goto` method transitions to a new scene.
+ It first calls the `leave` method to perform any necessary cleanup
+ in the current scene, then calls the `enter` event to enter the specified scene.
+
+ :param scene: The scene to transition to. Can be either a `Scene` instance
+ or a string representing the scene.
+ :param kwargs: Additional keyword arguments to pass to the `enter`
+ method of the scene manager.
+ :return: None
+ """
+ await self.leave(**kwargs)
+ await self.manager.enter(scene, _check_active=False, **kwargs)
+
+ async def _on_action(self, action: SceneAction, **kwargs: Any) -> bool:
+ if not self.scene:
+ raise SceneException("Scene is not initialized")
+
+ loggers.scene.debug("Call action %r in scene %r", action.name, self.scene_config.state)
+ action_config = self.scene_config.actions.get(action, {})
+ if not action_config:
+ loggers.scene.debug(
+ "Action %r not found in scene %r", action.name, self.scene_config.state
+ )
+ return False
+
+ event_type = self.update_type
+ if event_type not in action_config:
+ loggers.scene.debug(
+ "Action %r for event %r not found in scene %r",
+ action.name,
+ event_type,
+ self.scene_config.state,
+ )
+ return False
+
+ await action_config[event_type].call(self.scene, self.event, **{**self.data, **kwargs})
+ return True
+
+ async def set_data(self, data: Dict[str, Any]) -> None:
+ """
+ Sets custom data in the current state.
+
+ :param data: A dictionary containing the custom data to be set in the current state.
+ :return: None
+ """
+ await self.state.set_data(data=data)
+
+ async def get_data(self) -> Dict[str, Any]:
+ """
+ This method returns the data stored in the current state.
+
+ :return: A dictionary containing the data stored in the scene state.
+ """
+ return await self.state.get_data()
+
+ @overload
+ async def get_value(self, key: str) -> Optional[Any]:
+ """
+ This method returns the value from key in the data of the current state.
+
+ :param key: The keyname of the item you want to return the value from.
+
+ :return: A dictionary containing the data stored in the scene state.
+ """
+ pass
+
+ @overload
+ async def get_value(self, key: str, default: Any) -> Any:
+ """
+ This method returns the value from key in the data of the current state.
+
+ :param key: The keyname of the item you want to return the value from.
+ :param default: Default value to return, if ``key`` was not found.
+
+ :return: A dictionary containing the data stored in the scene state.
+ """
+ pass
+
+ async def get_value(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
+ return await self.state.get_value(key, default)
+
+ async def update_data(
+ self, data: Optional[Dict[str, Any]] = None, **kwargs: Any
+ ) -> Dict[str, Any]:
+ """
+ This method updates the data stored in the current state
+
+ :param data: Optional dictionary of data to update.
+ :param kwargs: Additional key-value pairs of data to update.
+ :return: Dictionary of updated data
+ """
+ if data:
+ kwargs.update(data)
+ return await self.state.update_data(data=kwargs)
+
+ async def clear_data(self) -> None:
+ """
+ Clears the data.
+
+ :return: None
+ """
+ await self.set_data({})
+
+
+class ScenesManager:
+ """
+ The ScenesManager class is responsible for managing scenes in an application.
+ It provides methods for entering and exiting scenes, as well as retrieving the active scene.
+ """
+
+ def __init__(
+ self,
+ registry: SceneRegistry,
+ update_type: str,
+ event: TelegramObject,
+ state: FSMContext,
+ data: Dict[str, Any],
+ ) -> None:
+ self.registry = registry
+ self.update_type = update_type
+ self.event = event
+ self.state = state
+ self.data = data
+
+ self.history = HistoryManager(self.state)
+
+ async def _get_scene(self, scene_type: Optional[Union[Type[Scene], str]]) -> Scene:
+ scene_type = self.registry.get(scene_type)
+ return scene_type(
+ wizard=SceneWizard(
+ scene_config=scene_type.__scene_config__,
+ manager=self,
+ state=self.state,
+ update_type=self.update_type,
+ event=self.event,
+ data=self.data,
+ ),
+ )
+
+ async def _get_active_scene(self) -> Optional[Scene]:
+ state = await self.state.get_state()
+ try:
+ return await self._get_scene(state)
+ except SceneException:
+ return None
+
+ async def enter(
+ self,
+ scene_type: Optional[Union[Type[Scene], str]],
+ _check_active: bool = True,
+ **kwargs: Any,
+ ) -> None:
+ """
+ Enters the specified scene.
+
+ :param scene_type: Optional Type[Scene] or str representing the scene type to enter.
+ :param _check_active: Optional bool indicating whether to check if
+ there is an active scene to exit before entering the new scene. Defaults to True.
+ :param kwargs: Additional keyword arguments to pass to the scene's wizard.enter() method.
+ :return: None
+ """
+ if _check_active:
+ active_scene = await self._get_active_scene()
+ if active_scene is not None:
+ await active_scene.wizard.exit(**kwargs)
+
+ try:
+ scene = await self._get_scene(scene_type)
+ except SceneException:
+ if scene_type is not None:
+ raise
+ await self.state.set_state(None)
+ else:
+ await scene.wizard.enter(**kwargs)
+
+ async def close(self, **kwargs: Any) -> None:
+ """
+ Close method is used to exit the currently active scene in the ScenesManager.
+
+ :param kwargs: Additional keyword arguments passed to the scene's exit method.
+ :return: None
+ """
+ scene = await self._get_active_scene()
+ if not scene:
+ return
+ await scene.wizard.exit(**kwargs)
+
+
+class SceneRegistry:
+ """
+ A class that represents a registry for scenes in a Telegram bot.
+ """
+
+ def __init__(self, router: Router, register_on_add: bool = True) -> None:
+ """
+ Initialize a new instance of the SceneRegistry class.
+
+ :param router: The router instance used for scene registration.
+ :param register_on_add: Whether to register the scenes to the router when they are added.
+ """
+ self.router = router
+ self.register_on_add = register_on_add
+
+ self._scenes: Dict[Optional[str], Type[Scene]] = {}
+ self._setup_middleware(router)
+
+ def _setup_middleware(self, router: Router) -> None:
+ if isinstance(router, Dispatcher):
+ # Small optimization for Dispatcher
+ # - we don't need to set up middleware for all observers
+ router.update.outer_middleware(self._update_middleware)
+ return
+
+ for observer in router.observers.values():
+ if observer.event_name in {"update", "error"}:
+ continue
+ observer.outer_middleware(self._middleware)
+
+ async def _update_middleware(
+ self,
+ handler: NextMiddlewareType[TelegramObject],
+ event: TelegramObject,
+ data: Dict[str, Any],
+ ) -> Any:
+ assert isinstance(event, Update), "Event must be an Update instance"
+
+ data["scenes"] = ScenesManager(
+ registry=self,
+ update_type=event.event_type,
+ event=event.event,
+ state=data["state"],
+ data=data,
+ )
+ return await handler(event, data)
+
+ async def _middleware(
+ self,
+ handler: NextMiddlewareType[TelegramObject],
+ event: TelegramObject,
+ data: Dict[str, Any],
+ ) -> Any:
+ update: Update = data["event_update"]
+ data["scenes"] = ScenesManager(
+ registry=self,
+ update_type=update.event_type,
+ event=event,
+ state=data["state"],
+ data=data,
+ )
+ return await handler(event, data)
+
+ def add(self, *scenes: Type[Scene], router: Optional[Router] = None) -> None:
+ """
+ This method adds the specified scenes to the registry
+ and optionally registers it to the router.
+
+ If a scene with the same state already exists in the registry, a SceneException is raised.
+
+ .. warning::
+
+ If the router is not specified, the scenes will not be registered to the router.
+ You will need to include the scenes manually to the router or use the register method.
+
+ :param scenes: A variable length parameter that accepts one or more types of scenes.
+ These scenes are instances of the Scene class.
+ :param router: An optional parameter that specifies the router
+ to which the scenes should be added.
+ :return: None
+ """
+ if not scenes:
+ raise ValueError("At least one scene must be specified")
+
+ for scene in scenes:
+ if scene.__scene_config__.state in self._scenes:
+ raise SceneException(
+ f"Scene with state {scene.__scene_config__.state!r} already exists"
+ )
+
+ self._scenes[scene.__scene_config__.state] = scene
+
+ if router:
+ router.include_router(scene.as_router())
+ elif self.register_on_add:
+ self.router.include_router(scene.as_router())
+
+ def register(self, *scenes: Type[Scene]) -> None:
+ """
+ Registers one or more scenes to the SceneRegistry.
+
+ :param scenes: One or more scene classes to register.
+ :return: None
+ """
+ self.add(*scenes, router=self.router)
+
+ def get(self, scene: Optional[Union[Type[Scene], str]]) -> Type[Scene]:
+ """
+ This method returns the registered Scene object for the specified scene.
+ The scene parameter can be either a Scene object or a string representing
+ the name of the scene. If a Scene object is provided, the state attribute
+ of the SceneConfig object associated with the Scene object will be used as the scene name.
+ If None or an invalid type is provided, a SceneException will be raised.
+
+ If the specified scene is not registered in the SceneRegistry object,
+ a SceneException will be raised.
+
+ :param scene: A Scene object or a string representing the name of the scene.
+ :return: The registered Scene object corresponding to the given scene parameter.
+
+ """
+ if inspect.isclass(scene) and issubclass(scene, Scene):
+ scene = scene.__scene_config__.state
+ if isinstance(scene, State):
+ scene = scene.state
+ if scene is not None and not isinstance(scene, str):
+ raise SceneException("Scene must be a subclass of Scene or a string")
+
+ try:
+ return self._scenes[scene]
+ except KeyError:
+ raise SceneException(f"Scene {scene!r} is not registered")
+
+
+@dataclass
+class After:
+ action: SceneAction
+ scene: Optional[Union[Type[Scene], str]] = None
+
+ @classmethod
+ def exit(cls) -> After:
+ return cls(action=SceneAction.exit)
+
+ @classmethod
+ def back(cls) -> After:
+ return cls(action=SceneAction.back)
+
+ @classmethod
+ def goto(cls, scene: Optional[Union[Type[Scene], str]]) -> After:
+ return cls(action=SceneAction.enter, scene=scene)
+
+
+class ObserverMarker:
+ def __init__(self, name: str) -> None:
+ self.name = name
+
+ def __call__(
+ self,
+ *filters: CallbackType,
+ after: Optional[After] = None,
+ ) -> ObserverDecorator:
+ return ObserverDecorator(
+ self.name,
+ filters,
+ after=after,
+ )
+
+ def enter(self, *filters: CallbackType) -> ObserverDecorator:
+ return ObserverDecorator(self.name, filters, action=SceneAction.enter)
+
+ def leave(self) -> ObserverDecorator:
+ return ObserverDecorator(self.name, (), action=SceneAction.leave)
+
+ def exit(self) -> ObserverDecorator:
+ return ObserverDecorator(self.name, (), action=SceneAction.exit)
+
+ def back(self) -> ObserverDecorator:
+ return ObserverDecorator(self.name, (), action=SceneAction.back)
+
+
+class OnMarker:
+ """
+ The `OnMarker` class is used as a marker class to define different
+ types of events in the Scenes.
+
+ Attributes:
+
+ - :code:`message`: Event marker for handling `Message` events.
+ - :code:`edited_message`: Event marker for handling edited `Message` events.
+ - :code:`channel_post`: Event marker for handling channel `Post` events.
+ - :code:`edited_channel_post`: Event marker for handling edited channel `Post` events.
+ - :code:`inline_query`: Event marker for handling `InlineQuery` events.
+ - :code:`chosen_inline_result`: Event marker for handling chosen `InlineResult` events.
+ - :code:`callback_query`: Event marker for handling `CallbackQuery` events.
+ - :code:`shipping_query`: Event marker for handling `ShippingQuery` events.
+ - :code:`pre_checkout_query`: Event marker for handling `PreCheckoutQuery` events.
+ - :code:`poll`: Event marker for handling `Poll` events.
+ - :code:`poll_answer`: Event marker for handling `PollAnswer` events.
+ - :code:`my_chat_member`: Event marker for handling my chat `Member` events.
+ - :code:`chat_member`: Event marker for handling chat `Member` events.
+ - :code:`chat_join_request`: Event marker for handling chat `JoinRequest` events.
+ - :code:`error`: Event marker for handling `Error` events.
+
+ .. note::
+
+ This is a marker class and does not contain any methods or implementation logic.
+ """
+
+ message = ObserverMarker("message")
+ edited_message = ObserverMarker("edited_message")
+ channel_post = ObserverMarker("channel_post")
+ edited_channel_post = ObserverMarker("edited_channel_post")
+ inline_query = ObserverMarker("inline_query")
+ chosen_inline_result = ObserverMarker("chosen_inline_result")
+ callback_query = ObserverMarker("callback_query")
+ shipping_query = ObserverMarker("shipping_query")
+ pre_checkout_query = ObserverMarker("pre_checkout_query")
+ poll = ObserverMarker("poll")
+ poll_answer = ObserverMarker("poll_answer")
+ my_chat_member = ObserverMarker("my_chat_member")
+ chat_member = ObserverMarker("chat_member")
+ chat_join_request = ObserverMarker("chat_join_request")
+
+
+on = OnMarker()
diff --git a/myenv/Lib/site-packages/aiogram/fsm/state.py b/myenv/Lib/site-packages/aiogram/fsm/state.py
new file mode 100644
index 0000000..6b8c737
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/state.py
@@ -0,0 +1,172 @@
+import inspect
+from typing import Any, Iterator, Optional, Tuple, Type, no_type_check
+
+from aiogram.types import TelegramObject
+
+
+class State:
+ """
+ State object
+ """
+
+ def __init__(self, state: Optional[str] = None, group_name: Optional[str] = None) -> None:
+ self._state = state
+ self._group_name = group_name
+ self._group: Optional[Type[StatesGroup]] = None
+
+ @property
+ def group(self) -> "Type[StatesGroup]":
+ if not self._group:
+ raise RuntimeError("This state is not in any group.")
+ return self._group
+
+ @property
+ def state(self) -> Optional[str]:
+ if self._state is None or self._state == "*":
+ return self._state
+
+ if self._group_name is None and self._group:
+ group = self._group.__full_group_name__
+ elif self._group_name:
+ group = self._group_name
+ else:
+ group = "@"
+
+ return f"{group}:{self._state}"
+
+ def set_parent(self, group: "Type[StatesGroup]") -> None:
+ if not issubclass(group, StatesGroup):
+ raise ValueError("Group must be subclass of StatesGroup")
+ self._group = group
+
+ def __set_name__(self, owner: "Type[StatesGroup]", name: str) -> None:
+ if self._state is None:
+ self._state = name
+ self.set_parent(owner)
+
+ def __str__(self) -> str:
+ return f""
+
+ __repr__ = __str__
+
+ def __call__(self, event: TelegramObject, raw_state: Optional[str] = None) -> bool:
+ if self.state == "*":
+ return True
+ return raw_state == self.state
+
+ def __eq__(self, other: Any) -> bool:
+ if isinstance(other, self.__class__):
+ return self.state == other.state
+ if isinstance(other, str):
+ return self.state == other
+ return NotImplemented
+
+ def __hash__(self) -> int:
+ return hash(self.state)
+
+
+class StatesGroupMeta(type):
+ __parent__: "Optional[Type[StatesGroup]]"
+ __childs__: "Tuple[Type[StatesGroup], ...]"
+ __states__: Tuple[State, ...]
+ __state_names__: Tuple[str, ...]
+ __all_childs__: Tuple[Type["StatesGroup"], ...]
+ __all_states__: Tuple[State, ...]
+ __all_states_names__: Tuple[str, ...]
+
+ @no_type_check
+ def __new__(mcs, name, bases, namespace, **kwargs):
+ cls = super().__new__(mcs, name, bases, namespace)
+
+ states = []
+ childs = []
+
+ for name, arg in namespace.items():
+ if isinstance(arg, State):
+ states.append(arg)
+ elif inspect.isclass(arg) and issubclass(arg, StatesGroup):
+ child = cls._prepare_child(arg)
+ childs.append(child)
+
+ cls.__parent__ = None
+ cls.__childs__ = tuple(childs)
+ cls.__states__ = tuple(states)
+ cls.__state_names__ = tuple(state.state for state in states)
+
+ cls.__all_childs__ = cls._get_all_childs()
+ cls.__all_states__ = cls._get_all_states()
+
+ # In order to ensure performance, we calculate this parameter
+ # in advance already during the production of the class.
+ # Depending on the relationship, it should be recalculated
+ cls.__all_states_names__ = cls._get_all_states_names()
+
+ return cls
+
+ @property
+ def __full_group_name__(cls) -> str:
+ if cls.__parent__:
+ return ".".join((cls.__parent__.__full_group_name__, cls.__name__))
+ return cls.__name__
+
+ def _prepare_child(cls, child: Type["StatesGroup"]) -> Type["StatesGroup"]:
+ """Prepare child.
+
+ While adding `cls` for its children, we also need to recalculate
+ the parameter `__all_states_names__` for each child
+ `StatesGroup`. Since the child class appears before the
+ parent, at the time of adding the parent, the child's
+ `__all_states_names__` is already recorded without taking into
+ account the name of current parent.
+ """
+ child.__parent__ = cls # type: ignore[assignment]
+ child.__all_states_names__ = child._get_all_states_names()
+ return child
+
+ def _get_all_childs(cls) -> Tuple[Type["StatesGroup"], ...]:
+ result = cls.__childs__
+ for child in cls.__childs__:
+ result += child.__childs__
+ return result
+
+ def _get_all_states(cls) -> Tuple[State, ...]:
+ result = cls.__states__
+ for group in cls.__childs__:
+ result += group.__all_states__
+ return result
+
+ def _get_all_states_names(cls) -> Tuple[str, ...]:
+ return tuple(state.state for state in cls.__all_states__ if state.state)
+
+ def __contains__(cls, item: Any) -> bool:
+ if isinstance(item, str):
+ return item in cls.__all_states_names__
+ if isinstance(item, State):
+ return item in cls.__all_states__
+ if isinstance(item, StatesGroupMeta):
+ return item in cls.__all_childs__
+ return False
+
+ def __str__(self) -> str:
+ return f""
+
+ def __iter__(self) -> Iterator[State]:
+ return iter(self.__all_states__)
+
+
+class StatesGroup(metaclass=StatesGroupMeta):
+ @classmethod
+ def get_root(cls) -> Type["StatesGroup"]:
+ if cls.__parent__ is None:
+ return cls
+ return cls.__parent__.get_root()
+
+ def __call__(self, event: TelegramObject, raw_state: Optional[str] = None) -> bool:
+ return raw_state in type(self).__all_states_names__
+
+ def __str__(self) -> str:
+ return f"StatesGroup {type(self).__full_group_name__}"
+
+
+default_state = State()
+any_state = State(state="*")
diff --git a/myenv/Lib/site-packages/aiogram/fsm/storage/__init__.py b/myenv/Lib/site-packages/aiogram/fsm/storage/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/myenv/Lib/site-packages/aiogram/fsm/storage/base.py b/myenv/Lib/site-packages/aiogram/fsm/storage/base.py
new file mode 100644
index 0000000..96cb2cb
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/storage/base.py
@@ -0,0 +1,212 @@
+from abc import ABC, abstractmethod
+from contextlib import asynccontextmanager
+from dataclasses import dataclass
+from typing import Any, AsyncGenerator, Dict, Literal, Optional, Union, overload
+
+from aiogram.fsm.state import State
+
+StateType = Optional[Union[str, State]]
+
+DEFAULT_DESTINY = "default"
+
+
+@dataclass(frozen=True)
+class StorageKey:
+ bot_id: int
+ chat_id: int
+ user_id: int
+ thread_id: Optional[int] = None
+ business_connection_id: Optional[str] = None
+ destiny: str = DEFAULT_DESTINY
+
+
+class KeyBuilder(ABC):
+ """Base class for key builder."""
+
+ @abstractmethod
+ def build(
+ self,
+ key: StorageKey,
+ part: Optional[Literal["data", "state", "lock"]] = None,
+ ) -> str:
+ """
+ Build key to be used in storage's db queries
+
+ :param key: contextual key
+ :param part: part of the record
+ :return: key to be used in storage's db queries
+ """
+ pass
+
+
+class DefaultKeyBuilder(KeyBuilder):
+ """
+ Simple key builder with default prefix.
+
+ Generates a colon-joined string with prefix, chat_id, user_id,
+ optional bot_id, business_connection_id, destiny and field.
+
+ Format:
+ :code:`::::::`
+ """
+
+ def __init__(
+ self,
+ *,
+ prefix: str = "fsm",
+ separator: str = ":",
+ with_bot_id: bool = False,
+ with_business_connection_id: bool = False,
+ with_destiny: bool = False,
+ ) -> None:
+ """
+ :param prefix: prefix for all records
+ :param separator: separator
+ :param with_bot_id: include Bot id in the key
+ :param with_business_connection_id: include business connection id
+ :param with_destiny: include destiny key
+ """
+ self.prefix = prefix
+ self.separator = separator
+ self.with_bot_id = with_bot_id
+ self.with_business_connection_id = with_business_connection_id
+ self.with_destiny = with_destiny
+
+ def build(
+ self,
+ key: StorageKey,
+ part: Optional[Literal["data", "state", "lock"]] = None,
+ ) -> str:
+ parts = [self.prefix]
+ if self.with_bot_id:
+ parts.append(str(key.bot_id))
+ if self.with_business_connection_id and key.business_connection_id:
+ parts.append(str(key.business_connection_id))
+ parts.append(str(key.chat_id))
+ if key.thread_id:
+ parts.append(str(key.thread_id))
+ parts.append(str(key.user_id))
+ if self.with_destiny:
+ parts.append(key.destiny)
+ elif key.destiny != DEFAULT_DESTINY:
+ error_message = (
+ "Default key builder is not configured to use key destiny other than the default."
+ "\n\nProbably, you should set `with_destiny=True` in for DefaultKeyBuilder."
+ )
+ raise ValueError(error_message)
+ if part:
+ parts.append(part)
+ return self.separator.join(parts)
+
+
+class BaseStorage(ABC):
+ """
+ Base class for all FSM storages
+ """
+
+ @abstractmethod
+ async def set_state(self, key: StorageKey, state: StateType = None) -> None:
+ """
+ Set state for specified key
+
+ :param key: storage key
+ :param state: new state
+ """
+ pass
+
+ @abstractmethod
+ async def get_state(self, key: StorageKey) -> Optional[str]:
+ """
+ Get key state
+
+ :param key: storage key
+ :return: current state
+ """
+ pass
+
+ @abstractmethod
+ async def set_data(self, key: StorageKey, data: Dict[str, Any]) -> None:
+ """
+ Write data (replace)
+
+ :param key: storage key
+ :param data: new data
+ """
+ pass
+
+ @abstractmethod
+ async def get_data(self, key: StorageKey) -> Dict[str, Any]:
+ """
+ Get current data for key
+
+ :param key: storage key
+ :return: current data
+ """
+ pass
+
+ @overload
+ async def get_value(self, storage_key: StorageKey, dict_key: str) -> Optional[Any]:
+ """
+ Get single value from data by key
+
+ :param storage_key: storage key
+ :param dict_key: value key
+ :return: value stored in key of dict or ``None``
+ """
+ pass
+
+ @overload
+ async def get_value(self, storage_key: StorageKey, dict_key: str, default: Any) -> Any:
+ """
+ Get single value from data by key
+
+ :param storage_key: storage key
+ :param dict_key: value key
+ :param default: default value to return
+ :return: value stored in key of dict or default
+ """
+ pass
+
+ async def get_value(
+ self, storage_key: StorageKey, dict_key: str, default: Optional[Any] = None
+ ) -> Optional[Any]:
+ data = await self.get_data(storage_key)
+ return data.get(dict_key, default)
+
+ async def update_data(self, key: StorageKey, data: Dict[str, Any]) -> Dict[str, Any]:
+ """
+ Update date in the storage for key (like dict.update)
+
+ :param key: storage key
+ :param data: partial data
+ :return: new data
+ """
+ current_data = await self.get_data(key=key)
+ current_data.update(data)
+ await self.set_data(key=key, data=current_data)
+ return current_data.copy()
+
+ @abstractmethod
+ async def close(self) -> None: # pragma: no cover
+ """
+ Close storage (database connection, file or etc.)
+ """
+ pass
+
+
+class BaseEventIsolation(ABC):
+ @abstractmethod
+ @asynccontextmanager
+ async def lock(self, key: StorageKey) -> AsyncGenerator[None, None]:
+ """
+ Isolate events with lock.
+ Will be used as context manager
+
+ :param key: storage key
+ :return: An async generator
+ """
+ yield None
+
+ @abstractmethod
+ async def close(self) -> None:
+ pass
diff --git a/myenv/Lib/site-packages/aiogram/fsm/storage/memory.py b/myenv/Lib/site-packages/aiogram/fsm/storage/memory.py
new file mode 100644
index 0000000..f26d15c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/storage/memory.py
@@ -0,0 +1,87 @@
+from asyncio import Lock
+from collections import defaultdict
+from contextlib import asynccontextmanager
+from copy import copy
+from dataclasses import dataclass, field
+from typing import Any, AsyncGenerator, DefaultDict, Dict, Hashable, Optional, overload
+
+from aiogram.fsm.state import State
+from aiogram.fsm.storage.base import (
+ BaseEventIsolation,
+ BaseStorage,
+ StateType,
+ StorageKey,
+)
+
+
+@dataclass
+class MemoryStorageRecord:
+ data: Dict[str, Any] = field(default_factory=dict)
+ state: Optional[str] = None
+
+
+class MemoryStorage(BaseStorage):
+ """
+ Default FSM storage, stores all data in :class:`dict` and loss everything on shutdown
+
+ .. warning::
+
+ Is not recommended using in production in due to you will lose all data
+ when your bot restarts
+ """
+
+ def __init__(self) -> None:
+ self.storage: DefaultDict[StorageKey, MemoryStorageRecord] = defaultdict(
+ MemoryStorageRecord
+ )
+
+ async def close(self) -> None:
+ pass
+
+ async def set_state(self, key: StorageKey, state: StateType = None) -> None:
+ self.storage[key].state = state.state if isinstance(state, State) else state
+
+ async def get_state(self, key: StorageKey) -> Optional[str]:
+ return self.storage[key].state
+
+ async def set_data(self, key: StorageKey, data: Dict[str, Any]) -> None:
+ self.storage[key].data = data.copy()
+
+ async def get_data(self, key: StorageKey) -> Dict[str, Any]:
+ return self.storage[key].data.copy()
+
+ @overload
+ async def get_value(self, storage_key: StorageKey, dict_key: str) -> Optional[Any]: ...
+
+ @overload
+ async def get_value(self, storage_key: StorageKey, dict_key: str, default: Any) -> Any: ...
+
+ async def get_value(
+ self, storage_key: StorageKey, dict_key: str, default: Optional[Any] = None
+ ) -> Optional[Any]:
+ data = self.storage[storage_key].data
+ return copy(data.get(dict_key, default))
+
+
+class DisabledEventIsolation(BaseEventIsolation):
+ @asynccontextmanager
+ async def lock(self, key: StorageKey) -> AsyncGenerator[None, None]:
+ yield
+
+ async def close(self) -> None:
+ pass
+
+
+class SimpleEventIsolation(BaseEventIsolation):
+ def __init__(self) -> None:
+ # TODO: Unused locks cleaner is needed
+ self._locks: DefaultDict[Hashable, Lock] = defaultdict(Lock)
+
+ @asynccontextmanager
+ async def lock(self, key: StorageKey) -> AsyncGenerator[None, None]:
+ lock = self._locks[key]
+ async with lock:
+ yield
+
+ async def close(self) -> None:
+ self._locks.clear()
diff --git a/myenv/Lib/site-packages/aiogram/fsm/storage/mongo.py b/myenv/Lib/site-packages/aiogram/fsm/storage/mongo.py
new file mode 100644
index 0000000..b4b1eea
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/storage/mongo.py
@@ -0,0 +1,130 @@
+from typing import Any, Dict, Optional, cast
+
+from motor.motor_asyncio import AsyncIOMotorClient
+
+from aiogram.fsm.state import State
+from aiogram.fsm.storage.base import (
+ BaseStorage,
+ DefaultKeyBuilder,
+ KeyBuilder,
+ StateType,
+ StorageKey,
+)
+
+
+class MongoStorage(BaseStorage):
+ """
+ MongoDB storage required :code:`motor` package installed (:code:`pip install motor`)
+ """
+
+ def __init__(
+ self,
+ client: AsyncIOMotorClient,
+ key_builder: Optional[KeyBuilder] = None,
+ db_name: str = "aiogram_fsm",
+ collection_name: str = "states_and_data",
+ ) -> None:
+ """
+ :param client: Instance of AsyncIOMotorClient
+ :param key_builder: builder that helps to convert contextual key to string
+ :param db_name: name of the MongoDB database for FSM
+ :param collection_name: name of the collection for storing FSM states and data
+ """
+ if key_builder is None:
+ key_builder = DefaultKeyBuilder()
+ self._client = client
+ self._database = self._client[db_name]
+ self._collection = self._database[collection_name]
+ self._key_builder = key_builder
+
+ @classmethod
+ def from_url(
+ cls, url: str, connection_kwargs: Optional[Dict[str, Any]] = None, **kwargs: Any
+ ) -> "MongoStorage":
+ """
+ Create an instance of :class:`MongoStorage` with specifying the connection string
+
+ :param url: for example :code:`mongodb://user:password@host:port`
+ :param connection_kwargs: see :code:`motor` docs
+ :param kwargs: arguments to be passed to :class:`MongoStorage`
+ :return: an instance of :class:`MongoStorage`
+ """
+ if connection_kwargs is None:
+ connection_kwargs = {}
+ client = AsyncIOMotorClient(url, **connection_kwargs)
+ return cls(client=client, **kwargs)
+
+ async def close(self) -> None:
+ """Cleanup client resources and disconnect from MongoDB."""
+ self._client.close()
+
+ def resolve_state(self, value: StateType) -> Optional[str]:
+ if value is None:
+ return None
+ if isinstance(value, State):
+ return value.state
+ return str(value)
+
+ async def set_state(self, key: StorageKey, state: StateType = None) -> None:
+ document_id = self._key_builder.build(key)
+ if state is None:
+ updated = await self._collection.find_one_and_update(
+ filter={"_id": document_id},
+ update={"$unset": {"state": 1}},
+ projection={"_id": 0},
+ return_document=True,
+ )
+ if updated == {}:
+ await self._collection.delete_one({"_id": document_id})
+ else:
+ await self._collection.update_one(
+ filter={"_id": document_id},
+ update={"$set": {"state": self.resolve_state(state)}},
+ upsert=True,
+ )
+
+ async def get_state(self, key: StorageKey) -> Optional[str]:
+ document_id = self._key_builder.build(key)
+ document = await self._collection.find_one({"_id": document_id})
+ if document is None:
+ return None
+ return document.get("state")
+
+ async def set_data(self, key: StorageKey, data: Dict[str, Any]) -> None:
+ document_id = self._key_builder.build(key)
+ if not data:
+ updated = await self._collection.find_one_and_update(
+ filter={"_id": document_id},
+ update={"$unset": {"data": 1}},
+ projection={"_id": 0},
+ return_document=True,
+ )
+ if updated == {}:
+ await self._collection.delete_one({"_id": document_id})
+ else:
+ await self._collection.update_one(
+ filter={"_id": document_id},
+ update={"$set": {"data": data}},
+ upsert=True,
+ )
+
+ async def get_data(self, key: StorageKey) -> Dict[str, Any]:
+ document_id = self._key_builder.build(key)
+ document = await self._collection.find_one({"_id": document_id})
+ if document is None or not document.get("data"):
+ return {}
+ return cast(Dict[str, Any], document["data"])
+
+ async def update_data(self, key: StorageKey, data: Dict[str, Any]) -> Dict[str, Any]:
+ document_id = self._key_builder.build(key)
+ update_with = {f"data.{key}": value for key, value in data.items()}
+ update_result = await self._collection.find_one_and_update(
+ filter={"_id": document_id},
+ update={"$set": update_with},
+ upsert=True,
+ return_document=True,
+ projection={"_id": 0},
+ )
+ if not update_result:
+ await self._collection.delete_one({"_id": document_id})
+ return update_result.get("data", {})
diff --git a/myenv/Lib/site-packages/aiogram/fsm/storage/redis.py b/myenv/Lib/site-packages/aiogram/fsm/storage/redis.py
new file mode 100644
index 0000000..edcf9d6
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/storage/redis.py
@@ -0,0 +1,169 @@
+import json
+from contextlib import asynccontextmanager
+from typing import Any, AsyncGenerator, Callable, Dict, Optional, cast
+
+from redis.asyncio.client import Redis
+from redis.asyncio.connection import ConnectionPool
+from redis.asyncio.lock import Lock
+from redis.typing import ExpiryT
+
+from aiogram.fsm.state import State
+from aiogram.fsm.storage.base import (
+ BaseEventIsolation,
+ BaseStorage,
+ DefaultKeyBuilder,
+ KeyBuilder,
+ StateType,
+ StorageKey,
+)
+
+DEFAULT_REDIS_LOCK_KWARGS = {"timeout": 60}
+_JsonLoads = Callable[..., Any]
+_JsonDumps = Callable[..., str]
+
+
+class RedisStorage(BaseStorage):
+ """
+ Redis storage required :code:`redis` package installed (:code:`pip install redis`)
+ """
+
+ def __init__(
+ self,
+ redis: Redis,
+ key_builder: Optional[KeyBuilder] = None,
+ state_ttl: Optional[ExpiryT] = None,
+ data_ttl: Optional[ExpiryT] = None,
+ json_loads: _JsonLoads = json.loads,
+ json_dumps: _JsonDumps = json.dumps,
+ ) -> None:
+ """
+ :param redis: Instance of Redis connection
+ :param key_builder: builder that helps to convert contextual key to string
+ :param state_ttl: TTL for state records
+ :param data_ttl: TTL for data records
+ """
+ if key_builder is None:
+ key_builder = DefaultKeyBuilder()
+ self.redis = redis
+ self.key_builder = key_builder
+ self.state_ttl = state_ttl
+ self.data_ttl = data_ttl
+ self.json_loads = json_loads
+ self.json_dumps = json_dumps
+
+ @classmethod
+ def from_url(
+ cls, url: str, connection_kwargs: Optional[Dict[str, Any]] = None, **kwargs: Any
+ ) -> "RedisStorage":
+ """
+ Create an instance of :class:`RedisStorage` with specifying the connection string
+
+ :param url: for example :code:`redis://user:password@host:port/db`
+ :param connection_kwargs: see :code:`redis` docs
+ :param kwargs: arguments to be passed to :class:`RedisStorage`
+ :return: an instance of :class:`RedisStorage`
+ """
+ if connection_kwargs is None:
+ connection_kwargs = {}
+ pool = ConnectionPool.from_url(url, **connection_kwargs)
+ redis = Redis(connection_pool=pool)
+ return cls(redis=redis, **kwargs)
+
+ def create_isolation(self, **kwargs: Any) -> "RedisEventIsolation":
+ return RedisEventIsolation(redis=self.redis, key_builder=self.key_builder, **kwargs)
+
+ async def close(self) -> None:
+ await self.redis.aclose(close_connection_pool=True)
+
+ async def set_state(
+ self,
+ key: StorageKey,
+ state: StateType = None,
+ ) -> None:
+ redis_key = self.key_builder.build(key, "state")
+ if state is None:
+ await self.redis.delete(redis_key)
+ else:
+ await self.redis.set(
+ redis_key,
+ cast(str, state.state if isinstance(state, State) else state),
+ ex=self.state_ttl,
+ )
+
+ async def get_state(
+ self,
+ key: StorageKey,
+ ) -> Optional[str]:
+ redis_key = self.key_builder.build(key, "state")
+ value = await self.redis.get(redis_key)
+ if isinstance(value, bytes):
+ return value.decode("utf-8")
+ return cast(Optional[str], value)
+
+ async def set_data(
+ self,
+ key: StorageKey,
+ data: Dict[str, Any],
+ ) -> None:
+ redis_key = self.key_builder.build(key, "data")
+ if not data:
+ await self.redis.delete(redis_key)
+ return
+ await self.redis.set(
+ redis_key,
+ self.json_dumps(data),
+ ex=self.data_ttl,
+ )
+
+ async def get_data(
+ self,
+ key: StorageKey,
+ ) -> Dict[str, Any]:
+ redis_key = self.key_builder.build(key, "data")
+ value = await self.redis.get(redis_key)
+ if value is None:
+ return {}
+ if isinstance(value, bytes):
+ value = value.decode("utf-8")
+ return cast(Dict[str, Any], self.json_loads(value))
+
+
+class RedisEventIsolation(BaseEventIsolation):
+ def __init__(
+ self,
+ redis: Redis,
+ key_builder: Optional[KeyBuilder] = None,
+ lock_kwargs: Optional[Dict[str, Any]] = None,
+ ) -> None:
+ if key_builder is None:
+ key_builder = DefaultKeyBuilder()
+ if lock_kwargs is None:
+ lock_kwargs = DEFAULT_REDIS_LOCK_KWARGS
+ self.redis = redis
+ self.key_builder = key_builder
+ self.lock_kwargs = lock_kwargs
+
+ @classmethod
+ def from_url(
+ cls,
+ url: str,
+ connection_kwargs: Optional[Dict[str, Any]] = None,
+ **kwargs: Any,
+ ) -> "RedisEventIsolation":
+ if connection_kwargs is None:
+ connection_kwargs = {}
+ pool = ConnectionPool.from_url(url, **connection_kwargs)
+ redis = Redis(connection_pool=pool)
+ return cls(redis=redis, **kwargs)
+
+ @asynccontextmanager
+ async def lock(
+ self,
+ key: StorageKey,
+ ) -> AsyncGenerator[None, None]:
+ redis_key = self.key_builder.build(key, "lock")
+ async with self.redis.lock(name=redis_key, **self.lock_kwargs, lock_class=Lock):
+ yield None
+
+ async def close(self) -> None:
+ pass
diff --git a/myenv/Lib/site-packages/aiogram/fsm/strategy.py b/myenv/Lib/site-packages/aiogram/fsm/strategy.py
new file mode 100644
index 0000000..da2d94e
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/fsm/strategy.py
@@ -0,0 +1,37 @@
+from enum import Enum, auto
+from typing import Optional, Tuple
+
+
+class FSMStrategy(Enum):
+ """
+ FSM strategy for storage key generation.
+ """
+
+ USER_IN_CHAT = auto()
+ """State will be stored for each user in chat."""
+ CHAT = auto()
+ """State will be stored for each chat globally without separating by users."""
+ GLOBAL_USER = auto()
+ """State will be stored globally for each user globally."""
+ USER_IN_TOPIC = auto()
+ """State will be stored for each user in chat and topic."""
+ CHAT_TOPIC = auto()
+ """State will be stored for each chat and topic, but not separated by users."""
+
+
+def apply_strategy(
+ strategy: FSMStrategy,
+ chat_id: int,
+ user_id: int,
+ thread_id: Optional[int] = None,
+) -> Tuple[int, int, Optional[int]]:
+ if strategy == FSMStrategy.CHAT:
+ return chat_id, chat_id, None
+ if strategy == FSMStrategy.GLOBAL_USER:
+ return user_id, user_id, None
+ if strategy == FSMStrategy.USER_IN_TOPIC:
+ return chat_id, user_id, thread_id
+ if strategy == FSMStrategy.CHAT_TOPIC:
+ return chat_id, chat_id, thread_id
+
+ return chat_id, user_id, None
diff --git a/myenv/Lib/site-packages/aiogram/handlers/__init__.py b/myenv/Lib/site-packages/aiogram/handlers/__init__.py
new file mode 100644
index 0000000..5483788
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/__init__.py
@@ -0,0 +1,25 @@
+from .base import BaseHandler, BaseHandlerMixin
+from .callback_query import CallbackQueryHandler
+from .chat_member import ChatMemberHandler
+from .chosen_inline_result import ChosenInlineResultHandler
+from .error import ErrorHandler
+from .inline_query import InlineQueryHandler
+from .message import MessageHandler, MessageHandlerCommandMixin
+from .poll import PollHandler
+from .pre_checkout_query import PreCheckoutQueryHandler
+from .shipping_query import ShippingQueryHandler
+
+__all__ = (
+ "BaseHandler",
+ "BaseHandlerMixin",
+ "CallbackQueryHandler",
+ "ChatMemberHandler",
+ "ChosenInlineResultHandler",
+ "ErrorHandler",
+ "InlineQueryHandler",
+ "MessageHandler",
+ "MessageHandlerCommandMixin",
+ "PollHandler",
+ "PreCheckoutQueryHandler",
+ "ShippingQueryHandler",
+)
diff --git a/myenv/Lib/site-packages/aiogram/handlers/base.py b/myenv/Lib/site-packages/aiogram/handlers/base.py
new file mode 100644
index 0000000..0eb1b42
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/base.py
@@ -0,0 +1,46 @@
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Any, Dict, Generic, TypeVar, cast
+
+from aiogram.types import Update
+
+if TYPE_CHECKING:
+ from aiogram import Bot
+
+T = TypeVar("T")
+
+
+class BaseHandlerMixin(Generic[T]):
+ if TYPE_CHECKING:
+ event: T
+ data: Dict[str, Any]
+
+
+class BaseHandler(BaseHandlerMixin[T], ABC):
+ """
+ Base class for all class-based handlers
+ """
+
+ def __init__(self, event: T, **kwargs: Any) -> None:
+ self.event: T = event
+ self.data: Dict[str, Any] = kwargs
+
+ @property
+ def bot(self) -> Bot:
+ from aiogram import Bot
+
+ if "bot" in self.data:
+ return cast(Bot, self.data["bot"])
+ raise RuntimeError("Bot instance not found in the context")
+
+ @property
+ def update(self) -> Update:
+ return cast(Update, self.data.get("update", self.data.get("event_update")))
+
+ @abstractmethod
+ async def handle(self) -> Any: # pragma: no cover
+ pass
+
+ def __await__(self) -> Any:
+ return self.handle().__await__()
diff --git a/myenv/Lib/site-packages/aiogram/handlers/callback_query.py b/myenv/Lib/site-packages/aiogram/handlers/callback_query.py
new file mode 100644
index 0000000..e2a3a25
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/callback_query.py
@@ -0,0 +1,43 @@
+from abc import ABC
+from typing import Optional
+
+from aiogram.handlers import BaseHandler
+from aiogram.types import CallbackQuery, MaybeInaccessibleMessage, User
+
+
+class CallbackQueryHandler(BaseHandler[CallbackQuery], ABC):
+ """
+ There is base class for callback query handlers.
+
+ Example:
+ .. code-block:: python
+
+ from aiogram.handlers import CallbackQueryHandler
+
+ ...
+
+ @router.callback_query()
+ class MyHandler(CallbackQueryHandler):
+ async def handle(self) -> Any: ...
+ """
+
+ @property
+ def from_user(self) -> User:
+ """
+ Is alias for `event.from_user`
+ """
+ return self.event.from_user
+
+ @property
+ def message(self) -> Optional[MaybeInaccessibleMessage]:
+ """
+ Is alias for `event.message`
+ """
+ return self.event.message
+
+ @property
+ def callback_data(self) -> Optional[str]:
+ """
+ Is alias for `event.data`
+ """
+ return self.event.data
diff --git a/myenv/Lib/site-packages/aiogram/handlers/chat_member.py b/myenv/Lib/site-packages/aiogram/handlers/chat_member.py
new file mode 100644
index 0000000..bf668ac
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/chat_member.py
@@ -0,0 +1,14 @@
+from abc import ABC
+
+from aiogram.handlers import BaseHandler
+from aiogram.types import ChatMemberUpdated, User
+
+
+class ChatMemberHandler(BaseHandler[ChatMemberUpdated], ABC):
+ """
+ Base class for chat member updated events
+ """
+
+ @property
+ def from_user(self) -> User:
+ return self.event.from_user
diff --git a/myenv/Lib/site-packages/aiogram/handlers/chosen_inline_result.py b/myenv/Lib/site-packages/aiogram/handlers/chosen_inline_result.py
new file mode 100644
index 0000000..d6b66c5
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/chosen_inline_result.py
@@ -0,0 +1,18 @@
+from abc import ABC
+
+from aiogram.handlers import BaseHandler
+from aiogram.types import ChosenInlineResult, User
+
+
+class ChosenInlineResultHandler(BaseHandler[ChosenInlineResult], ABC):
+ """
+ Base class for chosen inline result handlers
+ """
+
+ @property
+ def from_user(self) -> User:
+ return self.event.from_user
+
+ @property
+ def query(self) -> str:
+ return self.event.query
diff --git a/myenv/Lib/site-packages/aiogram/handlers/error.py b/myenv/Lib/site-packages/aiogram/handlers/error.py
new file mode 100644
index 0000000..51ccf07
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/error.py
@@ -0,0 +1,17 @@
+from abc import ABC
+
+from aiogram.handlers.base import BaseHandler
+
+
+class ErrorHandler(BaseHandler[Exception], ABC):
+ """
+ Base class for errors handlers
+ """
+
+ @property
+ def exception_name(self) -> str:
+ return self.event.__class__.__name__
+
+ @property
+ def exception_message(self) -> str:
+ return str(self.event)
diff --git a/myenv/Lib/site-packages/aiogram/handlers/inline_query.py b/myenv/Lib/site-packages/aiogram/handlers/inline_query.py
new file mode 100644
index 0000000..022d8f2
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/inline_query.py
@@ -0,0 +1,18 @@
+from abc import ABC
+
+from aiogram.handlers import BaseHandler
+from aiogram.types import InlineQuery, User
+
+
+class InlineQueryHandler(BaseHandler[InlineQuery], ABC):
+ """
+ Base class for inline query handlers
+ """
+
+ @property
+ def from_user(self) -> User:
+ return self.event.from_user
+
+ @property
+ def query(self) -> str:
+ return self.event.query
diff --git a/myenv/Lib/site-packages/aiogram/handlers/message.py b/myenv/Lib/site-packages/aiogram/handlers/message.py
new file mode 100644
index 0000000..4fbecec
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/message.py
@@ -0,0 +1,28 @@
+from abc import ABC
+from typing import Optional, cast
+
+from aiogram.filters import CommandObject
+from aiogram.handlers.base import BaseHandler, BaseHandlerMixin
+from aiogram.types import Chat, Message, User
+
+
+class MessageHandler(BaseHandler[Message], ABC):
+ """
+ Base class for message handlers
+ """
+
+ @property
+ def from_user(self) -> Optional[User]:
+ return self.event.from_user
+
+ @property
+ def chat(self) -> Chat:
+ return self.event.chat
+
+
+class MessageHandlerCommandMixin(BaseHandlerMixin[Message]):
+ @property
+ def command(self) -> Optional[CommandObject]:
+ if "command" in self.data:
+ return cast(CommandObject, self.data["command"])
+ return None
diff --git a/myenv/Lib/site-packages/aiogram/handlers/poll.py b/myenv/Lib/site-packages/aiogram/handlers/poll.py
new file mode 100644
index 0000000..2183d84
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/poll.py
@@ -0,0 +1,19 @@
+from abc import ABC
+from typing import List
+
+from aiogram.handlers import BaseHandler
+from aiogram.types import Poll, PollOption
+
+
+class PollHandler(BaseHandler[Poll], ABC):
+ """
+ Base class for poll handlers
+ """
+
+ @property
+ def question(self) -> str:
+ return self.event.question
+
+ @property
+ def options(self) -> List[PollOption]:
+ return self.event.options
diff --git a/myenv/Lib/site-packages/aiogram/handlers/pre_checkout_query.py b/myenv/Lib/site-packages/aiogram/handlers/pre_checkout_query.py
new file mode 100644
index 0000000..34290f2
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/pre_checkout_query.py
@@ -0,0 +1,14 @@
+from abc import ABC
+
+from aiogram.handlers import BaseHandler
+from aiogram.types import PreCheckoutQuery, User
+
+
+class PreCheckoutQueryHandler(BaseHandler[PreCheckoutQuery], ABC):
+ """
+ Base class for pre-checkout handlers
+ """
+
+ @property
+ def from_user(self) -> User:
+ return self.event.from_user
diff --git a/myenv/Lib/site-packages/aiogram/handlers/shipping_query.py b/myenv/Lib/site-packages/aiogram/handlers/shipping_query.py
new file mode 100644
index 0000000..64a5645
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/handlers/shipping_query.py
@@ -0,0 +1,14 @@
+from abc import ABC
+
+from aiogram.handlers import BaseHandler
+from aiogram.types import ShippingQuery, User
+
+
+class ShippingQueryHandler(BaseHandler[ShippingQuery], ABC):
+ """
+ Base class for shipping query handlers
+ """
+
+ @property
+ def from_user(self) -> User:
+ return self.event.from_user
diff --git a/myenv/Lib/site-packages/aiogram/loggers.py b/myenv/Lib/site-packages/aiogram/loggers.py
new file mode 100644
index 0000000..942c124
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/loggers.py
@@ -0,0 +1,7 @@
+import logging
+
+dispatcher = logging.getLogger("aiogram.dispatcher")
+event = logging.getLogger("aiogram.event")
+middlewares = logging.getLogger("aiogram.middlewares")
+webhook = logging.getLogger("aiogram.webhook")
+scene = logging.getLogger("aiogram.scene")
diff --git a/myenv/Lib/site-packages/aiogram/methods/__init__.py b/myenv/Lib/site-packages/aiogram/methods/__init__.py
new file mode 100644
index 0000000..a7d6283
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/__init__.py
@@ -0,0 +1,313 @@
+from .add_sticker_to_set import AddStickerToSet
+from .answer_callback_query import AnswerCallbackQuery
+from .answer_inline_query import AnswerInlineQuery
+from .answer_pre_checkout_query import AnswerPreCheckoutQuery
+from .answer_shipping_query import AnswerShippingQuery
+from .answer_web_app_query import AnswerWebAppQuery
+from .approve_chat_join_request import ApproveChatJoinRequest
+from .ban_chat_member import BanChatMember
+from .ban_chat_sender_chat import BanChatSenderChat
+from .base import Request, Response, TelegramMethod
+from .close import Close
+from .close_forum_topic import CloseForumTopic
+from .close_general_forum_topic import CloseGeneralForumTopic
+from .convert_gift_to_stars import ConvertGiftToStars
+from .copy_message import CopyMessage
+from .copy_messages import CopyMessages
+from .create_chat_invite_link import CreateChatInviteLink
+from .create_chat_subscription_invite_link import CreateChatSubscriptionInviteLink
+from .create_forum_topic import CreateForumTopic
+from .create_invoice_link import CreateInvoiceLink
+from .create_new_sticker_set import CreateNewStickerSet
+from .decline_chat_join_request import DeclineChatJoinRequest
+from .delete_business_messages import DeleteBusinessMessages
+from .delete_chat_photo import DeleteChatPhoto
+from .delete_chat_sticker_set import DeleteChatStickerSet
+from .delete_forum_topic import DeleteForumTopic
+from .delete_message import DeleteMessage
+from .delete_messages import DeleteMessages
+from .delete_my_commands import DeleteMyCommands
+from .delete_sticker_from_set import DeleteStickerFromSet
+from .delete_sticker_set import DeleteStickerSet
+from .delete_story import DeleteStory
+from .delete_webhook import DeleteWebhook
+from .edit_chat_invite_link import EditChatInviteLink
+from .edit_chat_subscription_invite_link import EditChatSubscriptionInviteLink
+from .edit_forum_topic import EditForumTopic
+from .edit_general_forum_topic import EditGeneralForumTopic
+from .edit_message_caption import EditMessageCaption
+from .edit_message_live_location import EditMessageLiveLocation
+from .edit_message_media import EditMessageMedia
+from .edit_message_reply_markup import EditMessageReplyMarkup
+from .edit_message_text import EditMessageText
+from .edit_story import EditStory
+from .edit_user_star_subscription import EditUserStarSubscription
+from .export_chat_invite_link import ExportChatInviteLink
+from .forward_message import ForwardMessage
+from .forward_messages import ForwardMessages
+from .get_available_gifts import GetAvailableGifts
+from .get_business_account_gifts import GetBusinessAccountGifts
+from .get_business_account_star_balance import GetBusinessAccountStarBalance
+from .get_business_connection import GetBusinessConnection
+from .get_chat import GetChat
+from .get_chat_administrators import GetChatAdministrators
+from .get_chat_member import GetChatMember
+from .get_chat_member_count import GetChatMemberCount
+from .get_chat_menu_button import GetChatMenuButton
+from .get_custom_emoji_stickers import GetCustomEmojiStickers
+from .get_file import GetFile
+from .get_forum_topic_icon_stickers import GetForumTopicIconStickers
+from .get_game_high_scores import GetGameHighScores
+from .get_me import GetMe
+from .get_my_commands import GetMyCommands
+from .get_my_default_administrator_rights import GetMyDefaultAdministratorRights
+from .get_my_description import GetMyDescription
+from .get_my_name import GetMyName
+from .get_my_short_description import GetMyShortDescription
+from .get_star_transactions import GetStarTransactions
+from .get_sticker_set import GetStickerSet
+from .get_updates import GetUpdates
+from .get_user_chat_boosts import GetUserChatBoosts
+from .get_user_profile_photos import GetUserProfilePhotos
+from .get_webhook_info import GetWebhookInfo
+from .gift_premium_subscription import GiftPremiumSubscription
+from .hide_general_forum_topic import HideGeneralForumTopic
+from .leave_chat import LeaveChat
+from .log_out import LogOut
+from .pin_chat_message import PinChatMessage
+from .post_story import PostStory
+from .promote_chat_member import PromoteChatMember
+from .read_business_message import ReadBusinessMessage
+from .refund_star_payment import RefundStarPayment
+from .remove_business_account_profile_photo import RemoveBusinessAccountProfilePhoto
+from .remove_chat_verification import RemoveChatVerification
+from .remove_user_verification import RemoveUserVerification
+from .reopen_forum_topic import ReopenForumTopic
+from .reopen_general_forum_topic import ReopenGeneralForumTopic
+from .replace_sticker_in_set import ReplaceStickerInSet
+from .restrict_chat_member import RestrictChatMember
+from .revoke_chat_invite_link import RevokeChatInviteLink
+from .save_prepared_inline_message import SavePreparedInlineMessage
+from .send_animation import SendAnimation
+from .send_audio import SendAudio
+from .send_chat_action import SendChatAction
+from .send_contact import SendContact
+from .send_dice import SendDice
+from .send_document import SendDocument
+from .send_game import SendGame
+from .send_gift import SendGift
+from .send_invoice import SendInvoice
+from .send_location import SendLocation
+from .send_media_group import SendMediaGroup
+from .send_message import SendMessage
+from .send_paid_media import SendPaidMedia
+from .send_photo import SendPhoto
+from .send_poll import SendPoll
+from .send_sticker import SendSticker
+from .send_venue import SendVenue
+from .send_video import SendVideo
+from .send_video_note import SendVideoNote
+from .send_voice import SendVoice
+from .set_business_account_bio import SetBusinessAccountBio
+from .set_business_account_gift_settings import SetBusinessAccountGiftSettings
+from .set_business_account_name import SetBusinessAccountName
+from .set_business_account_profile_photo import SetBusinessAccountProfilePhoto
+from .set_business_account_username import SetBusinessAccountUsername
+from .set_chat_administrator_custom_title import SetChatAdministratorCustomTitle
+from .set_chat_description import SetChatDescription
+from .set_chat_menu_button import SetChatMenuButton
+from .set_chat_permissions import SetChatPermissions
+from .set_chat_photo import SetChatPhoto
+from .set_chat_sticker_set import SetChatStickerSet
+from .set_chat_title import SetChatTitle
+from .set_custom_emoji_sticker_set_thumbnail import SetCustomEmojiStickerSetThumbnail
+from .set_game_score import SetGameScore
+from .set_message_reaction import SetMessageReaction
+from .set_my_commands import SetMyCommands
+from .set_my_default_administrator_rights import SetMyDefaultAdministratorRights
+from .set_my_description import SetMyDescription
+from .set_my_name import SetMyName
+from .set_my_short_description import SetMyShortDescription
+from .set_passport_data_errors import SetPassportDataErrors
+from .set_sticker_emoji_list import SetStickerEmojiList
+from .set_sticker_keywords import SetStickerKeywords
+from .set_sticker_mask_position import SetStickerMaskPosition
+from .set_sticker_position_in_set import SetStickerPositionInSet
+from .set_sticker_set_thumbnail import SetStickerSetThumbnail
+from .set_sticker_set_title import SetStickerSetTitle
+from .set_user_emoji_status import SetUserEmojiStatus
+from .set_webhook import SetWebhook
+from .stop_message_live_location import StopMessageLiveLocation
+from .stop_poll import StopPoll
+from .transfer_business_account_stars import TransferBusinessAccountStars
+from .transfer_gift import TransferGift
+from .unban_chat_member import UnbanChatMember
+from .unban_chat_sender_chat import UnbanChatSenderChat
+from .unhide_general_forum_topic import UnhideGeneralForumTopic
+from .unpin_all_chat_messages import UnpinAllChatMessages
+from .unpin_all_forum_topic_messages import UnpinAllForumTopicMessages
+from .unpin_all_general_forum_topic_messages import UnpinAllGeneralForumTopicMessages
+from .unpin_chat_message import UnpinChatMessage
+from .upgrade_gift import UpgradeGift
+from .upload_sticker_file import UploadStickerFile
+from .verify_chat import VerifyChat
+from .verify_user import VerifyUser
+
+__all__ = (
+ "AddStickerToSet",
+ "AnswerCallbackQuery",
+ "AnswerInlineQuery",
+ "AnswerPreCheckoutQuery",
+ "AnswerShippingQuery",
+ "AnswerWebAppQuery",
+ "ApproveChatJoinRequest",
+ "BanChatMember",
+ "BanChatSenderChat",
+ "Close",
+ "CloseForumTopic",
+ "CloseGeneralForumTopic",
+ "ConvertGiftToStars",
+ "CopyMessage",
+ "CopyMessages",
+ "CreateChatInviteLink",
+ "CreateChatSubscriptionInviteLink",
+ "CreateForumTopic",
+ "CreateInvoiceLink",
+ "CreateNewStickerSet",
+ "DeclineChatJoinRequest",
+ "DeleteBusinessMessages",
+ "DeleteChatPhoto",
+ "DeleteChatStickerSet",
+ "DeleteForumTopic",
+ "DeleteMessage",
+ "DeleteMessages",
+ "DeleteMyCommands",
+ "DeleteStickerFromSet",
+ "DeleteStickerSet",
+ "DeleteStory",
+ "DeleteWebhook",
+ "EditChatInviteLink",
+ "EditChatSubscriptionInviteLink",
+ "EditForumTopic",
+ "EditGeneralForumTopic",
+ "EditMessageCaption",
+ "EditMessageLiveLocation",
+ "EditMessageMedia",
+ "EditMessageReplyMarkup",
+ "EditMessageText",
+ "EditStory",
+ "EditUserStarSubscription",
+ "ExportChatInviteLink",
+ "ForwardMessage",
+ "ForwardMessages",
+ "GetAvailableGifts",
+ "GetBusinessAccountGifts",
+ "GetBusinessAccountStarBalance",
+ "GetBusinessConnection",
+ "GetChat",
+ "GetChatAdministrators",
+ "GetChatMember",
+ "GetChatMemberCount",
+ "GetChatMenuButton",
+ "GetCustomEmojiStickers",
+ "GetFile",
+ "GetForumTopicIconStickers",
+ "GetGameHighScores",
+ "GetMe",
+ "GetMyCommands",
+ "GetMyDefaultAdministratorRights",
+ "GetMyDescription",
+ "GetMyName",
+ "GetMyShortDescription",
+ "GetStarTransactions",
+ "GetStickerSet",
+ "GetUpdates",
+ "GetUserChatBoosts",
+ "GetUserProfilePhotos",
+ "GetWebhookInfo",
+ "GiftPremiumSubscription",
+ "HideGeneralForumTopic",
+ "LeaveChat",
+ "LogOut",
+ "PinChatMessage",
+ "PostStory",
+ "PromoteChatMember",
+ "ReadBusinessMessage",
+ "RefundStarPayment",
+ "RemoveBusinessAccountProfilePhoto",
+ "RemoveChatVerification",
+ "RemoveUserVerification",
+ "ReopenForumTopic",
+ "ReopenGeneralForumTopic",
+ "ReplaceStickerInSet",
+ "Request",
+ "Response",
+ "RestrictChatMember",
+ "RevokeChatInviteLink",
+ "SavePreparedInlineMessage",
+ "SendAnimation",
+ "SendAudio",
+ "SendChatAction",
+ "SendContact",
+ "SendDice",
+ "SendDocument",
+ "SendGame",
+ "SendGift",
+ "SendInvoice",
+ "SendLocation",
+ "SendMediaGroup",
+ "SendMessage",
+ "SendPaidMedia",
+ "SendPhoto",
+ "SendPoll",
+ "SendSticker",
+ "SendVenue",
+ "SendVideo",
+ "SendVideoNote",
+ "SendVoice",
+ "SetBusinessAccountBio",
+ "SetBusinessAccountGiftSettings",
+ "SetBusinessAccountName",
+ "SetBusinessAccountProfilePhoto",
+ "SetBusinessAccountUsername",
+ "SetChatAdministratorCustomTitle",
+ "SetChatDescription",
+ "SetChatMenuButton",
+ "SetChatPermissions",
+ "SetChatPhoto",
+ "SetChatStickerSet",
+ "SetChatTitle",
+ "SetCustomEmojiStickerSetThumbnail",
+ "SetGameScore",
+ "SetMessageReaction",
+ "SetMyCommands",
+ "SetMyDefaultAdministratorRights",
+ "SetMyDescription",
+ "SetMyName",
+ "SetMyShortDescription",
+ "SetPassportDataErrors",
+ "SetStickerEmojiList",
+ "SetStickerKeywords",
+ "SetStickerMaskPosition",
+ "SetStickerPositionInSet",
+ "SetStickerSetThumbnail",
+ "SetStickerSetTitle",
+ "SetUserEmojiStatus",
+ "SetWebhook",
+ "StopMessageLiveLocation",
+ "StopPoll",
+ "TelegramMethod",
+ "TransferBusinessAccountStars",
+ "TransferGift",
+ "UnbanChatMember",
+ "UnbanChatSenderChat",
+ "UnhideGeneralForumTopic",
+ "UnpinAllChatMessages",
+ "UnpinAllForumTopicMessages",
+ "UnpinAllGeneralForumTopicMessages",
+ "UnpinChatMessage",
+ "UpgradeGift",
+ "UploadStickerFile",
+ "VerifyChat",
+ "VerifyUser",
+)
diff --git a/myenv/Lib/site-packages/aiogram/methods/add_sticker_to_set.py b/myenv/Lib/site-packages/aiogram/methods/add_sticker_to_set.py
new file mode 100644
index 0000000..cc2e31d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/add_sticker_to_set.py
@@ -0,0 +1,42 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from ..types import InputSticker
+from .base import TelegramMethod
+
+
+class AddStickerToSet(TelegramMethod[bool]):
+ """
+ Use this method to add a new sticker to a set created by the bot. Emoji sticker sets can have up to 200 stickers. Other sticker sets can have up to 120 stickers. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#addstickertoset
+ """
+
+ __returning__ = bool
+ __api_method__ = "addStickerToSet"
+
+ user_id: int
+ """User identifier of sticker set owner"""
+ name: str
+ """Sticker set name"""
+ sticker: InputSticker
+ """A JSON-serialized object with information about the added sticker. If exactly the same sticker had already been added to the set, then the set isn't changed."""
+
+ if TYPE_CHECKING:
+ # DO NOT EDIT MANUALLY!!!
+ # This section was auto-generated via `butcher`
+
+ def __init__(
+ __pydantic__self__,
+ *,
+ user_id: int,
+ name: str,
+ sticker: InputSticker,
+ **__pydantic_kwargs: Any,
+ ) -> None:
+ # DO NOT EDIT MANUALLY!!!
+ # This method was auto-generated via `butcher`
+ # Is needed only for type checking and IDE support without any additional plugins
+
+ super().__init__(user_id=user_id, name=name, sticker=sticker, **__pydantic_kwargs)
diff --git a/myenv/Lib/site-packages/aiogram/methods/answer_callback_query.py b/myenv/Lib/site-packages/aiogram/methods/answer_callback_query.py
new file mode 100644
index 0000000..15ed1bf
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/answer_callback_query.py
@@ -0,0 +1,56 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Optional
+
+from .base import TelegramMethod
+
+
+class AnswerCallbackQuery(TelegramMethod[bool]):
+ """
+ Use this method to send answers to callback queries sent from `inline keyboards `_. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, :code:`True` is returned.
+
+ Alternatively, the user can be redirected to the specified Game URL. For this option to work, you must first create a game for your bot via `@BotFather `_ and accept the terms. Otherwise, you may use links like :code:`t.me/your_bot?start=XXXX` that open your bot with a parameter.
+
+ Source: https://core.telegram.org/bots/api#answercallbackquery
+ """
+
+ __returning__ = bool
+ __api_method__ = "answerCallbackQuery"
+
+ callback_query_id: str
+ """Unique identifier for the query to be answered"""
+ text: Optional[str] = None
+ """Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters"""
+ show_alert: Optional[bool] = None
+ """If :code:`True`, an alert will be shown by the client instead of a notification at the top of the chat screen. Defaults to *false*."""
+ url: Optional[str] = None
+ """URL that will be opened by the user's client. If you have created a :class:`aiogram.types.game.Game` and accepted the conditions via `@BotFather `_, specify the URL that opens your game - note that this will only work if the query comes from a `https://core.telegram.org/bots/api#inlinekeyboardbutton `_ *callback_game* button."""
+ cache_time: Optional[int] = None
+ """The maximum amount of time in seconds that the result of the callback query may be cached client-side. Telegram apps will support caching starting in version 3.14. Defaults to 0."""
+
+ if TYPE_CHECKING:
+ # DO NOT EDIT MANUALLY!!!
+ # This section was auto-generated via `butcher`
+
+ def __init__(
+ __pydantic__self__,
+ *,
+ callback_query_id: str,
+ text: Optional[str] = None,
+ show_alert: Optional[bool] = None,
+ url: Optional[str] = None,
+ cache_time: Optional[int] = None,
+ **__pydantic_kwargs: Any,
+ ) -> None:
+ # DO NOT EDIT MANUALLY!!!
+ # This method was auto-generated via `butcher`
+ # Is needed only for type checking and IDE support without any additional plugins
+
+ super().__init__(
+ callback_query_id=callback_query_id,
+ text=text,
+ show_alert=show_alert,
+ url=url,
+ cache_time=cache_time,
+ **__pydantic_kwargs,
+ )
diff --git a/myenv/Lib/site-packages/aiogram/methods/answer_inline_query.py b/myenv/Lib/site-packages/aiogram/methods/answer_inline_query.py
new file mode 100644
index 0000000..2884867
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/answer_inline_query.py
@@ -0,0 +1,77 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Optional
+
+from pydantic import Field
+
+from ..types import InlineQueryResultsButton, InlineQueryResultUnion
+from .base import TelegramMethod
+
+
+class AnswerInlineQuery(TelegramMethod[bool]):
+ """
+ Use this method to send answers to an inline query. On success, :code:`True` is returned.
+
+ No more than **50** results per query are allowed.
+
+ Source: https://core.telegram.org/bots/api#answerinlinequery
+ """
+
+ __returning__ = bool
+ __api_method__ = "answerInlineQuery"
+
+ inline_query_id: str
+ """Unique identifier for the answered query"""
+ results: list[InlineQueryResultUnion]
+ """A JSON-serialized array of results for the inline query"""
+ cache_time: Optional[int] = None
+ """The maximum amount of time in seconds that the result of the inline query may be cached on the server. Defaults to 300."""
+ is_personal: Optional[bool] = None
+ """Pass :code:`True` if results may be cached on the server side only for the user that sent the query. By default, results may be returned to any user who sends the same query."""
+ next_offset: Optional[str] = None
+ """Pass the offset that a client should send in the next query with the same text to receive more results. Pass an empty string if there are no more results or if you don't support pagination. Offset length can't exceed 64 bytes."""
+ button: Optional[InlineQueryResultsButton] = None
+ """A JSON-serialized object describing a button to be shown above inline query results"""
+ switch_pm_parameter: Optional[str] = Field(None, json_schema_extra={"deprecated": True})
+ """`Deep-linking `_ parameter for the /start message sent to the bot when user presses the switch button. 1-64 characters, only :code:`A-Z`, :code:`a-z`, :code:`0-9`, :code:`_` and :code:`-` are allowed.
+
+.. deprecated:: API:6.7
+ https://core.telegram.org/bots/api-changelog#april-21-2023"""
+ switch_pm_text: Optional[str] = Field(None, json_schema_extra={"deprecated": True})
+ """If passed, clients will display a button with specified text that switches the user to a private chat with the bot and sends the bot a start message with the parameter *switch_pm_parameter*
+
+.. deprecated:: API:6.7
+ https://core.telegram.org/bots/api-changelog#april-21-2023"""
+
+ if TYPE_CHECKING:
+ # DO NOT EDIT MANUALLY!!!
+ # This section was auto-generated via `butcher`
+
+ def __init__(
+ __pydantic__self__,
+ *,
+ inline_query_id: str,
+ results: list[InlineQueryResultUnion],
+ cache_time: Optional[int] = None,
+ is_personal: Optional[bool] = None,
+ next_offset: Optional[str] = None,
+ button: Optional[InlineQueryResultsButton] = None,
+ switch_pm_parameter: Optional[str] = None,
+ switch_pm_text: Optional[str] = None,
+ **__pydantic_kwargs: Any,
+ ) -> None:
+ # DO NOT EDIT MANUALLY!!!
+ # This method was auto-generated via `butcher`
+ # Is needed only for type checking and IDE support without any additional plugins
+
+ super().__init__(
+ inline_query_id=inline_query_id,
+ results=results,
+ cache_time=cache_time,
+ is_personal=is_personal,
+ next_offset=next_offset,
+ button=button,
+ switch_pm_parameter=switch_pm_parameter,
+ switch_pm_text=switch_pm_text,
+ **__pydantic_kwargs,
+ )
diff --git a/myenv/Lib/site-packages/aiogram/methods/answer_pre_checkout_query.py b/myenv/Lib/site-packages/aiogram/methods/answer_pre_checkout_query.py
new file mode 100644
index 0000000..479d76c
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/answer_pre_checkout_query.py
@@ -0,0 +1,46 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Optional
+
+from .base import TelegramMethod
+
+
+class AnswerPreCheckoutQuery(TelegramMethod[bool]):
+ """
+ Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of an :class:`aiogram.types.update.Update` with the field *pre_checkout_query*. Use this method to respond to such pre-checkout queries. On success, :code:`True` is returned. **Note:** The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
+
+ Source: https://core.telegram.org/bots/api#answerprecheckoutquery
+ """
+
+ __returning__ = bool
+ __api_method__ = "answerPreCheckoutQuery"
+
+ pre_checkout_query_id: str
+ """Unique identifier for the query to be answered"""
+ ok: bool
+ """Specify :code:`True` if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use :code:`False` if there are any problems."""
+ error_message: Optional[str] = None
+ """Required if *ok* is :code:`False`. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user."""
+
+ if TYPE_CHECKING:
+ # DO NOT EDIT MANUALLY!!!
+ # This section was auto-generated via `butcher`
+
+ def __init__(
+ __pydantic__self__,
+ *,
+ pre_checkout_query_id: str,
+ ok: bool,
+ error_message: Optional[str] = None,
+ **__pydantic_kwargs: Any,
+ ) -> None:
+ # DO NOT EDIT MANUALLY!!!
+ # This method was auto-generated via `butcher`
+ # Is needed only for type checking and IDE support without any additional plugins
+
+ super().__init__(
+ pre_checkout_query_id=pre_checkout_query_id,
+ ok=ok,
+ error_message=error_message,
+ **__pydantic_kwargs,
+ )
diff --git a/myenv/Lib/site-packages/aiogram/methods/answer_shipping_query.py b/myenv/Lib/site-packages/aiogram/methods/answer_shipping_query.py
new file mode 100644
index 0000000..eec5986
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/answer_shipping_query.py
@@ -0,0 +1,51 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Optional
+
+from ..types import ShippingOption
+from .base import TelegramMethod
+
+
+class AnswerShippingQuery(TelegramMethod[bool]):
+ """
+ If you sent an invoice requesting a shipping address and the parameter *is_flexible* was specified, the Bot API will send an :class:`aiogram.types.update.Update` with a *shipping_query* field to the bot. Use this method to reply to shipping queries. On success, :code:`True` is returned.
+
+ Source: https://core.telegram.org/bots/api#answershippingquery
+ """
+
+ __returning__ = bool
+ __api_method__ = "answerShippingQuery"
+
+ shipping_query_id: str
+ """Unique identifier for the query to be answered"""
+ ok: bool
+ """Pass :code:`True` if delivery to the specified address is possible and :code:`False` if there are any problems (for example, if delivery to the specified address is not possible)"""
+ shipping_options: Optional[list[ShippingOption]] = None
+ """Required if *ok* is :code:`True`. A JSON-serialized array of available shipping options."""
+ error_message: Optional[str] = None
+ """Required if *ok* is :code:`False`. Error message in human readable form that explains why it is impossible to complete the order (e.g. 'Sorry, delivery to your desired address is unavailable'). Telegram will display this message to the user."""
+
+ if TYPE_CHECKING:
+ # DO NOT EDIT MANUALLY!!!
+ # This section was auto-generated via `butcher`
+
+ def __init__(
+ __pydantic__self__,
+ *,
+ shipping_query_id: str,
+ ok: bool,
+ shipping_options: Optional[list[ShippingOption]] = None,
+ error_message: Optional[str] = None,
+ **__pydantic_kwargs: Any,
+ ) -> None:
+ # DO NOT EDIT MANUALLY!!!
+ # This method was auto-generated via `butcher`
+ # Is needed only for type checking and IDE support without any additional plugins
+
+ super().__init__(
+ shipping_query_id=shipping_query_id,
+ ok=ok,
+ shipping_options=shipping_options,
+ error_message=error_message,
+ **__pydantic_kwargs,
+ )
diff --git a/myenv/Lib/site-packages/aiogram/methods/answer_web_app_query.py b/myenv/Lib/site-packages/aiogram/methods/answer_web_app_query.py
new file mode 100644
index 0000000..edcbf7d
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/answer_web_app_query.py
@@ -0,0 +1,39 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from ..types import InlineQueryResultUnion, SentWebAppMessage
+from .base import TelegramMethod
+
+
+class AnswerWebAppQuery(TelegramMethod[SentWebAppMessage]):
+ """
+ Use this method to set the result of an interaction with a `Web App `_ and send a corresponding message on behalf of the user to the chat from which the query originated. On success, a :class:`aiogram.types.sent_web_app_message.SentWebAppMessage` object is returned.
+
+ Source: https://core.telegram.org/bots/api#answerwebappquery
+ """
+
+ __returning__ = SentWebAppMessage
+ __api_method__ = "answerWebAppQuery"
+
+ web_app_query_id: str
+ """Unique identifier for the query to be answered"""
+ result: InlineQueryResultUnion
+ """A JSON-serialized object describing the message to be sent"""
+
+ if TYPE_CHECKING:
+ # DO NOT EDIT MANUALLY!!!
+ # This section was auto-generated via `butcher`
+
+ def __init__(
+ __pydantic__self__,
+ *,
+ web_app_query_id: str,
+ result: InlineQueryResultUnion,
+ **__pydantic_kwargs: Any,
+ ) -> None:
+ # DO NOT EDIT MANUALLY!!!
+ # This method was auto-generated via `butcher`
+ # Is needed only for type checking and IDE support without any additional plugins
+
+ super().__init__(web_app_query_id=web_app_query_id, result=result, **__pydantic_kwargs)
diff --git a/myenv/Lib/site-packages/aiogram/methods/approve_chat_join_request.py b/myenv/Lib/site-packages/aiogram/methods/approve_chat_join_request.py
new file mode 100644
index 0000000..1142cd8
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/approve_chat_join_request.py
@@ -0,0 +1,35 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from ..types import ChatIdUnion
+from .base import TelegramMethod
+
+
+class ApproveChatJoinRequest(TelegramMethod[bool]):
+ """
+ Use this method to approve a chat join request. The bot must be an administrator in the chat for this to work and must have the *can_invite_users* administrator right. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#approvechatjoinrequest
+ """
+
+ __returning__ = bool
+ __api_method__ = "approveChatJoinRequest"
+
+ chat_id: ChatIdUnion
+ """Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)"""
+ user_id: int
+ """Unique identifier of the target user"""
+
+ if TYPE_CHECKING:
+ # DO NOT EDIT MANUALLY!!!
+ # This section was auto-generated via `butcher`
+
+ def __init__(
+ __pydantic__self__, *, chat_id: ChatIdUnion, user_id: int, **__pydantic_kwargs: Any
+ ) -> None:
+ # DO NOT EDIT MANUALLY!!!
+ # This method was auto-generated via `butcher`
+ # Is needed only for type checking and IDE support without any additional plugins
+
+ super().__init__(chat_id=chat_id, user_id=user_id, **__pydantic_kwargs)
diff --git a/myenv/Lib/site-packages/aiogram/methods/ban_chat_member.py b/myenv/Lib/site-packages/aiogram/methods/ban_chat_member.py
new file mode 100644
index 0000000..57e2f53
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/ban_chat_member.py
@@ -0,0 +1,51 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Optional
+
+from ..types import ChatIdUnion, DateTimeUnion
+from .base import TelegramMethod
+
+
+class BanChatMember(TelegramMethod[bool]):
+ """
+ Use this method to ban a user in a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the chat on their own using invite links, etc., unless `unbanned `_ first. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
+
+ Source: https://core.telegram.org/bots/api#banchatmember
+ """
+
+ __returning__ = bool
+ __api_method__ = "banChatMember"
+
+ chat_id: ChatIdUnion
+ """Unique identifier for the target group or username of the target supergroup or channel (in the format :code:`@channelusername`)"""
+ user_id: int
+ """Unique identifier of the target user"""
+ until_date: Optional[DateTimeUnion] = None
+ """Date when the user will be unbanned; Unix time. If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever. Applied for supergroups and channels only."""
+ revoke_messages: Optional[bool] = None
+ """Pass :code:`True` to delete all messages from the chat for the user that is being removed. If :code:`False`, the user will be able to see messages in the group that were sent before the user was removed. Always :code:`True` for supergroups and channels."""
+
+ if TYPE_CHECKING:
+ # DO NOT EDIT MANUALLY!!!
+ # This section was auto-generated via `butcher`
+
+ def __init__(
+ __pydantic__self__,
+ *,
+ chat_id: ChatIdUnion,
+ user_id: int,
+ until_date: Optional[DateTimeUnion] = None,
+ revoke_messages: Optional[bool] = None,
+ **__pydantic_kwargs: Any,
+ ) -> None:
+ # DO NOT EDIT MANUALLY!!!
+ # This method was auto-generated via `butcher`
+ # Is needed only for type checking and IDE support without any additional plugins
+
+ super().__init__(
+ chat_id=chat_id,
+ user_id=user_id,
+ until_date=until_date,
+ revoke_messages=revoke_messages,
+ **__pydantic_kwargs,
+ )
diff --git a/myenv/Lib/site-packages/aiogram/methods/ban_chat_sender_chat.py b/myenv/Lib/site-packages/aiogram/methods/ban_chat_sender_chat.py
new file mode 100644
index 0000000..72173cc
--- /dev/null
+++ b/myenv/Lib/site-packages/aiogram/methods/ban_chat_sender_chat.py
@@ -0,0 +1,39 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from ..types import ChatIdUnion
+from .base import TelegramMethod
+
+
+class BanChatSenderChat(TelegramMethod[bool]):
+ """
+ Use this method to ban a channel chat in a supergroup or a channel. Until the chat is `unbanned