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) andMenuBuilder.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 raisesEncodingError
(usebuild_async()for those).assert_inline()is a cheap pre-flight, and the new
MenuBuilder(on_oversize="spill" | "error")policy makesbuild_async()fail loudly instead of
silently spilling. Backed by a new synchronousCallbackEncoder.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 onBaseStorageso existing
custom backends keep working; concurrency-safe overrides forMemoryStorage,RedisStoragevia
SET … NX, andSQLAlchemyStoragevia 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),
andrelease(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.testingmodule (standard-libraryunittest.mock
only; imported as a submodule).simulate_tap(router, callback_data, ...)and
tap(router, handler, /, **params)drive aMenuRouterwith no live Telegram and return a
TapResult(answered,answer_text,edited_text,handler_error);assert_inline(target)
verifies aMenuBuilder/InlineKeyboardMarkup/ raw dict contains only inlineI:/IC:callback
buttons (noS:/P:storage references).
Full changelog: v0.3.0...v0.4.0