💻 Initial structure and a simple handler
Introduction
The structure of the module was described in the previous section. Now let's move on to its creation!
INFO
First read the PyroTGFork, this only describes the specifics of writing for PBModular
Step 1: Create module directory and configuration
Create a directory for your module (e.g., my_module) inside the main modules/ folder. Inside my_module, create:
- init.py: This file makes Python treat the directory as a package. It should import your main module class (see Step 2).
- config.yaml: This file defines metadata and settings for your module. It's preferred over the older
info.yaml
.
Example config.yaml:
# config.yaml
info:
name: MyModule # User-friendly name (single word recommended)
author: Your Name
version: 0.1.0
description: A brief description of what the module does.
src_url: https://github.com/your/repo # Optional: Link to source code
python: 3.11 # Optional: Recommended Python version (warns if different)
auto_load: true # Optional: Whether to load this module automatically (default: true)
# Optional: List of permissions needed (see Module Permissions)
permissions:
- use_db # Example: requests database access
# Optional: Custom configuration specific to your module
config:
key: "YOUR_DEFAULT_KEY"
feature_enabled: true
WARNING
Fallback: If config.yaml
is missing, the loader will look for info.yaml
(containing only info and permissions keys) for backward compatibility, but using config.yaml
is strongly recommended.
Step 2: Create the main module class
Create a Python file (e.g., main.py) in your module directory and define your main class inheriting from BaseModule
.
# main.py
from base.module import BaseModule, command
from pyrogram import Client
from pyrogram.types import Message
class MyModule(BaseModule):
# Module logic and handlers go here
pass
Now, make sure __init__.py
imports this class:
# __init__.py
from .main import MyModule
Step 3: Writing a command handler
Define an asynchronous method within your MyModule
class. The method should accept self
, and optionally client
(the Pyrogram Client instance) and message
(or callback_query
, depending on the handler type).
# main.py (inside MyModule class)
async def on_hello(self, client: Client, message: Message):
"""Replies with a friendly greeting.""" # Docstring used for auto-help
await message.reply("Hello World!")
Step 4: Registering the handler
Use decorators from base.module
to register your method as a handler.
@command(names, filters=None, fsm_state=None):
Registers a command handler.names:
A string or list of strings for the command name(s) (e.g., "hello" or ["hi", "hello"]).filters:
Optional Pyrogram filter (pyrogram.filters.Filter
) to add more specific conditions. Highly recommended for commands beyond simple triggers (e.g.,filters.private
orfilters.regex
).fsm_state:
Optional State or list of States for FSM control (see FSM documentation).
@callback_query(filters=None, fsm_state=None):
Registers a callback query handler (for inline buttons).@message(filters=None, fsm_state=None):
Registers a general message handler. Using filters here is crucial to avoid conflicts and performance issues.
# main.py (inside MyModule class)
from base.module import command
from pyrogram import filters
@command("hello", filters=filters.private) # Only works in private chat
async def on_hello(self, client: Client, message: Message):
"""Replies with a friendly greeting."""
await message.reply("Hello World!")
@command("start", filters.regex(r"/start payload_\w+")) # Example with regex
async def on_start_with_payload(self, client: Client, message: Message):
"""Handles start command with specific payload"""
payload = message.text.split('_', 1)[1]
await message.reply(f"Received start with payload: {payload}")
INFO
The framework automatically handles command registration (command_registry) and permission checks (@allowed_for decorator and /allow_cmd command).