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

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.1.2
File Size Uploaded
puragram-1.1.2.tar.gz 26.9 kB Details

Built distribution (wheel)

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

Total release size: 51.5 kB

Release files / puragram-1.1.2.tar.gz

Download URL puragram-1.1.2.tar.gz
Size 26.9 kB
Tags Source
SHA-256 checksum
How to use checksums
0ad9a5aff140889b4e535f98d8e8486d9c88db4b6eac5a15857a0bd3ef59e0c3
BLAKE2b-256 checksum
How to use checksums
8adeff4de40596614dc2879e3c652e3965885921a6c580ec7f8d25068bb315a6
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.1.2-py3-none-any.whl

Download URL puragram-1.1.2-py3-none-any.whl
Size 24.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f1dfe634b4fd0520d8c22b5f68a4f4894c6cb25ae76f05985f9644f5775b29ee
BLAKE2b-256 checksum
How to use checksums
742671b9c8205f9011655f166631df776461e07ab1d40624bc6bfffb0c77f720
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

1.2.0

2 release files

This release

1.1.2 This release

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