Skip to content

v0.4.0

Latest

Choose a tag to compare

@smoxy smoxy released this 04 Jun 10:37

telegram-menu-builder v0.4.0

This release makes menus usable outside a python-telegram-bot Application, adds an atomic
multi-operator claim
primitive, and ships first-class test helpers — the high-leverage set
from real downstream feedback.

Added

  • Application-free, budget-enforced menus. MenuBuilder.to_markup() (synchronous →
    telegram.InlineKeyboardMarkup) and MenuBuilder.to_raw() (synchronous → a plain Telegram Bot API
    dict {"inline_keyboard": [[...]]}, built directly from items so it can be consumed without
    python-telegram-bot) build a menu with no event loop, no storage, and no worker thread. Every
    button is encoded inline; any item that would otherwise spill to storage raises EncodingError
    (use build_async() for those). assert_inline() is a cheap pre-flight, and the new
    MenuBuilder(on_oversize="spill" | "error") policy makes build_async() fail loudly instead of
    silently spilling. Backed by a new synchronous CallbackEncoder.encode_inline().
  • Atomic claim / idempotency for multi-operator workflows. A new atomic set-if-absent primitive
    StorageBackend.add(key, data, ttl=None) -> bool (non-atomic default on BaseStorage so existing
    custom backends keep working; concurrency-safe overrides for MemoryStorage, RedisStorage via
    SET … NX, and SQLAlchemyStorage via a single transaction that frees expired rows then INSERTs
    no-op-on-conflict). On top of it, MenuRouter.claim(key, user_id, *, ttl=3600), who_claimed(key),
    and release(key) provide a single-winner guarantee — verified end-to-end against live
    PostgreSQL 16, Redis 7, and Valkey 8
    (concurrent claimers → exactly one wins).
  • Testing helpers — new telegram_menu_builder.testing module (standard-library unittest.mock
    only; imported as a submodule). simulate_tap(router, callback_data, ...) and
    tap(router, handler, /, **params) drive a MenuRouter with no live Telegram and return a
    TapResult (answered, answer_text, edited_text, handler_error); assert_inline(target)
    verifies a MenuBuilder / InlineKeyboardMarkup / raw dict contains only inline I:/IC: callback
    buttons (no S:/P: storage references).

Full changelog: v0.3.0...v0.4.0