### Handle Delimited Text with SurroundedArg, StartsWithArg, UntilArg Source: https://context7.com/sophiebot/ass/llms.txt These arguments parse text based on delimiters. SurroundedArg captures text between a prefix and postfix, StartsWithArg captures text starting with a prefix (stripping it), and UntilArg captures text up to a postfix. ```python from ass_tg.types import SurroundedArg, StartsWithArg, UntilArg, TextArg, WordArg # Text surrounded by quotes @flags.args( command=WordArg("Command"), message=SurroundedArg(TextArg("Message"), prefix='"', postfix='"') ) async def say_handler(msg: Message, command: str, message: str): # Input: /say announce "Hello everyone!" # Result: command = "announce", message = "Hello everyone!" await msg.reply(f"Saying: {message}") # Text starting with a prefix @flags.args(tag=StartsWithArg("#", TextArg("Tag name"))) async def hashtag_handler(msg: Message, tag: str): # Input: /hashtag #trending # Result: tag = "trending" (# is stripped) await msg.reply(f"Tagged as: {tag}") # Text until a delimiter @flags.args( title=UntilArg(":", TextArg("Title")), description=TextArg("Description") ) async def article_handler(msg: Message, title: str, description: str): # Input: /article Breaking News: Something happened today # Result: title = "Breaking News", description = "Something happened today" await msg.reply(f"Title: {title}\nDescription: {description}") ``` -------------------------------- ### Modify parsed argument content with ASS custom argument Source: https://gitlab.com/sophiebot/ass/-/blob/main/README.md This Python example extends 'TextArg' to create 'ShortTextArg' with a modified 'parse' method. If the parsed text exceeds 10 characters, it's truncated and appended with '...', demonstrating how to alter the content of parsed arguments. ```python class ShortTextArg(TextArg): async def parse(self, text: str, offset: int, entities: ArgEntities) -> tuple[int, str]: length, text = super().parse(text, offset, entities) if len(text) > 10: text = text[:10] + "..." return length, text ``` -------------------------------- ### Define Optional User Argument at Runtime (Python) Source: https://gitlab.com/sophiebot/ass/-/blob/main/README.md This Python function, `optional_user`, demonstrates how to dynamically define argument specifications at runtime. It checks if a message is a reply; if so, it returns an empty dictionary, indicating no arguments should be parsed. Otherwise, it defines a 'user' argument. ```python async def optional_user(message: Message | None, _data: dict): # message can be None for gathering arguments spec on startup if message and message.reply_to_message: # Return a blank dictionary # Means, the ASS will not parse an arguments in this case (when the message has a replied message) return {} return { 'user': UserArg("User") } ``` -------------------------------- ### Define a tban command handler with argument parsing using ASS Source: https://gitlab.com/sophiebot/ass/-/blob/main/README.md This Python snippet demonstrates how to create a message handler for a 'tban' command using the ASS library. It defines expected arguments like user, time, and an optional description, showcasing ASS's type checking and argument parsing capabilities. ```python from ass_tg.types import UserArg, ActionTimeArg, TextArg, OptionalArg from stfu_tg import Section, KeyValue @dp.message(Command('tban')) # Set a command filter @flags.args( user=UserArg("User"), time=ActionTimeArg("Time to ban"), description=OptionalArg(TextArg("Reason text")) ) async def tban_user_handler( msg: Message, user: str, time: timedelta, description: str | None ): # Here we used STFU's formatting, but you can use variables as you wish! await msg.reply(str(Section( KeyValue("User", user), KeyValue("On", time), KeyValue("Description", description or "No description"), title="Ban" ))) ``` -------------------------------- ### Match Exact String Value with EqualsArg Source: https://context7.com/sophiebot/ass/llms.txt Demonstrates how to use EqualsArg to match exact string values for command sub-actions. This is useful for defining specific commands within a larger command structure, such as 'add', 'remove', or 'list'. It integrates with OrArg, AndArg, and TextArg for complex command parsing. ```python from ass_tg.types import EqualsArg, OrArg, TextArg, AndArg @flags.args( action=OrArg( AndArg(cmd=EqualsArg("add"), value=TextArg("Item to add")), AndArg(cmd=EqualsArg("remove"), value=TextArg("Item to remove")), AndArg(cmd=EqualsArg("list")) ) ) async def items_handler(msg: Message, action: dict): # Input: /items add New Item -> action with cmd="add", value="New Item" # Input: /items remove Old Item -> action with cmd="remove", value="Old Item" # Input: /items list -> action with cmd="list" cmd = action.get('cmd') value = action.get('value') await msg.reply(f"Action: {cmd}, Value: {value}") ``` -------------------------------- ### Handle Dynamic User Arguments in Command Handler (Python) Source: https://gitlab.com/sophiebot/ass/-/blob/main/README.md This Python code snippet shows a command handler (`id_cmd`) that utilizes runtime-defined arguments. It retrieves the 'user' argument, which might be dynamically provided, and constructs a document containing user IDs from the message, replied message, and the dynamically resolved user. ```python @router.message(CMDFilter('id'), flags={'args': optional_user}) async def id_cmd(message: Message, user: Optional[Example]) async def handle(self) -> Any: user: Optional[ChatModel] = self.data.get('user', None) doc = Doc() if self.event.from_user: user_id = self.event.from_user.id doc += Template(_("Your ID: {id}"), id=Code(user_id)) if self.event.reply_to_message and self.event.reply_to_message.from_user: user_id = self.event.reply_to_message.from_user.id doc += Template(_("Replied user ID: {id}"), id=Code(user_id)) if user: doc += Template( _("{user}'s ID: {id}"), user=UserLink(user_id=user.chat_id, name=user.first_name_or_title), id=Code(user.chat_id), ) return await self.event.reply(str(doc)) ``` -------------------------------- ### Integrate ArgsMiddleware with Aiogram 3.x Bots Source: https://context7.com/sophiebot/ass/llms.txt The ArgsMiddleware class integrates ASS with Aiogram, intercepting messages, parsing arguments based on handler flags, and injecting them into handler parameters. It also manages error presentation to users, with options for custom error messages and inline keyboards. ```python from aiogram import Bot, Dispatcher, flags from aiogram.client.default import DefaultBotProperties from aiogram.filters import Command from aiogram.types import Message, InlineKeyboardButton from ass_tg.middleware import ArgsMiddleware from ass_tg.types import UserArg, ActionTimeArg, TextArg, OptionalArg # Initialize bot and dispatcher bot = Bot(token="YOUR_BOT_TOKEN", default=DefaultBotProperties(parse_mode="html")) dp = Dispatcher() # Add middleware with optional customization dp.message.middleware(ArgsMiddleware( # Optional: Add custom content after error messages error_additional_items=("Contact @support for help",), # Optional: Add inline keyboard to error messages error_markup_buttons=[[InlineKeyboardButton(text="Help", url="https://example.com/help")]] )) @dp.message(Command('ban')) @flags.args( user=UserArg("User to ban"), duration=ActionTimeArg("Ban duration"), reason=OptionalArg(TextArg("Reason")) ) async def ban_handler(msg: Message, user: str, duration, reason: str | None): await msg.reply(f"Banned {user} for {duration}. Reason: {reason or 'Not specified'}") # Run the bot dp.run_polling(bot) ``` -------------------------------- ### Define Arguments Dynamically Based on Message Context Source: https://context7.com/sophiebot/ass/llms.txt Shows how to define argument specifications dynamically at runtime using a function passed to `flags.args`. This allows the argument parsing logic to adapt based on message properties, such as whether the message is a reply. It demonstrates conditional argument requirements. ```python from typing import Optional from aiogram import Router from aiogram.types import Message from ass_tg.types import UserArg, TextArg router = Router() async def conditional_user_arg(message: Message | None, _data: dict): """Return different argument specs based on whether message is a reply.""" # message can be None when gathering specs on startup if message and message.reply_to_message: # If replying to a message, don't require user argument return { 'reason': TextArg("Reason") } # Otherwise require user to be specified return { 'user': UserArg("User"), 'reason': TextArg("Reason") } @router.message(Command('warn'), flags={'args': conditional_user_arg}) async def warn_handler(message: Message, user: Optional[str] = None, reason: str = ""): if message.reply_to_message and message.reply_to_message.from_user: target = message.reply_to_message.from_user.id else: target = user await message.reply(f"Warned {target}: {reason}") ``` -------------------------------- ### Create Custom Argument Types by Extending Base Classes Source: https://context7.com/sophiebot/ass/llms.txt Illustrates how to create custom argument types by extending existing ASS argument classes like TextArg and OneWordArgFabricABC. This allows for custom validation (e.g., length constraints) or transformation (e.g., text truncation) of parsed arguments. It demonstrates overriding `check()` for validation and `parse()` for transformation. ```python from ass_tg.types import TextArg, IntArg from ass_tg.types.base_abc import OneWordArgFabricABC from ass_tg.entities import ArgEntities from ass_tg.exceptions import ArgStrictError from ass_tg.i18n import lazy_gettext as l_ # Custom validation: limit text length class ShortTextArg(TextArg): def check(self, text: str, entities: ArgEntities) -> bool: if len(text) < 3: raise ArgStrictError("Text is too short (minimum 3 characters)") if len(text) > 100: raise ArgStrictError("Text is too long (maximum 100 characters)") return True # Custom transformation: truncate long text class TruncatedTextArg(TextArg): def __init__(self, description, max_length: int = 50): super().__init__(description) self.max_length = max_length async def parse(self, text: str, offset: int, entities: ArgEntities) -> tuple[int, str]: length, text = await super().parse(text, offset, entities) if len(text) > self.max_length: text = text[:self.max_length] + "..." return length, text # Custom single-word argument: positive integer class PositiveIntArg(OneWordArgFabricABC): def needed_type(self): return l_("Positive integer"), l_("Positive integers") async def check_type(self, text: str) -> bool: return text.isdigit() and int(text) > 0 async def value(self, text: str) -> int: return int(text) # Usage @flags.args( name=ShortTextArg("Name (3-100 chars)"), description=TruncatedTextArg("Description", max_length=200), count=PositiveIntArg("Positive count") ) async def custom_handler(msg: Message, name: str, description: str, count: int): await msg.reply(f"Name: {name}\nDescription: {description}\nCount: {count}") ``` -------------------------------- ### Match One Value from a List with OneOf Source: https://context7.com/sophiebot/ass/llms.txt OneOf matches a single input value against a predefined list of allowed string values. It's useful for enforcing specific options or states. ```python from ass_tg.types import OneOf, TextArg @flags.args( priority=OneOf(["low", "medium", "high", "critical"], "Priority level"), description=TextArg("Task description") ) async def task_handler(msg: Message, priority: str, description: str): # Input: /task high Fix the bug # Result: priority = "high", description = "Fix the bug" # Input: /task urgent Something -> Error: must be one of 'low', 'medium', 'high', 'critical' await msg.reply(f"[{priority.upper()}] {description}") ``` -------------------------------- ### Parse Lists with ListArg and DividedArg Source: https://context7.com/sophiebot/ass/llms.txt ListArg parses a list of items with configurable prefix, postfix, and separator, while DividedArg is a simplified version using only a separator. Both are useful for handling multiple arguments of the same type. ```python from ass_tg.types import ListArg, DividedArg, WordArg, IntArg, UserArg # ListArg with parentheses and comma separator (default) @flags.args(tags=ListArg(WordArg("Tag"), separator=',', prefix='(', postfix=')')) async def tag_handler(msg: Message, tags: list): # Input: /tag (python, telegram, bot) # Result: tags = ["python", "telegram", "bot"] await msg.reply(f"Tags: {', '.join(tags)}") # DividedArg with pipe separator (no prefix/postfix) @flags.args(ids=DividedArg(IntArg("ID"), separator='|')) async def multi_handler(msg: Message, ids: list): # Input: /process 1|2|3|4|5 # Result: ids = [1, 2, 3, 4, 5] await msg.reply(f"Processing IDs: {ids}") # List of users @flags.args(users=ListArg(UserArg("User"))) async def notify_handler(msg: Message, users: list): # Input: /notify (@alice, @bob, 123456) await msg.reply(f"Notifying {len(users)} users") ``` -------------------------------- ### Parse Key-Value Pairs with KeyValueArg and KeyValuesArg Source: https://context7.com/sophiebot/ass/llms.txt KeyValueArg parses a single key-value pair with configurable syntax. KeyValuesArg parses multiple optional key-value pairs, often used for options or settings. ```python from ass_tg.types import KeyValueArg, KeyValuesArg, TextArg, IntArg, BooleanArg # Single key-value argument @flags.args( title=TextArg("Title"), options=KeyValuesArg( KeyValueArg("color", TextArg("Color value")), KeyValueArg("size", IntArg("Size value")), KeyValueArg("bold", BooleanArg("Bold flag")) ) ) async def create_handler(msg: Message, title: str, options: dict): # Input: /create My Title ^color=red ^size=14 ^bold # Result: title = "My Title", options = {"color": "red", "size": 14, "bold": True} # ^key=value syntax for key-values # ^key without value uses default (True for BooleanArg) await msg.reply(f"Creating '{title}' with options: {options}") ``` -------------------------------- ### Create a custom argument validator with ASS Source: https://gitlab.com/sophiebot/ass/-/blob/main/README.md This Python code defines a custom argument type 'ShortTextArg' that inherits from 'TextArg'. It includes a 'check' method to validate the length of the input text, raising an 'ArgStrictError' if the text is too short or too long, demonstrating custom validation logic. ```python class ShortTextArg(TextArg): def check(self, text: str, entities: ArgEntities) -> bool: if len(text) < 3: # We use ArgStrictError, because it doesn't get ignored by the OptionalArg or OrArg and would cause an argument typing error message raise ArgStrictError("Text too short") elif len(text) > 10: raise ArgStrictError("Text too long") return True ``` -------------------------------- ### Identify Telegram Users with UserArg, UsernameArg, UserIDArg, UserMentionArg Source: https://context7.com/sophiebot/ass/llms.txt These argument types facilitate identifying Telegram users in various formats. `UserArg` is a versatile type accepting numeric IDs, @usernames, or text mentions. `UsernameArg` strictly parses @mentions, `UserIDArg` only accepts numeric IDs, and `UserMentionArg` specifically handles mention links. ```python from ass_tg.types import UserArg, UsernameArg, UserIDArg, UserMentionArg # UserArg accepts any user identifier @flags.args(target=UserArg("Target user")) async def info_handler(msg: Message, target): # Input: /info @username -> target = "username" (str) # Input: /info 123456789 -> target = 123456789 (int) # Input: /info [mention link] -> target = User object await msg.reply(f"Looking up: {target}") # UsernameArg only accepts @mentions @flags.args(username=UsernameArg("Username")) async def lookup_handler(msg: Message, username: str): # Input: /lookup @johndoe -> username = "johndoe" await msg.reply(f"Found user: {username}") # UserIDArg only accepts numeric IDs @flags.args(user_id=UserIDArg("User ID")) async def ban_id_handler(msg: Message, user_id: int): # Input: /banid 123456789 -> user_id = 123456789 await msg.reply(f"Banned user ID: {user_id}") ``` -------------------------------- ### Handle Optional Arguments with OptionalArg Source: https://context7.com/sophiebot/ass/llms.txt OptionalArg wraps another argument type, making it optional. If the argument is not provided or fails to parse, it returns `None`. This is useful for arguments that are not always required, such as search limits or filters. ```python from ass_tg.types import OptionalArg, TextArg, IntArg, UserArg @flags.args( query=TextArg("Search query"), limit=OptionalArg(IntArg("Result limit")), author=OptionalArg(UserArg("Filter by author")) ) async def search_handler(msg: Message, query: str, limit: int | None, author: str | None): # Input: /search python # Result: query="python", limit=None, author=None # Input: /search python 10 # Result: query="python", limit=10, author=None # Input: /search python 5 @johndoe # Result: query="python", limit=5, author="johndoe" results = f"Searching '{query}'" if limit: results += f" (limit: {limit})" if author: results += f" by {author}" await msg.reply(results) ``` -------------------------------- ### Parse Time Durations with ActionTimeArg Source: https://context7.com/sophiebot/ass/llms.txt ActionTimeArg parses human-readable time duration strings like '2d3h' (2 days, 3 hours). It supports years (y), weeks (w), days (d), hours (h), and minutes (m), returning a `datetime.timedelta` object. This is useful for setting temporary actions like mutes. ```python from datetime import timedelta from ass_tg.types import ActionTimeArg, UserArg, OptionalArg, TextArg @flags.args( user=UserArg("User to mute"), duration=ActionTimeArg("Mute duration"), reason=OptionalArg(TextArg("Reason")) ) async def mute_handler(msg: Message, user: str, duration: timedelta, reason: str | None): # Input: /mute @username 2d3h Being rude # Result: user = "username", duration = timedelta(days=2, hours=3), reason = "Being rude" # Input: /mute 123456789 1w # Result: user = 123456789, duration = timedelta(weeks=1), reason = None hours = duration.total_seconds() / 3600 await msg.reply(f"Muted {user} for {hours:.1f} hours. Reason: {reason or 'Not specified'}") ``` -------------------------------- ### Parse One of Multiple Types with OrArg Source: https://context7.com/sophiebot/ass/llms.txt OrArg allows an argument to be parsed as one of several specified types. It attempts to parse the input using each provided type in order until one succeeds. This is useful when a single input could represent different kinds of data, like an ID or a name. ```python from ass_tg.types import OrArg, IntArg, WordArg, TextArg # Accept either a number or a word @flags.args( identifier=OrArg(IntArg("ID"), WordArg("Name")) ) async def get_handler(msg: Message, identifier): # Input: /get 12345 -> identifier = 12345 (int) # Input: /get admin -> identifier = "admin" (str) await msg.reply(f"Fetching: {identifier} (type: {type(identifier).__name__})") ``` -------------------------------- ### Parse Arguments in Reverse Order with ReverseArg Source: https://context7.com/sophiebot/ass/llms.txt ReverseArg parses arguments from right to left instead of the default left to right. This is useful when a variable-length argument needs to appear before a fixed-format argument in the input string. ```python from ass_tg.types import ReverseArg, TextArg, SurroundedArg @flags.args( args=ReverseArg( description=TextArg("Description"), # Parsed last (consumes remaining) note=SurroundedArg(TextArg("Note"), prefix='"', postfix='"') # Parsed first from right ) ) async def note_handler(msg: Message, args: dict): # Input: /note This is a long description "Important note" # Result: args = {"description": "This is a long description", "note": "Important note"} # ReverseArg parses "Important note" first (from right), then description gets the rest await msg.reply(f"Description: {args['description'].get_value()}\nNote: {args['note'].get_value()}") ``` -------------------------------- ### Parse Boolean Values with BooleanArg Source: https://context7.com/sophiebot/ass/llms.txt The BooleanArg type parses various text representations of boolean values, such as 'true'/'false', 'yes'/'no', 'on'/'off', '1'/'0', '+/-', 'enable'/'disable', and emoticons. It simplifies handling user input for toggling settings. ```python from ass_tg.types import BooleanArg, WordArg @flags.args( setting=WordArg("Setting name"), value=BooleanArg("Enable/disable") ) async def toggle_handler(msg: Message, setting: str, value: bool): # Input: /toggle notifications yes -> value = True # Input: /toggle darkmode off -> value = False # Input: /toggle sounds :) -> value = True # Input: /toggle ads disable -> value = False status = "enabled" if value else "disabled" await msg.reply(f"{setting} is now {status}") ``` -------------------------------- ### Parse a Single Word with WordArg Source: https://context7.com/sophiebot/ass/llms.txt The WordArg type parses a single word (a string without spaces) from the input. This is useful for parsing command names or specific keywords. ```python from ass_tg.types import WordArg, TextArg @flags.args( command=WordArg("Command name"), args=OptionalArg(TextArg("Command arguments")) ) async def execute_handler(msg: Message, command: str, args: str | None): # Input: /exec start --verbose # Result: command = "start", args = "--verbose" await msg.reply(f"Executing '{command}' with args: {args}") ``` -------------------------------- ### Parse Integers with IntArg Source: https://context7.com/sophiebot/ass/llms.txt The IntArg type parses an integer number from the input. It supports both positive and negative integers. It can be used with OptionalArg to handle cases where the integer might be missing. ```python from ass_tg.types import IntArg, OptionalArg @flags.args( count=IntArg("Number of items"), offset=OptionalArg(IntArg("Starting offset")) ) async def list_handler(msg: Message, count: int, offset: int | None): # Input: /list 10 -5 # Result: count = 10, offset = -5 await msg.reply(f"Listing {count} items from offset {offset or 0}") ``` -------------------------------- ### Combine Multiple Arguments with AndArg Source: https://context7.com/sophiebot/ass/llms.txt AndArg sequentially parses multiple named arguments from left to right. This is the default behavior when using the `@flags.args()` decorator with keyword arguments. It's used to define a set of arguments that must all be present and parsed successfully. ```python from ass_tg.types import AndArg, UserArg, ActionTimeArg, TextArg, OptionalArg # Explicit AndArg usage (equivalent to @flags.args kwargs) base_arg = AndArg( user=UserArg("User"), duration=ActionTimeArg("Duration"), reason=OptionalArg(TextArg("Reason")) ) # The @flags.args decorator internally creates an AndArg @flags.args( user=UserArg("User"), duration=ActionTimeArg("Duration"), reason=OptionalArg(TextArg("Reason")) ) async def restrict_handler(msg: Message, user, duration, reason): # Input: /restrict @user 1d Spam await msg.reply(f"Restricted {user} for {duration}: {reason}") ``` -------------------------------- ### Parse Arbitrary Text with TextArg Source: https://context7.com/sophiebot/ass/llms.txt The TextArg type parses arbitrary text from a Telegram message. By default, it consumes all remaining text. The `parse_entities` option can be enabled to preserve HTML entities from Telegram formatting. ```python from ass_tg.types import TextArg, OptionalArg # Basic text argument - consumes all remaining text @flags.args(message=TextArg("Message content")) async def echo_handler(msg: Message, message: str): # Input: /echo Hello world! # Result: message = "Hello world!" await msg.reply(f"You said: {message}") # With HTML entity parsing enabled @flags.args(content=TextArg("Content", parse_entities=True)) async def format_handler(msg: Message, content: str): # Input: /format Hello world! # Result: content = "Hello world!" (preserves formatting) await msg.reply(content) # Optional text @flags.args(note=OptionalArg(TextArg("Optional note"))) async def note_handler(msg: Message, note: str | None): # Input: /note -> note = None # Input: /note Remember this -> note = "Remember this" await msg.reply(note or "No note provided") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.