python-telegram-bot

raw JSON →
22.7 verified Tue May 12 auth: no python install: verified

This library provides a pure Python, asynchronous interface for the Telegram Bot API. It's compatible with Python versions 3.10+. It features convenience methods, shortcuts, and high-level classes within the `telegram.ext` submodule to simplify bot development. It supports all types and methods of the Telegram Bot API 9.5 and receives frequent updates, with new releases typically coming out every few weeks/months.

pip install python-telegram-bot
error ImportError: cannot import name 'Updater' from 'telegram.ext'
cause The `Updater` class was removed in `python-telegram-bot` version 20.0 and later, replaced by the `Application` class for managing the bot's lifecycle.
fix
Update your code to use Application.builder().token('YOUR_TOKEN').build() and application.run_polling() or application.run_webhook() instead of Updater.
error AttributeError: 'CallbackContext' object has no attribute 'dispatcher'
cause In `python-telegram-bot` version 20.0 and later, the `Dispatcher` object was removed, and the `bot` instance is now directly accessible via `context.bot` within handlers.
fix
Access the bot instance directly using context.bot (e.g., await context.bot.send_message(...)) instead of context.dispatcher.bot or update.dispatcher.bot.
error NameError: name 'MessageFilter' is not defined
cause The `MessageFilter` class was replaced by the `filters` module in `python-telegram-bot` version 20.0 and later, offering a more granular way to filter updates.
fix
Import filters from telegram.ext and use its attributes (e.g., filters.TEXT, filters.COMMAND) directly within MessageHandler or other handlers. For example, MessageHandler(filters.TEXT & ~filters.COMMAND, my_handler).
error TypeError: object NoneType can't be used in 'await' expression
cause This error typically indicates that an `await` keyword was used on a function call that either returned `None` or did not return a valid awaitable (coroutine) object, often because the function itself was not defined as `async` or was called incorrectly.
fix
Ensure that any function called with await is an async def function and that it actually returns an awaitable object. Check for typos or missing awaits on functions like context.bot.send_message.
breaking Version 20.0 introduced significant breaking changes. The `Updater` class was removed and replaced by `Application`. The architecture shifted to `asyncio`, requiring async/await for handler functions. The `File.download` method was split into `File.download_to_drive` and `File.download_to_memory`. Most third-party dependencies became optional, requiring explicit installation for certain features.
fix Rewrite bot initialization to use `Application.builder().build()`, update handler functions to be `async def`, and adjust file download calls. Install optional dependencies if needed, e.g., `pip install "python-telegram-bot[job-queue]"`.
gotcha Since v20.0, `python-telegram-bot` is built on `asyncio` and is generally not thread-safe. Avoid using `telegram.ext.Application/Updater.update_queue`, `telegram.ext.ConversationHandler.check/handle_update`, `telegram.ext.CallbackDataCache`, and runtime modifications to `telegram.ext.filters` classes in multi-threaded environments to prevent race conditions.
fix Design your bot with asyncio concurrency in mind. If you must use threads for specific tasks, ensure proper synchronization for PTB components or isolate PTB interactions to the main async loop.
deprecated Timeout arguments (`read_timeout`, `write_timeout`, `connect_timeout`, `pool_timeout`) for `Application.run_polling()` were removed in v22.0.
fix Configure timeouts using `ApplicationBuilder` methods (e.g., `ApplicationBuilder().read_timeout(seconds)`) or by specifying them via `telegram.Bot.get_updates_request`.
deprecated Attributes representing durations/time periods (e.g., `ChatFullInfo.slow_mode_delay`) are migrating from `int` to `datetime.timedelta`. While `int` is currently supported, it's deprecated and will be removed in a future major version.
fix Set the environment variable `PTB_TIMEDELTA=true` or `PTB_TIMEDELTA=1` to opt into `datetime.timedelta` objects now. Update your code to handle `timedelta` objects for these attributes.
gotcha For new Telegram Bot API update types (e.g., `MESSAGE_REACTION_COUNT`, `BUSINESS_CONNECTION`), you must explicitly list them in `Application.run_polling(allowed_updates=...)` or `Bot.set_webhook(allowed_updates=...)` to receive them. Using `Update.ALL_TYPES` is generally safer for comprehensive update reception.
fix Always include relevant new update types in the `allowed_updates` parameter, or use `allowed_updates=Update.ALL_TYPES` if you want to receive all available updates by default.
breaking Version 22.5 addressed a breaking change accidentally introduced in v22.4 regarding the `ReplyParameters` class, where adding a new parameter broke positional arguments.
fix Upgrade to v22.5.0 or later. For future compatibility, always use keyword arguments when calling methods, especially those with many parameters or new parameters in recent versions.
pip install "python-telegram-bot[all]"
python os / libc variant status wheel install import disk
3.10 alpine (musl) all wheel - 0.89s 50.7M
3.10 alpine (musl) all - - 0.91s 49.6M
3.10 alpine (musl) python-telegram-bot wheel - 0.61s 28.8M
3.10 alpine (musl) python-telegram-bot - - 0.60s 28.7M
3.10 slim (glibc) all wheel 4.0s 0.71s 51M
3.10 slim (glibc) all - - 0.70s 50M
3.10 slim (glibc) python-telegram-bot wheel 2.4s 0.40s 29M
3.10 slim (glibc) python-telegram-bot - - 0.47s 29M
3.11 alpine (musl) all wheel - 1.50s 55.4M
3.11 alpine (musl) all - - 1.60s 54.2M
3.11 alpine (musl) python-telegram-bot wheel - 1.19s 31.8M
3.11 alpine (musl) python-telegram-bot - - 1.31s 31.8M
3.11 slim (glibc) all wheel 4.0s 1.24s 56M
3.11 slim (glibc) all - - 1.28s 55M
3.11 slim (glibc) python-telegram-bot wheel 2.5s 1.03s 32M
3.11 slim (glibc) python-telegram-bot - - 1.02s 32M
3.12 alpine (musl) all wheel - 1.34s 46.5M
3.12 alpine (musl) all - - 1.48s 45.4M
3.12 alpine (musl) python-telegram-bot wheel - 1.05s 23.3M
3.12 alpine (musl) python-telegram-bot - - 1.23s 23.3M
3.12 slim (glibc) all wheel 3.6s 1.32s 47M
3.12 slim (glibc) all - - 1.54s 46M
3.12 slim (glibc) python-telegram-bot wheel 2.3s 1.06s 24M
3.12 slim (glibc) python-telegram-bot - - 1.25s 24M
3.13 alpine (musl) all wheel - 1.38s 45.8M
3.13 alpine (musl) all - - 1.47s 44.5M
3.13 alpine (musl) python-telegram-bot wheel - 1.13s 22.6M
3.13 alpine (musl) python-telegram-bot - - 1.25s 22.4M
3.13 slim (glibc) all wheel 3.6s 1.28s 46M
3.13 slim (glibc) all - - 1.51s 45M
3.13 slim (glibc) python-telegram-bot wheel 2.3s 1.04s 23M
3.13 slim (glibc) python-telegram-bot - - 1.23s 23M
3.9 alpine (musl) all wheel - 0.77s 50.3M
3.9 alpine (musl) all - - 0.80s 49.3M
3.9 alpine (musl) python-telegram-bot wheel - 0.49s 27.9M
3.9 alpine (musl) python-telegram-bot - - 0.52s 27.9M
3.9 slim (glibc) all wheel 4.8s 0.65s 51M
3.9 slim (glibc) all - - 0.70s 50M
3.9 slim (glibc) python-telegram-bot wheel 2.8s 0.42s 28M
3.9 slim (glibc) python-telegram-bot - - 0.43s 28M

