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.1

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.1
File Size Uploaded
puragram-1.2.1.tar.gz 30.6 kB Details

Built distribution (wheel)

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

Total release size: 57.6 kB

Release files / puragram-1.2.1.tar.gz

Download URL puragram-1.2.1.tar.gz
Size 30.6 kB
Tags Source
SHA-256 checksum
How to use checksums
efc298946e9f7720ee8f660310b5ed83eb1caaf075d78102ce3f21fec35eaff4
BLAKE2b-256 checksum
How to use checksums
525f7947e94ad2fee60849a032840d515108f61163a1dcf2b2d25fd2c3bd95ee
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.1-py3-none-any.whl

Download URL puragram-1.2.1-py3-none-any.whl
Size 27.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
89a0a0c2d814dcd33d2ccfb1b49134187935d5225d44b0c708af5aa99a9134f8
BLAKE2b-256 checksum
How to use checksums
ccebc2ea8d1f25dbbd4da73fba0476689525758c7e9c3da7ac41e3c7713eaab4
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

This release

1.2.1 This release

2 release files

1.2.0

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