A pure Python, asynchronous interface for the Telegram Bot API with comprehensive wrapper and high-level framework for building sophisticated Telegram bots
—
Complete file handling system supporting uploads, downloads, and media processing for all Telegram file types including photos, videos, documents, audio, stickers, and voice messages.
Upload files to Telegram from various sources.
class InputFile:
def __init__(
self,
obj: BinaryIO | bytes | str,
filename: str = None,
attach: bool = None
): ...
def __enter__(self) -> 'InputFile': ...
def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...
@property
def field_tuple(self) -> tuple: ...Usage examples:
from telegram import InputFile
# From file path
photo = InputFile("/path/to/photo.jpg")
await bot.send_photo(chat_id, photo)
# From bytes
with open("/path/to/document.pdf", "rb") as f:
document_bytes = f.read()
document = InputFile(document_bytes, filename="document.pdf")
await bot.send_document(chat_id, document)
# From file-like object
import io
buffer = io.BytesIO()
# ... write data to buffer
buffer.seek(0)
file_obj = InputFile(buffer, filename="generated.txt")
await bot.send_document(chat_id, file_obj)
# From URL (string)
await bot.send_photo(chat_id, "https://example.com/photo.jpg")
# From file_id (string)
await bot.send_photo(chat_id, "AgACAgIAAxkDAAIC...")Download files from Telegram servers.
class File:
file_id: str
file_unique_id: str
file_size: int | None
file_path: str | None
async def download_to_drive(
self,
custom_path: str = None,
block: bool = True
) -> str: ...
async def download_as_bytearray(self, block: bool = True) -> bytearray: ...
async def download_to_memory(self, out: BinaryIO = None, block: bool = True) -> BinaryIO: ...Usage examples:
# Get file object from message
if update.message.photo:
# Get largest photo size
photo = update.message.photo[-1]
file = await bot.get_file(photo.file_id)
# Download to specific path
file_path = await file.download_to_drive("downloads/photo.jpg")
print(f"Downloaded to: {file_path}")
# Download to default path (uses file_id as filename)
file_path = await file.download_to_drive()
# Download as bytes
file_bytes = await file.download_as_bytearray()
# Download to memory stream
import io
buffer = io.BytesIO()
await file.download_to_memory(buffer)
buffer.seek(0)
data = buffer.read()
# Handle document downloads
if update.message.document:
file = await bot.get_file(update.message.document.file_id)
filename = update.message.document.file_name or "unknown"
await file.download_to_drive(f"downloads/{filename}")Send multiple media files as a grouped message.
class InputMediaPhoto:
def __init__(
self,
media: str | InputFile,
caption: str = None,
parse_mode: str = None,
caption_entities: list[MessageEntity] = None,
show_caption_above_media: bool = None,
has_spoiler: bool = None
): ...
class InputMediaVideo:
def __init__(
self,
media: str | InputFile,
thumbnail: str | InputFile = None,
caption: str = None,
parse_mode: str = None,
caption_entities: list[MessageEntity] = None,
show_caption_above_media: bool = None,
width: int = None,
height: int = None,
duration: int = None,
supports_streaming: bool = None,
has_spoiler: bool = None
): ...
class InputMediaAnimation:
def __init__(
self,
media: str | InputFile,
thumbnail: str | InputFile = None,
caption: str = None,
parse_mode: str = None,
caption_entities: list[MessageEntity] = None,
show_caption_above_media: bool = None,
width: int = None,
height: int = None,
duration: int = None,
has_spoiler: bool = None
): ...
class InputMediaAudio:
def __init__(
self,
media: str | InputFile,
thumbnail: str | InputFile = None,
caption: str = None,
parse_mode: str = None,
caption_entities: list[MessageEntity] = None,
duration: int = None,
performer: str = None,
title: str = None
): ...
class InputMediaDocument:
def __init__(
self,
media: str | InputFile,
thumbnail: str | InputFile = None,
caption: str = None,
parse_mode: str = None,
caption_entities: list[MessageEntity] = None,
disable_content_type_detection: bool = None
): ...Usage example:
from telegram import InputMediaPhoto, InputMediaVideo
# Send media group
media_group = [
InputMediaPhoto("photo1.jpg", caption="First photo"),
InputMediaPhoto("photo2.jpg", caption="Second photo"),
InputMediaVideo("video.mp4", caption="A video")
]
messages = await bot.send_media_group(chat_id, media_group)Handle paid media content with star payments.
class InputPaidMediaPhoto:
def __init__(self, media: str | InputFile): ...
media: str | InputFile
class InputPaidMediaVideo:
def __init__(
self,
media: str | InputFile,
thumbnail: str | InputFile = None,
width: int = None,
height: int = None,
duration: int = None,
supports_streaming: bool = None
): ...
media: str | InputFile
thumbnail: str | InputFile | None
width: int | None
height: int | None
duration: int | None
supports_streaming: bool | None
class PaidMediaInfo:
star_count: int
paid_media: list[PaidMedia]
class PaidMediaPhoto:
type: str = "photo"
photo: list[PhotoSize]
class PaidMediaVideo:
type: str = "video"
video: Video
class PaidMediaPreview:
type: str = "preview"
width: int | None
height: int | None
duration: int | NoneUsage example:
from telegram import InputPaidMediaPhoto, InputPaidMediaVideo
# Send paid media
paid_media = [
InputPaidMediaPhoto("exclusive_photo.jpg"),
InputPaidMediaVideo("exclusive_video.mp4")
]
message = await bot.send_paid_media(
chat_id=chat_id,
star_count=10, # Cost in Telegram Stars
media=paid_media,
caption="Exclusive content for 10 stars!"
)Handle sticker uploads and sticker set management.
class InputSticker:
def __init__(
self,
sticker: str | InputFile,
format: str,
emoji_list: list[str],
mask_position: MaskPosition = None,
keywords: list[str] = None
): ...
sticker: str | InputFile
format: str # "static", "animated", "video"
emoji_list: list[str]
mask_position: MaskPosition | None
keywords: list[str] | None
class MaskPosition:
def __init__(
self,
point: str,
x_shift: float,
y_shift: float,
scale: float
): ...
point: str # "forehead", "eyes", "mouth", "chin"
x_shift: float
y_shift: float
scale: float
class Sticker:
file_id: str
file_unique_id: str
type: str # "regular", "mask", "custom_emoji"
width: int
height: int
is_animated: bool
is_video: bool
thumbnail: PhotoSize | None
emoji: str | None
set_name: str | None
premium_animation: File | None
mask_position: MaskPosition | None
custom_emoji_id: str | None
needs_repainting: bool | None
file_size: int | None
async def get_file(self, **kwargs) -> File: ...
class StickerSet:
name: str
title: str
sticker_type: str
stickers: list[Sticker]
thumbnail: PhotoSize | NoneUsage examples:
# Send existing sticker
await bot.send_sticker(chat_id, sticker_file_id)
# Create new sticker set
from telegram import InputSticker, MaskPosition
stickers = [
InputSticker(
sticker="sticker1.png",
format="static",
emoji_list=["😀", "😃"]
),
InputSticker(
sticker="sticker2.png",
format="static",
emoji_list=["😎"],
keywords=["cool", "sunglasses"]
)
]
success = await bot.create_new_sticker_set(
user_id=user_id,
name="my_sticker_set_by_mybot",
title="My Sticker Set",
stickers=stickers
)
# Add sticker to existing set
new_sticker = InputSticker(
sticker="new_sticker.png",
format="static",
emoji_list=["🎉"]
)
await bot.add_sticker_to_set(
user_id=user_id,
name="my_sticker_set_by_mybot",
sticker=new_sticker
)
# Get sticker set
sticker_set = await bot.get_sticker_set("my_sticker_set_by_mybot")
for sticker in sticker_set.stickers:
print(f"Sticker: {sticker.emoji} - {sticker.file_id}")Utilities for working with different file types.
# Check file types in messages
async def handle_media(update, context):
message = update.message
if message.photo:
# Handle photo
photo = message.photo[-1] # Get largest size
file = await bot.get_file(photo.file_id)
await file.download_to_drive(f"photos/{photo.file_id}.jpg")
elif message.video:
# Handle video
video = message.video
file = await bot.get_file(video.file_id)
filename = f"videos/{video.file_id}.mp4"
await file.download_to_drive(filename)
elif message.document:
# Handle document
document = message.document
file = await bot.get_file(document.file_id)
filename = document.file_name or f"document_{document.file_id}"
await file.download_to_drive(f"documents/{filename}")
elif message.audio:
# Handle audio
audio = message.audio
file = await bot.get_file(audio.file_id)
filename = f"{audio.performer or 'Unknown'} - {audio.title or 'Untitled'}.mp3"
await file.download_to_drive(f"audio/{filename}")
elif message.voice:
# Handle voice message
voice = message.voice
file = await bot.get_file(voice.file_id)
await file.download_to_drive(f"voice/{voice.file_id}.ogg")
elif message.video_note:
# Handle video note (circle video)
video_note = message.video_note
file = await bot.get_file(video_note.file_id)
await file.download_to_drive(f"video_notes/{video_note.file_id}.mp4")
elif message.sticker:
# Handle sticker
sticker = message.sticker
file = await bot.get_file(sticker.file_id)
extension = "tgs" if sticker.is_animated else "webm" if sticker.is_video else "webp"
await file.download_to_drive(f"stickers/{sticker.file_id}.{extension}")Understanding Telegram file limitations.
from telegram.constants import FileSizeLimit
# File size limits (in bytes)
max_photo_size = FileSizeLimit.FILESIZE_UPLOAD # 50 MB for bots
max_file_size = FileSizeLimit.FILESIZE_UPLOAD # 50 MB for bots
max_thumb_size = FileSizeLimit.FILESIZE_DOWNLOAD # 20 MB for downloads
# Check file size before upload
import os
def check_file_size(file_path):
size = os.path.getsize(file_path)
if size > FileSizeLimit.FILESIZE_UPLOAD:
raise ValueError(f"File too large: {size} bytes (max: {FileSizeLimit.FILESIZE_UPLOAD})")
return size
# Handle large files
async def send_large_file(bot, chat_id, file_path):
try:
check_file_size(file_path)
with open(file_path, 'rb') as f:
await bot.send_document(chat_id, InputFile(f))
except ValueError as e:
await bot.send_message(chat_id, f"Cannot send file: {e}")Generate and use thumbnails for media files.
# Send video with custom thumbnail
video_file = InputFile("video.mp4")
thumbnail_file = InputFile("thumbnail.jpg")
await bot.send_video(
chat_id=chat_id,
video=video_file,
thumbnail=thumbnail_file,
duration=120,
width=1920,
height=1080,
caption="Video with custom thumbnail"
)
# Send document with thumbnail
document_file = InputFile("document.pdf")
thumbnail_file = InputFile("doc_preview.jpg")
await bot.send_document(
chat_id=chat_id,
document=document_file,
thumbnail=thumbnail_file,
caption="PDF document with preview"
)Helper functions for common file operations.
import mimetypes
import os
from pathlib import Path
def get_file_info(file_path):
"""Get comprehensive file information."""
path = Path(file_path)
return {
'name': path.name,
'stem': path.stem,
'suffix': path.suffix,
'size': path.stat().st_size,
'mime_type': mimetypes.guess_type(str(path))[0],
'is_image': path.suffix.lower() in ['.jpg', '.jpeg', '.png', '.gif', '.webp'],
'is_video': path.suffix.lower() in ['.mp4', '.avi', '.mov', '.mkv'],
'is_audio': path.suffix.lower() in ['.mp3', '.wav', '.ogg', '.m4a']
}
async def process_uploaded_file(bot, message):
"""Process any type of uploaded file."""
file_obj = None
file_info = {}
if message.document:
file_obj = message.document
file_info = {
'type': 'document',
'name': file_obj.file_name,
'mime_type': file_obj.mime_type,
'size': file_obj.file_size
}
elif message.photo:
file_obj = message.photo[-1] # Largest size
file_info = {
'type': 'photo',
'width': file_obj.width,
'height': file_obj.height,
'size': file_obj.file_size
}
elif message.video:
file_obj = message.video
file_info = {
'type': 'video',
'duration': file_obj.duration,
'width': file_obj.width,
'height': file_obj.height,
'size': file_obj.file_size
}
# ... handle other types
if file_obj:
# Download file
file = await bot.get_file(file_obj.file_id)
local_path = await file.download_to_drive()
# Process file as needed
return {
'telegram_file': file_obj,
'local_path': local_path,
'info': file_info
}
return Nonefrom typing import BinaryIO, Union
from pathlib import Path
FileInput = Union[str, InputFile, BinaryIO, Path]Install with Tessl CLI
npx tessl i tessl/pypi-python-telegram-bot