### Install Mubble with optional dependencies Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/installation.md These commands install Mubble along with its optional dependencies, such as `aiosonic` for an alternative HTTP client and `msgpack` for efficient serialization. This ensures all necessary packages for advanced features are available, using either `pip` or `poetry`. ```bash pip install mubble[full] ``` ```bash poetry add mubble[full] ``` -------------------------------- ### Install Mubble using pip or Poetry Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/installation.md These commands demonstrate how to install the Mubble library using common Python package managers. You can choose between `pip` for direct installation or `poetry` for project-based dependency management to get the latest stable version. ```bash pip install mubble ``` ```bash pip install mubble==1.6.0 ``` ```bash poetry add mubble ``` -------------------------------- ### Install Mubble from GitHub source Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/installation.md These commands allow you to install the latest development version of Mubble directly from its GitHub repository. This is useful for accessing the newest features or contributing to the project, using either `pip` or `poetry`. ```bash pip install git+https://github.com/vladislavkovalskyi/mubble.git#master ``` ```bash poetry add git+https://github.com/vladislavkovalskyi/mubble.git#master ``` -------------------------------- ### Set Up Mubble Telegram Bot Project Directory Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/quickstart.md This snippet provides bash commands to create a new directory for your Mubble bot project and an empty Python file (`bot.py`) within it. These steps are essential to organize your bot's code before writing the main logic. ```bash mkdir my_first_bot cd my_first_bot touch bot.py ``` -------------------------------- ### Run Your Mubble Telegram Bot Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/quickstart.md This bash command executes the Python script containing your Mubble bot's code. Running this command will start the bot, allowing it to connect to Telegram and begin processing messages. Ensure you are in the project directory where `bot.py` is located. ```bash python bot.py ``` -------------------------------- ### Verify Mubble installation with Python Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/installation.md This Python script provides a simple way to confirm that Mubble has been successfully installed and is accessible in your Python environment. It imports the library and prints a confirmation message. ```python import mubble print(f"Mubble installed successfully!") ``` -------------------------------- ### Create a Basic Mubble Telegram Echo Bot Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/quickstart.md This Python code defines a simple Telegram echo bot using the Mubble framework. It initializes the API with a bot token, sets up handlers for the `/start` command and any text messages, and then runs the bot indefinitely. Remember to replace 'YOUR_BOT_TOKEN' with your actual Telegram bot token. ```python from mubble import API, Message, Mubble, Token from mubble.modules import logger from mubble.rules import StartCommand, Text # Initialize the API with your bot token api = API(token=Token("YOUR_BOT_TOKEN")) # Replace with your actual token # Or load from environment variable: # api = API(token=Token.from_env()) # Set TOKEN environment variable # Create a bot instance bot = Mubble(api) # Set logging level logger.set_level("INFO") # Handler for /start command @bot.on.message(StartCommand()) async def start_handler(message: Message) -> None: await message.answer(f"Hello, {message.from_user.full_name}! I'm an echo bot created with Mubble.") # Handler for any text message @bot.on.message(Text()) async def echo_handler(message: Message) -> None: await message.answer(f"You said: {message.text}") # Run the bot if __name__ == "__main__": bot.run_forever() ``` -------------------------------- ### Initialize and Run a Basic Mubble Bot Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/bot-structure.md Demonstrates the fundamental setup of a Mubble bot, including API initialization with a token, logging configuration, registering a message handler, and starting the bot in blocking mode. ```python from mubble import API, Mubble, Token from mubble.modules import logger # Initialize components api = API(token=Token("YOUR_BOT_TOKEN")) bot = Mubble(api) # Configure logging logger.set_level("INFO") # Register handlers @bot.on.message(...) async def handler(message): ... # Run the bot bot.run_forever() ``` -------------------------------- ### Create a simple Mubble Telegram bot Source: https://github.com/vladislavkovalskyi/mubble/blob/master/README.md This example demonstrates how to set up a basic Telegram bot using the Mubble framework. It includes handlers for start commands, menu navigation, random number generation, and inline keyboard interactions, showcasing common bot functionalities. ```python import random from mubble import Token, API, Mubble, Message, CallbackQueryEq from mubble.rules import StartCommand, Text, Markup, CallbackData from mubble.tools.keyboard import InlineKeyboard, InlineButton api = API(Token("Your token")) bot = Mubble(api) class Keyboard: menu = ( InlineKeyboard() .add(InlineButton("✍️ Write hello", callback_data="hello")) .row() .add(InlineButton("🍌 Choice banana", callback_data="banana")) ).get_markup() back = ( InlineKeyboard().add(InlineButton("⬅️ Back", callback_data="menu")) ).get_markup() @bot.on.message(StartCommand()) async def start_handler(message: Message): await message.answer( "👋 Hello, I'm Mubble! How can I help you?\n\n" "My available commands:\n" "- /start\n" "- /menu\n" "- /random [from number] [to number]" ) @bot.on.message(Text("/menu")) async def menu_handler(message: Message): await message.answer( "📃 Here's your menu! Use the keyboard.", reply_markup=Keyboard.menu ) @bot.on.message(Markup(["/random", "/random "])) async def random_handler(message: Message, a: int = None, b: int = None): if None in (a, b): await message.answer( "🤓 Wrong syntax. You also need to write the first number and the second number." ) return await message.answer(f"🎲 Your random number is {random.randint(a, b)}") @bot.on.callback_query(CallbackQueryEq("menu")) async def menu_handler(cq: CallbackQuery): await cq.edit_text( "📃 Here's your menu! Use the keyboard.", reply_markup=Keyboard.menu ) @bot.on.callback_query(CallbackQueryEq("hello")) async def hello_handler(cq: CallbackQuery): await cq.edit_text("👋 Hello, I'm Mubble!", reply_markup=Keyboard.back) @bot.on.callback_query(CallbackQueryEq("banana")) async def fruits_handler(cq: CallbackQuery): await cq.answer("You clicked on the 🍌!") bot.run_forever() ``` -------------------------------- ### Add Command Handler to Mubble Bot Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/quickstart.md This Python snippet demonstrates how to add a new command handler to an existing Mubble bot. It defines a handler for the `/help` command, which sends a predefined help message to the user. This extends the bot's functionality beyond simple echoing. ```python @bot.on.message(Text("/help")) async def help_handler(message: Message) -> None: await message.answer( "This is a simple echo bot created with Mubble.\n" "Available commands:\n" "/start - Start the bot\n" "/help - Show this help message" ) ``` -------------------------------- ### Install Mubble using pip Source: https://github.com/vladislavkovalskyi/mubble/blob/master/README.md This command installs the Mubble framework using the pip package manager. It fetches the latest stable version of Mubble from PyPI, making it available for use in your Python projects. ```bash pip install mubble ``` -------------------------------- ### Clone Mubble Repository Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/contributing.md Instructions to clone your forked Mubble repository from GitHub to your local machine and navigate into the project directory, initiating your development setup. ```bash git clone https://github.com/your-username/mubble.git cd mubble ``` -------------------------------- ### Rate Limiting Middleware Setup in Mubble Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/middleware.md Initial setup for a rate limiting middleware, showing the import of `time` and `defaultdict` to store the last request time for each user. This snippet provides the foundation for a full rate-limiting implementation. ```Python import time from collections import defaultdict # Store last request time for each user last_request = defaultdict(float) ``` -------------------------------- ### Implement Inline Keyboards in Mubble Bot Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/quickstart.md This Python code shows how to integrate inline keyboards into a Mubble Telegram bot. It defines a handler for the `/menu` command that sends a message with an inline keyboard, and separate handlers for the callback queries triggered by button presses. This allows for interactive user interfaces. ```python from mubble.tools.keyboard import InlineKeyboard, InlineButton from mubble import CallbackQuery @bot.on.message(Text("/menu")) async def menu_handler(message: Message) -> None: keyboard = ( InlineKeyboard() .add(InlineButton("Option 1", callback_data="option_1")) .add(InlineButton("Option 2", callback_data="option_2")) ).get_markup() await message.answer("Please select an option:", reply_markup=keyboard) @bot.on.callback_query(lambda cq: cq.data == "option_1") async def option_1_handler(callback_query: CallbackQuery) -> None: await callback_query.answer("You selected Option 1!") await callback_query.message.answer("You clicked Option 1") @bot.on.callback_query(lambda cq: cq.data == "option_2") async def option_2_handler(callback_query: CallbackQuery) -> None: await callback_query.answer("You selected Option 2!") await callback_query.message.answer("You clicked Option 2") ``` -------------------------------- ### Handle /start Command (Mubble Python) Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/rules.md This specialized rule specifically matches the '/start' command. It supports optional parameter extraction from the command, allowing for dynamic behavior based on the start payload. ```python from mubble.rules import StartCommand @bot.on.message(StartCommand()) async def start_handler(message: Message) -> None: await message.answer("Welcome to the bot!") # With parameter extraction @bot.on.message(StartCommand(lambda x: int(x) if x.isdigit() else None)) async def start_with_param(message: Message, param: int | None) -> None: if param is None: await message.answer("Started without a parameter") else: await message.answer(f"Started with parameter: {param}") ``` -------------------------------- ### Basic Handlers: Message Handler Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/handlers.md Message handlers process incoming messages. This example shows how to register a handler that responds to the '/start' command and sends a greeting. ```python from mubble import Message from mubble.rules import Text @bot.on.message(Text("/start")) async def start_handler(message: Message) -> None: await message.answer(f"Hello, {message.from_user.full_name}!") ``` -------------------------------- ### Install Pre-commit Hooks for Mubble Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/contributing.md Command to install pre-commit hooks, which automatically run code quality checks and formatting tools (like Black and isort) before each commit, ensuring code consistency. ```bash pre-commit install ``` -------------------------------- ### Basic Webhook Setup with Mubble Python Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/webhooks.md Demonstrates how to set up a standalone webhook server using Mubble's built-in WebhookServer. It covers bot initialization, handler registration, detailed webhook configuration, and server startup for receiving Telegram updates. ```python from mubble import API, Mubble, Token, WebhookConfig from mubble.server import WebhookServer # Create API client and bot api = API(token=Token("YOUR_BOT_TOKEN")) bot = Mubble(api) # Register your handlers @bot.on.message() async def echo_handler(message): await message.answer(message.text) # Configure webhook webhook_config = WebhookConfig( url="https://your-domain.com/webhook", certificate=None, # Path to certificate file if self-signed ip_address=None, # Optional IP address max_connections=40, # Maximum number of connections allowed_updates=["message", "callback_query"], # Types of updates to receive drop_pending_updates=True, # Whether to drop pending updates secret_token="your-secret-token" # Secret token to validate webhook requests ) # Create webhook server server = WebhookServer( bot=bot, webhook_config=webhook_config, host="0.0.0.0", # Server host port=8443, # Server port path="/webhook" # Webhook endpoint path ) # Start the webhook server if __name__ == "__main__": server.run() ``` -------------------------------- ### Dockerize Mubble Bot for Deployment (Dockerfile) Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/webhooks.md Provides a Dockerfile for containerizing a Mubble bot, including setting up the Python environment, installing dependencies, copying application files, exposing a port, and defining the startup command. ```Dockerfile FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8443 CMD ["python", "bot.py"] ``` -------------------------------- ### Install Mubble using Poetry Source: https://github.com/vladislavkovalskyi/mubble/blob/master/README.md This command adds the Mubble framework as a dependency to your project using Poetry. It integrates Mubble into your project's dependency management, ensuring consistent environments. ```bash poetry add mubble ``` -------------------------------- ### Install Mubble Development Dependencies Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/contributing.md Command to install all necessary development dependencies for Mubble. The '-e ".[dev]"' flag installs the package in editable mode and includes additional development-specific dependencies. ```bash pip install -e ".[dev]" ``` -------------------------------- ### Implement Custom State Storage with Redis in Mubble Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/state-management.md Demonstrates how to create a custom state storage solution by inheriting from `ABCStateStorage`. This example shows an asynchronous Redis-backed implementation for `get`, `set`, and `delete` operations, allowing Mubble to persist state data externally. ```python from mubble.tools.state_storage import ABCStateStorage, StateData import redis class RedisStateStorage(ABCStateStorage): def __init__(self, redis_url: str) -> None: self.redis = redis.from_url(redis_url) async def get(self, key: str | int) -> StateData | None: data = self.redis.get(f"state:{key}") if data: return StateData.from_json(data) return None async def set(self, key: str | int, state_data: StateData) -> None: self.redis.set(f"state:{key}", state_data.to_json()) async def delete(self, key: str | int) -> None: self.redis.delete(f"state:{key}") ``` -------------------------------- ### Initialize and Run Mubble Bot Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/basic-concepts.md This snippet illustrates how to initialize the central `Mubble` (or `Bot`) class, linking it to an `API` instance. It then shows how to start the bot's polling mechanism using `bot.run_forever()`, which continuously fetches and processes updates from the Telegram API. ```python from mubble import API, Mubble, Token api = API(token=Token("YOUR_BOT_TOKEN")) bot = Mubble(api) # Start the bot bot.run_forever() ``` -------------------------------- ### Manage Simple User States with Mubble ShortState Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/state-management.md Illustrates the use of `ShortState` for managing simple, sequential user states. This example sets up a basic registration flow, demonstrating how to define states, set initial states, transition between them, and store user data within the state storage using message handlers. ```python from mubble import ShortState, Message from mubble.rules import Text # Define states START = ShortState("start") WAITING_FOR_NAME = ShortState("waiting_for_name") WAITING_FOR_AGE = ShortState("waiting_for_age") FINISHED = ShortState("finished") # Create a state storage state_storage = MemoryStateStorage() @bot.on.message(Text("/register")) async def register_handler(message: Message) -> None: user_id = message.from_user.id # Set initial state await state_storage.set(user_id, StateData(state=START.state)) # Transition to waiting for name await state_storage.set(user_id, StateData(state=WAITING_FOR_NAME.state)) await message.answer("Please enter your name.") @bot.on.message(WAITING_FOR_NAME) async def name_handler(message: Message) -> None: user_id = message.from_user.id name = message.text # Store the name state_data = await state_storage.get(user_id) data = state_data.data or {} data["name"] = name # Transition to waiting for age await state_storage.set( user_id, StateData(state=WAITING_FOR_AGE.state, data=data) ) await message.answer(f"Nice to meet you, {name}! Now, please enter your age.") @bot.on.message(WAITING_FOR_AGE) async def age_handler(message: Message) -> None: user_id = message.from_user.id try: age = int(message.text) except ValueError: await message.answer("Please enter a valid age (a number).") return # Get the stored data state_data = await state_storage.get(user_id) data = state_data.data or {} name = data.get("name", "User") # Store the age data["age"] = age # Transition to finished await state_storage.set( user_id, StateData(state=FINISHED.state, data=data) ) await message.answer(f"Registration complete! Name: {name}, Age: {age}") ``` -------------------------------- ### Install Mubble from Git with Poetry Source: https://github.com/vladislavkovalskyi/mubble/blob/master/README.md This command adds Mubble as a dependency to your project using Poetry, directly from its GitHub repository's master branch. This is useful for obtaining the very latest development version or specific unreleased features. ```bash poetry add git+https://github.com/vladislavkovalskyi/mubble.git#master ``` -------------------------------- ### Configure Non-Final Handlers in Mubble Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/handlers.md Illustrates how to configure a handler as non-final using `final=False`, allowing subsequent matching handlers to also be executed. This example shows two handlers for the `/start` command, both of which will run. ```python @bot.on.message(Text("/start"), final=False) async def non_final_handler(message: Message) -> None: # This handler will be executed, but other matching handlers will also be checked await message.answer("First handler") @bot.on.message(Text("/start")) async def another_handler(message: Message) -> None: # This handler will also be executed if the first handler is not final await message.answer("Second handler") ``` -------------------------------- ### Basic Handlers: Chat Join Request Handler Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/handlers.md Chat join request handlers process requests from users to join a chat. This example shows how to approve a request and send a welcome message to the user. ```python from mubble import ChatJoinRequest @bot.on.chat_join_request() async def join_request_handler(join_request: ChatJoinRequest) -> None: await join_request.approve() await bot.api.send_message( chat_id=join_request.user_chat_id, text=f"Welcome to {join_request.chat.title}!" ) ``` -------------------------------- ### Setting and Getting Values in Mubble Global Context Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/global-context.md Illustrates various operations on the global context, including setting and retrieving values, using default values, checking for key existence, and deleting keys. ```python from mubble import Message, Context @bot.on.message() async def handler(message: Message, ctx: Context) -> None: # Get the global context global_ctx = ctx.global_ctx # Set a value global_ctx.set("last_user", message.from_user.id) # Get a value last_user = global_ctx.get("last_user") # Get a value with a default counter = global_ctx.get("counter", 0) # Check if a key exists has_counter = "counter" in global_ctx # Delete a key if "temporary_data" in global_ctx: del global_ctx["temporary_data"] await message.answer(f"Last user: {last_user}, Counter: {counter}") ``` -------------------------------- ### Managing Configuration with Mubble Global Context Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/global-context.md This example demonstrates how to use the global context to store and manage application configuration values. A middleware initializes the configuration dictionary, making it accessible to all handlers for consistent access to settings like API URLs and keys. ```python from mubble import Message, Context # Initialize configuration @bot.dispatch.middleware async def init_config(update, next_handler, ctx: Context): global_ctx = ctx.global_ctx # Set configuration values if not exists if "config" not in global_ctx: config = { "api_url": "https://api.example.com", "api_key": "your-api-key", "max_retries": 3, "timeout": 10 } global_ctx.set("config", config) return await next_handler(update) @bot.on.message() async def handler(message: Message, ctx: Context) -> None: global_ctx = ctx.global_ctx # Get configuration config = global_ctx.get("config") # Use configuration values api_url = config["api_url"] api_key = config["api_key"] await message.answer(f"API URL: {api_url}") ``` -------------------------------- ### Implementing Logging Middleware in Mubble Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/middleware.md Provides an example of a logging middleware that logs incoming update details and message information. It also includes error logging for exceptions during handler processing, demonstrating robust logging practices. ```Python from mubble.modules import logger @bot.dispatch.middleware async def logging_middleware(update: Update, next_handler: Callable) -> Any: # Log the incoming update logger.info( "Received update (update_id={}, type={})", update.update_id, update.update_type.name ) # Log message details if present if update.message: logger.info( "Message from user {} (id={}): {}", update.message.from_user.full_name, update.message.from_user.id, update.message.text ) # Call the next handler try: result = await next_handler(update) logger.info("Update processed successfully") return result except Exception as e: logger.error("Error processing update: {}", e) raise ``` -------------------------------- ### Match Command Messages (Mubble Python) Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/rules.md This rule identifies messages that start with a specific command. It can be used to trigger handlers for commands like '/help' and allows for parsing arguments that follow the command. ```python from mubble.rules import Command @bot.on.message(Command("help")) async def help_handler(message: Message) -> None: await message.answer("This is the help message.") # With arguments @bot.on.message(Command("echo")) async def echo_handler(message: Message) -> None: args = message.text.split()[1:] # Get arguments after command await message.answer(" ".join(args)) ``` -------------------------------- ### Register Handlers with Mubble Dispatcher Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/basic-concepts.md This snippet demonstrates how to register different types of handlers using the `bot.on` property, which exposes the dispatcher's registration methods. It shows examples for registering a message handler and a callback query handler, indicating how incoming updates are routed to specific functions. ```python @bot.on.message(...) # Register a message handler @bot.on.callback_query(...) # Register a callback query handler ``` -------------------------------- ### Apply Mubble Rules for Handler Execution Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/basic-concepts.md This snippet demonstrates the use of Mubble's built-in rules to control when handlers should be executed. It shows examples of `Text` for exact string matching, `Command` for command parsing, and `Regex` for pattern-based matching. These rules are passed to the `@bot.on.message` decorator to filter incoming updates. ```python from mubble.rules import Text, Command, Regex @bot.on.message(Text("/start")) # Exact text match @bot.on.message(Command("help")) # Command match @bot.on.message(Regex(r"^\d+$")) # Regex pattern match ``` -------------------------------- ### Accessing API Client in Mubble Middleware Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/middleware.md Demonstrates how to inject and use the `API` client within a middleware function. It shows an example of calling `api.get_me()` to retrieve bot information before passing control to the next handler. ```Python from mubble import API @bot.dispatch.middleware async def api_middleware(update: Update, next_handler: Callable, api: API) -> Any: # Use the API client me = (await api.get_me()).unwrap() print(f"Processing update for bot: {me.username}") # Call the next handler return await next_handler(update) ``` -------------------------------- ### Basic Handlers: Callback Query Handler Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/handlers.md Callback query handlers process button presses from inline keyboards. This example demonstrates handling a callback with specific data, answering the query, and editing the original message. ```python from mubble import CallbackQuery @bot.on.callback_query(lambda cq: cq.data == "option_1") async def option_1_handler(callback_query: CallbackQuery) -> None: await callback_query.answer("You selected Option 1!") await callback_query.message.edit_text("Option 1 selected") ``` -------------------------------- ### Implement Complex State Machines with Mubble State Views Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/state-management.md Demonstrates how to use `BaseStateView` for building more sophisticated state machines. This example defines a `RegistrationView` with decorated state methods, showing how to manage state transitions, update data, and clear state within a structured class, along with registering the view with the bot. ```python from mubble import BaseStateView, Message, Context from mubble.rules import Text class RegistrationView(BaseStateView): def get_state_key(self, message: Message, ctx: Context) -> str: return str(message.from_user.id) @BaseStateView.state("start") async def start(self, message: Message) -> None: await message.answer("Please enter your name.") await self.set_state("waiting_for_name") @BaseStateView.state("waiting_for_name") async def waiting_for_name(self, message: Message) -> None: name = message.text await self.update_data(name=name) await message.answer(f"Nice to meet you, {name}! Now, please enter your age.") await self.set_state("waiting_for_age") @BaseStateView.state("waiting_for_age") async def waiting_for_age(self, message: Message) -> None: try: age = int(message.text) except ValueError: await message.answer("Please enter a valid age (a number).") return data = await self.get_data() name = data.get("name", "User") await self.update_data(age=age) await message.answer(f"Registration complete! Name: {name}, Age: {age}") await self.clear_state() # Create the view registration_view = RegistrationView(state_storage) # Register the view @bot.on.message(Text("/register")) async def register_handler(message: Message) -> None: await registration_view.set_state("start", message) await registration_view.start(message) # Register the view's message handler @bot.on.message() async def message_handler(message: Message) -> None: await registration_view.process_message(message) ``` -------------------------------- ### Handle Callback Queries in Mubble Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/callback-queries.md After a user clicks an inline keyboard button, your bot receives a callback query. This example shows how to register a handler for a specific callback data, answer the query to provide feedback, and edit the original message text. ```python from mubble import CallbackQuery @bot.on.callback_query(lambda cq: cq.data == "option_1") async def option_1_handler(callback_query: CallbackQuery) -> None: # Answer the callback query (shows a notification to the user) await callback_query.answer("You selected Option 1!") # Edit the message text await callback_query.message.edit_text("Option 1 selected") ``` -------------------------------- ### Initializing and Cleaning Up Global Context Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/global-context.md Illustrates how to set up initial values in the global context when the bot starts and perform cleanup operations, such as saving data, when the bot stops. This snippet also shows a basic message handler interacting with the global context. ```python from mubble import API, Mubble, Token import asyncio # Create API client and bot api = API(token=Token("YOUR_BOT_TOKEN")) bot = Mubble(api) # Initialize the global context async def init_global_context(): # Set initial values bot.global_ctx.set("start_time", time.time()) bot.global_ctx.set("counter", 0) bot.global_ctx.set("user_stats", {}) print("Global context initialized") # Clean up the global context async def cleanup_global_context(): # Perform cleanup if "user_stats" in bot.global_ctx: # Save user stats to a database user_stats = bot.global_ctx.get("user_stats") await save_user_stats_to_db(user_stats) print("Global context cleaned up") # Register your handlers @bot.on.message() async def handler(message, ctx): # Use the global context global_ctx = ctx.global_ctx counter = global_ctx.get("counter", 0) counter += 1 global_ctx.set("counter", counter) await message.answer(f"Counter: {counter}") # Run the bot async def main(): # Initialize the global context await init_global_context() try: # Start the bot await bot.start_polling() finally: # Clean up the global context await cleanup_global_context() if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Combining rules with logical AND operator Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/rules.md Illustrates how to combine multiple rules using the logical AND (`&`) operator. This example shows a handler that triggers only if the message text is 'admin' AND it's from a specific user ID, enabling highly specific command handling. ```python from mubble.rules import Text, FromUser @bot.on.message(Text("admin") & FromUser(123456789)) async def admin_command_handler(message: Message) -> None: await message.answer("Admin command executed") ``` -------------------------------- ### Run Mubble Bot with Default Loop Wrapper Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/loop-wrapper.md Demonstrates the simplest way to run a Mubble bot using the `bot.run_polling()` method, which internally leverages the loop wrapper to create an asyncio event loop, start polling, and handle termination signals gracefully. ```python from mubble import API, Mubble, Token # Create API client and bot api = API(token=Token("YOUR_BOT_TOKEN")) bot = Mubble(api) # Register your handlers @bot.on.message() async def echo_handler(message): await message.answer(message.text) # Run the bot with polling if __name__ == "__main__": bot.run_polling() ``` -------------------------------- ### Integrating Mubble LoopWrapper with AIOHTTP for Webhooks Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/loop-wrapper.md This example illustrates how to integrate Mubble's LoopWrapper with an AIOHTTP web application to manage Telegram bot webhooks. It covers setting up the AIOHTTP app, defining webhook routes, configuring startup/shutdown hooks for webhook management, and running the application using the LoopWrapper. ```python import asyncio from aiohttp import web from mubble import API, Mubble, Token, WebhookConfig from mubble.server import setup_webhook from mubble.loop import LoopWrapper # Create API client and bot api = API(token=Token("YOUR_BOT_TOKEN")) bot = Mubble(api) # Register your handlers @bot.on.message() async def echo_handler(message): await message.answer(message.text) # Configure webhook webhook_config = WebhookConfig( url="https://your-domain.com/webhook", secret_token="your-secret-token" ) # Create AIOHTTP application app = web.Application() # Add your routes app.router.add_get("/", lambda request: web.Response(text="Bot is running")) # Setup webhook setup_webhook( app=app, bot=bot, webhook_config=webhook_config, path="/webhook" ) # Define startup and shutdown handlers async def on_startup(app): # Set webhook await api.set_webhook(webhook_config) print("Webhook set") async def on_shutdown(app): # Delete webhook await api.delete_webhook() print("Webhook deleted") # Register startup and shutdown handlers app.on_startup.append(on_startup) app.on_shutdown.append(on_shutdown) # Create a loop wrapper wrapper = LoopWrapper() # Run the application if __name__ == "__main__": wrapper.run(web._run_app(app, host="0.0.0.0", port=8443)) ``` -------------------------------- ### Manage state across callback queries using Context Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/callback-queries.md This example illustrates how to use Mubble's `Context` object to maintain state between different callback queries. It shows how to retrieve, update, and store a 'page' number, then update the message to reflect the new state, enabling multi-step user interactions. ```python from mubble import Context @bot.on.callback_query(PayloadEqRule("page/next")) async def next_page_handler(callback_query: CallbackQuery, ctx: Context) -> None: # Get the current page from context (default to 1) current_page = ctx.get("page", 1) # Increment the page next_page = current_page + 1 # Store the new page in context ctx.set("page", next_page) # Update the message await callback_query.message.edit_text(f"Page {next_page}") ``` -------------------------------- ### Integrate gettext for Advanced Internationalization Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/i18n.md This snippet demonstrates how to integrate the `gettext` library for more robust internationalization. It shows how to set up `gettext` with a locale directory, create a helper function to retrieve translation functions, and incorporate this into the bot's middleware. The example also illustrates how to use the `_` translation function within a message handler to translate strings, ensuring proper localization. ```Python import gettext import os # Set up gettext localedir = os.path.join(os.path.dirname(__file__), "locales") gettext.bindtextdomain("mybot", localedir) gettext.textdomain("mybot") def get_translation(language: str): """Get a translation function for the given language.""" try: translation = gettext.translation("mybot", localedir, languages=[language]) return translation.gettext except FileNotFoundError: # Fallback to default gettext function return gettext.gettext @bot.dispatch.middleware async def i18n_middleware(update: Update, next_handler: Callable, ctx: Context) -> Any: # Determine user's language user_language = "en" if update.message and update.message.from_user.language_code: user_language = update.message.from_user.language_code if "-" in user_language: user_language = user_language.split("-")[0] # Get translation function for the language _ = get_translation(user_language) # Set the translation function in context ctx.set("_", _) # Call the next handler return await next_handler(update) # Use the translation function in a handler @bot.on.message(Text("/start")) async def start_handler(message: Message, ctx: Context) -> None: # Get the translation function from context _ = ctx.get("_") # Translate messages welcome_message = _("Welcome to the bot!") hello_message = _("Hello, {}!").format(message.from_user.first_name) await message.answer(f"{hello_message}\n{welcome_message}") ``` -------------------------------- ### Manage Asynchronous Background Tasks in Mubble Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/loop-wrapper.md This example shows how to manage background tasks within a Mubble application, ensuring they are properly started and gracefully cancelled during shutdown. It uses a global list to track tasks and integrates their cancellation into the `on_shutdown` callback. ```python background_tasks = [] async def start_background_tasks(): # Create and store background tasks task1 = asyncio.create_task(background_task1()) task2 = asyncio.create_task(background_task2()) background_tasks.extend([task1, task2]) async def on_shutdown(): # Cancel background tasks for task in background_tasks: task.cancel() # Wait for tasks to be cancelled await asyncio.gather(*background_tasks, return_exceptions=True) wrapper = LoopWrapper(on_shutdown=on_shutdown) wrapper.run(bot.start_polling(), start_background_tasks()) ``` -------------------------------- ### Implement i18n Middleware for Language Detection and Context Setup Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/i18n.md Illustrates how to create a Mubble middleware to detect a user's preferred language (from Telegram settings or default to English), simplify language codes, and store both the detected language and the `SimpleTranslator` instance in the bot's context. It also shows how a message handler can retrieve and use these context variables to send localized responses. ```python from mubble import Update, Context from mubble.tools.i18n import SimpleTranslator # Create a translator translator = SimpleTranslator( { "en": { "welcome": "Welcome to the bot!", "hello": "Hello, {}!", "help": "This bot helps you do amazing things." }, "ru": { "welcome": "Добро пожаловать в бота!", "hello": "Привет, {}!", "help": "Этот бот помогает делать удивительные вещи." } }, default_locale="en" ) @bot.dispatch.middleware async def i18n_middleware(update: Update, next_handler: Callable, ctx: Context) -> Any: # Determine user's language user_language = "en" # Default language if update.message and update.message.from_user.language_code: # Get language from Telegram user settings user_language = update.message.from_user.language_code # Simplify language code (e.g., "en-US" -> "en") if "-" in user_language: user_language = user_language.split("-")[0] # Check if we support this language, otherwise fallback to default if not translator.has("welcome", user_language): user_language = "en" # Set the language in context ctx.set("language", user_language) # Set the translator in context ctx.set("translator", translator) # Call the next handler return await next_handler(update) # Use the translator in a handler @bot.on.message(Text("/start")) async def start_handler(message: Message, ctx: Context) -> None: # Get the translator and language from context translator = ctx.get("translator") language = ctx.get("language") # Translate the messages welcome_message = translator.get("welcome", language) hello_message = translator.get("hello", language).format(message.from_user.first_name) await message.answer(f"{hello_message}\n{welcome_message}") ``` -------------------------------- ### Serve Mubble Documentation Locally Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/contributing.md Commands to navigate to the `docs` directory and serve the Mubble documentation locally. This allows you to preview documentation changes in real-time in your web browser. ```bash cd docs mkdocs serve ``` -------------------------------- ### Integrating Mubble LoopWrapper with FastAPI for Webhooks Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/loop-wrapper.md This example demonstrates how to integrate Mubble's LoopWrapper with a FastAPI web application for handling Telegram bot webhooks. It includes setting up the FastAPI app, defining a webhook endpoint with secret token verification, configuring startup/shutdown events for webhook management, and running the application using a custom Uvicorn server class that leverages LoopWrapper. ```python import asyncio import uvicorn from fastapi import FastAPI, Request, Response from mubble import API, Mubble, Token, WebhookConfig from mubble.server import process_update from mubble.loop import LoopWrapper # Create API client and bot api = API(token=Token("YOUR_BOT_TOKEN")) bot = Mubble(api) # Register your handlers @bot.on.message() async def echo_handler(message): await message.answer(message.text) # Configure webhook webhook_config = WebhookConfig( url="https://your-domain.com/webhook", secret_token="your-secret-token" ) # Create FastAPI application app = FastAPI() # Add webhook endpoint @app.post("/webhook") async def webhook(request: Request): # Verify secret token if request.headers.get("X-Telegram-Bot-Api-Secret-Token") != webhook_config.secret_token: return Response(status_code=403) # Process update update_data = await request.json() await process_update(bot, update_data) return Response(status_code=200) # Add startup event @app.on_event("startup") async def on_startup(): # Set webhook await api.set_webhook(webhook_config) print("Webhook set") # Add shutdown event @app.on_event("shutdown") async def on_shutdown(): # Delete webhook await api.delete_webhook() print("Webhook deleted") # Create a custom server class that uses the loop wrapper class LoopWrapperUvicornServer(uvicorn.Server): def run(self, sockets=None): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) wrapper = LoopWrapper(loop=loop) wrapper.run(self.serve(sockets=sockets)) # Run the application if __name__ == "__main__": config = uvicorn.Config(app, host="0.0.0.0", port=8443) server = LoopWrapperUvicornServer(config=config) server.run() ``` -------------------------------- ### Build Mubble Documentation Locally Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/contributing.md Commands to navigate to the `docs` directory and build the Mubble documentation using mkdocs. This generates static HTML files that can be viewed in a web browser. ```bash cd docs mkdocs build ``` -------------------------------- ### Thread-Safe Operations with Mubble Global Context Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/global-context.md Confirms that the global context is thread-safe and provides an example of incrementing a counter safely in a multi-threaded environment. ```python import threading from mubble import Message, Context @bot.on.message() async def handler(message: Message, ctx: Context) -> None: global_ctx = ctx.global_ctx # Thread-safe operations counter = global_ctx.get("counter", 0) counter += 1 global_ctx.set("counter", counter) await message.answer(f"Counter: {counter}") ``` -------------------------------- ### Basic Handlers: Inline Query Handler Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/handlers.md Inline query handlers process queries made by users in the chat input field. This example shows how to respond with an `InlineQueryResultArticle`. ```python from mubble import InlineQuery from mubble.types import InlineQueryResultArticle, InputTextMessageContent @bot.on.inline_query() async def inline_handler(inline_query: InlineQuery) -> None: await inline_query.answer( results=[ InlineQueryResultArticle( id="1", title="Example", input_message_content=InputTextMessageContent( message_text="This is an example" ) ) ] ) ``` -------------------------------- ### Registering a Message Handler for '/start' Command Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/dispatching.md Shows how to register a handler specifically for incoming messages that match the text '/start'. This is a common pattern for command-based interactions. ```python @bot.on.message(Text("/start")) async def start_handler(message: Message) -> None: await message.answer("Hello!") ``` -------------------------------- ### Clear Pending Updates on Webhook Setup (Python) Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/webhooks.md Shows how to configure a Telegram webhook to drop any pending updates when it's set up, which is useful for preventing old updates from being processed after a bot restart. ```Python webhook_config = WebhookConfig( url="https://your-domain.com/webhook", drop_pending_updates=True ) ``` -------------------------------- ### Initialize Mubble API Client with Token Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/basic-concepts.md This snippet demonstrates how to initialize the Mubble API client. It shows both the default `AiohttpClient` usage and how to explicitly specify an alternative client like `AiosonicClient` for potentially better performance. The client requires a `Token` object initialized with your bot's API token. ```python from mubble import API, Token # Create an API instance with the default client api = API(token=Token("YOUR_BOT_TOKEN")) # Or specify a client explicitly from mubble.client import AiosonicClient api = API(token=Token("YOUR_BOT_TOKEN"), client=AiosonicClient()) ``` -------------------------------- ### Set Up Python Virtual Environment for Mubble Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/contributing.md Steps to create a Python virtual environment named 'venv' and activate it. This isolates project dependencies, ensuring they don't conflict with other Python projects on your system. Includes instructions for both Unix-like and Windows systems. ```bash python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate ``` -------------------------------- ### Accessing Global Context from a Background Thread Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/global-context.md Demonstrates how to access and modify the global context from a separate background thread, ensuring thread-safe operations. The thread is started as a daemon to run continuously. ```python def background_task(global_ctx): while True: # Thread-safe operations counter = global_ctx.get("counter", 0) print(f"Current counter: {counter}") time.sleep(60) # Start the background thread threading.Thread( target=background_task, args=(bot.global_ctx,), daemon=True ).start() ``` -------------------------------- ### Creating an API Client in Mubble (Python) Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/api-client.md This snippet demonstrates how to initialize the Mubble API client. It shows two ways to provide the bot token: directly as a string or by loading it from an environment variable named 'TOKEN'. ```python from mubble import API, Token # Create an API instance with a token string api = API(token=Token("123456789:ABCDefGhIJKlmnOPQRstUVwxyz")) # Or load the token from an environment variable api = API(token=Token.from_env()) # Uses the TOKEN environment variable ``` -------------------------------- ### Run Mubble Bot in Blocking Mode Source: https://github.com/vladislavkovalskyi/mubble/blob/master/docs/bot-structure.md Explains how to start the Mubble bot in a blocking manner using the `run_forever()` method, which keeps the bot running in the current thread until it's interrupted. ```python bot.run_forever() ```