### 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.