This quickstart code sets up a simple echo bot that replies to `/start` and `/help` commands, and echoes back any other text message it receives. It demonstrates the use of `Application`, `CommandHandler`, and `MessageHandler` with filters. Your bot token should be provided via the `TELEGRAM_BOT_TOKEN` environment variable.

import os
import logging
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes

# Enable logging
logging.basicConfig(
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
)
# set higher logging level for httpx to avoid all GET and POST requests being logged
logging.getLogger("httpx").setLevel(logging.WARNING)

logger = logging.getLogger(__name__)


async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Sends a message when the command /start is issued."""
    user = update.effective_user
    await update.message.reply_html(
        f"Hi {user.mention_html()}!\nI'm an echo bot. Send me anything!",
    )


async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Sends a message when the command /help is issued."""
    await update.message.reply_text("Help! Send me a message and I will echo it back!")


async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Echo the user message."""
    await update.message.reply_text(update.message.text)


async def main() -> None:
    """Start the bot."""
    # Replace with your bot's token from BotFather. Get from environment variable.
    BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
    if not BOT_TOKEN:
        raise ValueError("TELEGRAM_BOT_TOKEN environment variable not set.")

    # Create the Application and pass it your bot's token.
    application = Application.builder().token(BOT_TOKEN).build()

    # On different commands - add handlers
    application.add_handler(CommandHandler("start", start_command))
    application.add_handler(CommandHandler("help", help_command))

    # On non command messages - echo the message on Telegram
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))

    # Run the bot until the user presses Ctrl-C
    logger.info("Starting bot polling...")
    await application.run_polling(allowed_updates=Update.ALL_TYPES)


if __name__ == "__main__":
    import asyncio
    asyncio.run(main())