Skip to main content

puragram

Fast, dependency-light Telegram Bot API framework built on urllib3. No aiohttp. No requests. No httpx.

PyPI Python License

Why puragram?

Most Telegram Python libraries pull in aiohttp or requests. puragram talks directly to the Telegram Bot API through urllib3 with a keep-alive connection pool. That means:

  • Small — no heavy dependencies, just urllib3
  • Fast — direct JSON requests, no middleware layers
  • Sync — simple, predictable, easy to debug

Install

pip install puragram

Requires Python 3.9+.

Quick start

from puragram import Bot

bot = Bot("YOUR_TOKEN", parse_mode="HTML")

@bot.message_handler(commands=["start"])
def start(msg):
    bot.send_message(msg.chat.id, f"Hi, <b>{msg.from_user.first_name}</b>!")

@bot.message_handler(content_types=["text"])
def echo(msg):
    bot.send_message(msg.chat.id, f"You said: <b>{msg.text}</b>")

if __name__ == "__main__":
    bot.run_polling()

FSM example

from puragram import Bot, RemoveKeyboard, State, StatesGroup

bot = Bot("YOUR_TOKEN", parse_mode="HTML")

class Form(StatesGroup):
    name = State()
    age = State()

@bot.message_handler(commands=["start"])
def start(msg, data):
    data["state"].set_state(Form.name)
    bot.send_message(msg.chat.id, "What's your name?")

@bot.message_handler(state=Form.name)
def on_name(msg, data):
    data["state"].update_data(name=msg.text)
    data["state"].set_state(Form.age)
    bot.send_message(msg.chat.id, f"Nice to meet you, {msg.text}. How old are you?")

@bot.message_handler(state=Form.age)
def on_age(msg, data):
    ctx = data["state"]
    if not msg.text.isdigit():
        bot.send_message(msg.chat.id, "Please enter a number.")
        return
    ctx.update_data(age=int(msg.text))
    info = ctx.get_data()
    ctx.clear()
    bot.send_message(
        msg.chat.id,
        f"Done!\nName: {info['name']}\nAge: {info['age']}",
        reply_markup=RemoveKeyboard(),
    )

bot.run_polling()

Inline mode

from puragram import Bot, InlineQueryResultArticle

bot = Bot("YOUR_TOKEN")

@bot.inline_query_handler()
def on_inline(q):
    results = [
        InlineQueryResultArticle(
            id="hello",
            title="Send hello",
            input_message_content={"message_text": "Hello!"},
        ),
    ]
    bot.answer_inline_query(q.id, results)

bot.run_polling()

Middleware

from puragram import Bot, LoggingMiddleware, ThrottlingMiddleware

bot = Bot("YOUR_TOKEN")
bot.middleware(LoggingMiddleware())
bot.middleware(ThrottlingMiddleware(rate=0.5))

@bot.message_handler(content_types=["text"])
def echo(msg):
    bot.send_message(msg.chat.id, msg.text)

bot.run_polling(workers=4)

Webhook

from puragram import Bot, WebhookServer

bot = Bot("YOUR_TOKEN")

@bot.message_handler(commands=["start"])
def start(msg):
    bot.send_message(msg.chat.id, "Hello via webhook!")

if __name__ == "__main__":
    server = WebhookServer(
        bot,
        host="0.0.0.0",
        port=8080,
        path="/webhook",
        secret_token="change-me-to-random-32-chars",
    )
    server.install("https://your-domain.com/webhook")
    server.start(blocking=True)

Features

  • Long-polling and webhook (pure stdlib http.server)
  • Inline mode: @yourbot query with results
  • FSM: State, StatesGroup, MemoryStorage, FileStorage, SQLiteStorage
  • Middleware: logging, throttling, timing
  • Filters: Command, Text, Regexp, ContentTypes, ChatType, ChatId, UserId, CallbackData, CallbackDataPrefix, Func
  • Filter operators: & (and), | (or), ~ (not)
  • File sending: photo, document, video, audio, voice, sticker
  • Extras: poll, location, contact, dice
  • Auto-split for long messages: send_long_message
  • Security: path traversal guard, size limits, ReDoS protection, token redaction, dedup, safe SQLite
  • Zero dependencies except urllib3

Performance

Benchmarked on Termux (Android, same Wi-Fi, ~30 ms to Telegram, median of 3 trials):

Workload puragram pyTelegramBotAPI
5 × sendMessage 85 ms/msg 89 ms/msg
3 × sendPhoto 99 ms/msg 116 ms/msg

Your results will vary with network latency.

Security

  • Path traversal — safe_path() rejects /etc, /proc, /sys, /root, /dev
  • Upload size — 50 MB limit enforced
  • Callback data — validated to ≤64 UTF-8 bytes
  • ReDoS — compile_safe_regex() rejects nested quantifiers
  • Webhook forgery — hmac.compare_digest on secret token
  • Token leakage — bot tokens redacted from logs
  • Idempotency — duplicate update_id dropped via LRU
  • SQL injection — parameterized queries only

Documentation

Full beginner's guide: ABOUT.md.

Changelog: CHANGELOG.md.

License

MIT — see LICENSE.

Release files for puragram 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for puragram 1.2.0
File Size Uploaded
puragram-1.2.0.tar.gz 29.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for puragram 1.2.0
File Interpreter ABI Platform
puragram-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 56.7 kB

Release files / puragram-1.2.0.tar.gz

Download URL puragram-1.2.0.tar.gz
Size 29.8 kB
Tags Source
SHA-256 checksum
How to use checksums
b4b69d56b19129fcb7374451d070f51e1855459e2882a13bc232361903f35925
BLAKE2b-256 checksum
How to use checksums
efccf6458607dbf957b78cf9359b088ca731c8ca927294d636a168e79a1a8581
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / puragram-1.2.0-py3-none-any.whl

Download URL puragram-1.2.0-py3-none-any.whl
Size 26.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1527a964f21e9f5c096f0f5de721203e00d7d438d66975715427de63ccefa4fa
BLAKE2b-256 checksum
How to use checksums
34097af0bdb9a4edf8fd9d68c98c257b2526f74f3fab63c9029fb2a46e69fed5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

1.2.1

2 release files

This release

1.2.0 This release

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page