mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Refactored and added docs
This commit is contained in:
parent
28e4c15d75
commit
bfa69f6deb
5 changed files with 527 additions and 126 deletions
|
|
@ -1,28 +1,19 @@
|
|||
"""
|
||||
Proof of Concept text decoration utility for aiogram 3.0
|
||||
|
||||
This part of the code is licensed under MIT as the same as aiogarm
|
||||
|
||||
Soon it will be moved into main package
|
||||
|
||||
Usage:
|
||||
|
||||
>>> formatting = Text("Hello, ", Bold("World"), "!")
|
||||
>>> await bot.send_message(chat_id=..., **formatting.to_kwargs())
|
||||
"""
|
||||
import textwrap
|
||||
from typing import (
|
||||
Any,
|
||||
ClassVar,
|
||||
Dict,
|
||||
Generator,
|
||||
Iterable,
|
||||
Iterator,
|
||||
List,
|
||||
Optional,
|
||||
Tuple,
|
||||
TypeVar,
|
||||
Union,
|
||||
Type,
|
||||
)
|
||||
|
||||
from typing_extensions import Self
|
||||
|
||||
from aiogram.enums import MessageEntityType
|
||||
from aiogram.types import MessageEntity, User
|
||||
from aiogram.utils.text_decorations import (
|
||||
|
|
@ -32,16 +23,18 @@ from aiogram.utils.text_decorations import (
|
|||
remove_surrogates,
|
||||
)
|
||||
|
||||
NodeType = Union[str, "Node"]
|
||||
|
||||
NodeT = TypeVar("NodeT", bound=NodeType)
|
||||
NodeType = Any
|
||||
|
||||
|
||||
def sizeof(value: str) -> int:
|
||||
return len(value.encode("utf-16-le")) // 2
|
||||
|
||||
|
||||
class Node:
|
||||
class Text(Iterable[NodeType]):
|
||||
"""
|
||||
Simple text element
|
||||
"""
|
||||
|
||||
type: ClassVar[Optional[str]] = None
|
||||
|
||||
__slots__ = ("_body", "_params")
|
||||
|
|
@ -51,12 +44,12 @@ class Node:
|
|||
*body: NodeType,
|
||||
**params: Any,
|
||||
) -> None:
|
||||
self._body = body
|
||||
self._params = params
|
||||
self._body: Tuple[NodeType, ...] = body
|
||||
self._params: Dict[str, Any] = params
|
||||
|
||||
@classmethod
|
||||
def from_entities(cls, text: str, entities: List[MessageEntity]) -> "Node":
|
||||
return Node(
|
||||
def from_entities(cls, text: str, entities: List[MessageEntity]) -> "Text":
|
||||
return Text(
|
||||
*_unparse_entities(
|
||||
text=add_surrogates(text),
|
||||
entities=sorted(entities, key=lambda item: item.offset) if entities else [],
|
||||
|
|
@ -70,17 +63,26 @@ class Node:
|
|||
_sort: bool = True,
|
||||
_collect_entities: bool = True,
|
||||
) -> Tuple[str, List[MessageEntity]]:
|
||||
"""
|
||||
Render elements tree as text with entities list
|
||||
|
||||
:return:
|
||||
"""
|
||||
|
||||
text = ""
|
||||
entities = []
|
||||
offset = _offset
|
||||
|
||||
for node in self._body:
|
||||
if isinstance(node, str):
|
||||
if not isinstance(node, Text):
|
||||
node = str(node)
|
||||
text += node
|
||||
offset += sizeof(node)
|
||||
else:
|
||||
node_text, node_entities = node.render(
|
||||
_offset=offset, _sort=False, _collect_entities=_collect_entities
|
||||
_offset=offset,
|
||||
_sort=False,
|
||||
_collect_entities=_collect_entities,
|
||||
)
|
||||
text += node_text
|
||||
offset += sizeof(node_text)
|
||||
|
|
@ -98,16 +100,30 @@ class Node:
|
|||
def _render_entity(self, *, offset: int, length: int) -> MessageEntity:
|
||||
return MessageEntity(type=self.type, offset=offset, length=length, **self._params)
|
||||
|
||||
def to_kwargs(
|
||||
def as_kwargs(
|
||||
self,
|
||||
*,
|
||||
text_key: str = "text",
|
||||
entities_key: str = "entities",
|
||||
replace_parse_mode: bool = False,
|
||||
replace_parse_mode: bool = True,
|
||||
parse_mode_key: str = "parse_mode",
|
||||
) -> Dict[str, Union[str, List[MessageEntity]]]:
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Render elements tree as keyword arguments for usage in the API call, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
entities = Text(...)
|
||||
await message.answer(**entities.as_kwargs())
|
||||
|
||||
:param text_key:
|
||||
:param entities_key:
|
||||
:param replace_parse_mode:
|
||||
:param parse_mode_key:
|
||||
:return:
|
||||
"""
|
||||
text_value, entities_value = self.render()
|
||||
result = {
|
||||
result: Dict[str, Any] = {
|
||||
text_key: text_value,
|
||||
entities_key: entities_value,
|
||||
}
|
||||
|
|
@ -115,17 +131,27 @@ class Node:
|
|||
result[parse_mode_key] = None
|
||||
return result
|
||||
|
||||
def to_html(self) -> str:
|
||||
def as_html(self) -> str:
|
||||
"""
|
||||
Render elements tree as HTML markup
|
||||
"""
|
||||
text, entities = self.render()
|
||||
return html_decoration.unparse(text, entities)
|
||||
|
||||
def to_markdown(self) -> str:
|
||||
def as_markdown(self) -> str:
|
||||
"""
|
||||
Render elements tree as MarkdownV2 markup
|
||||
"""
|
||||
text, entities = self.render()
|
||||
return markdown_decoration.unparse(text, entities)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
body = ", ".join(repr(item) for item in self._body)
|
||||
params = ", ".join(f"{k}={v!r}" for k, v in self._params.items())
|
||||
def as_pretty_string(self, indent: bool = False) -> str:
|
||||
sep = ",\n" if indent else ", "
|
||||
body = sep.join(
|
||||
item.as_pretty_string(indent=indent) if isinstance(item, Text) else repr(item)
|
||||
for item in self._body
|
||||
)
|
||||
params = sep.join(f"{k}={v!r}" for k, v in self._params.items())
|
||||
|
||||
args = []
|
||||
if body:
|
||||
|
|
@ -133,38 +159,40 @@ class Node:
|
|||
if params:
|
||||
args.append(params)
|
||||
|
||||
return f"{type(self).__name__}({', '.join(args)})"
|
||||
args_str = sep.join(args)
|
||||
if indent:
|
||||
args_str = textwrap.indent("\n" + args_str + "\n", " ")
|
||||
return f"{type(self).__name__}({args_str})"
|
||||
|
||||
def __add__(self, other: NodeType) -> "Node":
|
||||
if type(self) == type(other) and self._params == other._params:
|
||||
return type(self)(*self._body, *other._body, **self._params)
|
||||
if type(self) == Node and isinstance(other, str):
|
||||
return type(self)(*self._body, other, **self._params)
|
||||
return Node(self, other)
|
||||
|
||||
def line(self: NodeT, *nodes: NodeType) -> NodeT:
|
||||
first_node = Text(self) if isinstance(self, str) else self
|
||||
return first_node + Text(*nodes, "\n")
|
||||
|
||||
def replace(self: NodeT, *args: Any, **kwargs: Any) -> NodeT:
|
||||
def replace(self: Self, *args: Any, **kwargs: Any) -> Self:
|
||||
return type(self)(*args, **{**self._params, **kwargs})
|
||||
|
||||
def __iter__(self) -> Iterator[NodeT]:
|
||||
return iter(self._body)
|
||||
def __repr__(self) -> str:
|
||||
return self.as_pretty_string()
|
||||
|
||||
def __add__(self, other: NodeType) -> "Text":
|
||||
if isinstance(other, Text) and other.type == self.type and self._params == other._params:
|
||||
return type(self)(*self, *other, **self._params)
|
||||
if type(self) == Text and isinstance(other, str):
|
||||
return type(self)(*self, other, **self._params)
|
||||
return Text(self, other)
|
||||
|
||||
def __iter__(self) -> Iterator[NodeType]:
|
||||
yield from self._body
|
||||
|
||||
def __len__(self) -> int:
|
||||
text, _ = self.render(_collect_entities=False)
|
||||
return sizeof(text)
|
||||
|
||||
def __getitem__(self, item):
|
||||
# FIXME: currently is not always separate text in correct place
|
||||
def __getitem__(self, item: slice) -> "Text":
|
||||
if not isinstance(item, slice):
|
||||
raise TypeError("Can only be sliced")
|
||||
if (item.start is None or item.start == 0) and item.stop is None:
|
||||
return self
|
||||
|
||||
start = item.start or 0
|
||||
stop = item.stop or len(self)
|
||||
start = 0 if item.start is None else item.start
|
||||
stop = len(self) if item.stop is None else item.stop
|
||||
if start == stop:
|
||||
return self.replace()
|
||||
|
||||
nodes = []
|
||||
position = 0
|
||||
|
|
@ -177,7 +205,9 @@ class Node:
|
|||
continue
|
||||
if current_position > stop:
|
||||
break
|
||||
new_node = node[start - current_position : stop - current_position]
|
||||
a = max((0, start - current_position))
|
||||
b = min((node_size, stop - current_position))
|
||||
new_node = node[a:b]
|
||||
if not new_node:
|
||||
continue
|
||||
nodes.append(new_node)
|
||||
|
|
@ -185,79 +215,208 @@ class Node:
|
|||
return self.replace(*nodes)
|
||||
|
||||
|
||||
class HashTag(Node):
|
||||
class HashTag(Text):
|
||||
"""
|
||||
Hashtag element.
|
||||
|
||||
.. warning::
|
||||
|
||||
The value should always start with '#' symbol
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.HASHTAG`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.HASHTAG
|
||||
|
||||
|
||||
class CashTag(Node):
|
||||
class CashTag(Text):
|
||||
"""
|
||||
Cashtag element.
|
||||
|
||||
.. warning::
|
||||
|
||||
The value should always start with '$' symbol
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.CASHTAG`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.CASHTAG
|
||||
|
||||
|
||||
class BotCommand(Node):
|
||||
class BotCommand(Text):
|
||||
"""
|
||||
Bot command element.
|
||||
|
||||
.. warning::
|
||||
|
||||
The value should always start with '/' symbol
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.BOT_COMMAND`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.BOT_COMMAND
|
||||
|
||||
|
||||
class Url(Node):
|
||||
class Url(Text):
|
||||
"""
|
||||
Url element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.URL`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.URL
|
||||
|
||||
|
||||
class Email(Node):
|
||||
class Email(Text):
|
||||
"""
|
||||
Email element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.EMAIL`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.EMAIL
|
||||
|
||||
|
||||
class PhoneNumber(Node):
|
||||
class PhoneNumber(Text):
|
||||
"""
|
||||
Phone number element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.PHONE_NUMBER`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.PHONE_NUMBER
|
||||
|
||||
|
||||
class Bold(Node):
|
||||
class Bold(Text):
|
||||
"""
|
||||
Bold element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.BOLD`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.BOLD
|
||||
|
||||
|
||||
class Italic(Node):
|
||||
class Italic(Text):
|
||||
"""
|
||||
Italic element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.ITALIC`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.ITALIC
|
||||
|
||||
|
||||
class Underline(Node):
|
||||
class Underline(Text):
|
||||
"""
|
||||
Underline element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.UNDERLINE`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.UNDERLINE
|
||||
|
||||
|
||||
class Strikethrough(Node):
|
||||
class Strikethrough(Text):
|
||||
"""
|
||||
Strikethrough element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.STRIKETHROUGH`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.STRIKETHROUGH
|
||||
|
||||
|
||||
class Spoiler(Node):
|
||||
class Spoiler(Text):
|
||||
"""
|
||||
Spoiler element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.SPOILER`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.SPOILER
|
||||
|
||||
|
||||
class Code(Node):
|
||||
class Code(Text):
|
||||
"""
|
||||
Code element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.CODE`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.CODE
|
||||
|
||||
|
||||
class Pre(Node):
|
||||
class Pre(Text):
|
||||
"""
|
||||
Pre element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.PRE`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.PRE
|
||||
|
||||
def __init__(self, *body: NodeType, language: str, **params: Any) -> None:
|
||||
super().__init__(*body, language=language, **params)
|
||||
|
||||
|
||||
class TextLink(Node):
|
||||
class TextLink(Text):
|
||||
"""
|
||||
Text link element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.TEXT_LINK`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.TEXT_LINK
|
||||
|
||||
def __init__(self, *body: NodeType, url: str, **params: Any) -> None:
|
||||
super().__init__(*body, url=url, **params)
|
||||
|
||||
|
||||
class TextMention(Node):
|
||||
class TextMention(Text):
|
||||
"""
|
||||
Text mention element.
|
||||
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.TEXT_MENTION`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.TEXT_MENTION
|
||||
|
||||
def __init__(self, *body: NodeType, user: User, **params: Any) -> None:
|
||||
super().__init__(*body, user=user, **params)
|
||||
|
||||
|
||||
Text = Node
|
||||
Strong = Bold
|
||||
class CustomEmoji(Text):
|
||||
"""
|
||||
Custom emoji element.
|
||||
|
||||
NODE_TYPES = {
|
||||
Will be wrapped into :obj:`aiogram.types.message_entity.MessageEntity`
|
||||
with type :obj:`aiogram.enums.message_entity_type.MessageEntityType.CUSTOM_EMOJI`
|
||||
"""
|
||||
|
||||
type = MessageEntityType.CUSTOM_EMOJI
|
||||
|
||||
def __init__(self, *body: NodeType, emoji_id: str, **params: Any) -> None:
|
||||
super().__init__(*body, emoji_id=emoji_id, **params)
|
||||
|
||||
|
||||
NODE_TYPES: Dict[Optional[str], Type[Text]] = {
|
||||
Text.type: Text,
|
||||
HashTag.type: HashTag,
|
||||
CashTag.type: CashTag,
|
||||
BotCommand.type: BotCommand,
|
||||
|
|
@ -273,7 +432,6 @@ NODE_TYPES = {
|
|||
Pre.type: Pre,
|
||||
TextLink.type: TextLink,
|
||||
TextMention.type: TextMention,
|
||||
Text.type: Text,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -285,7 +443,7 @@ def _apply_entity(entity: MessageEntity, *nodes: NodeType) -> NodeType:
|
|||
:param text:
|
||||
:return:
|
||||
"""
|
||||
node_type = NODE_TYPES.get(entity.type, Node)
|
||||
node_type = NODE_TYPES.get(entity.type, Text)
|
||||
return node_type(*nodes, **entity.dict(exclude={"type", "offset", "length"}))
|
||||
|
||||
|
||||
|
|
@ -317,17 +475,106 @@ def _unparse_entities(
|
|||
yield remove_surrogates(text[offset:length])
|
||||
|
||||
|
||||
def as_list(*items: NodeType) -> Node:
|
||||
def as_line(*items: NodeType, end: str = "\n") -> Text:
|
||||
"""
|
||||
Wrap multiple nodes into line with :code:`\\\\n` at the end of line.
|
||||
|
||||
:param items: Text or Any
|
||||
:param end: ending of the line, by default is :code:`\\\\n`
|
||||
:return: Text
|
||||
"""
|
||||
return Text(*items, end)
|
||||
|
||||
|
||||
def as_list(*items: NodeType, sep: str = "\n") -> Text:
|
||||
"""
|
||||
Wrap each element to separated lines
|
||||
|
||||
:param items:
|
||||
:param sep:
|
||||
:return:
|
||||
"""
|
||||
nodes = []
|
||||
for item in items[:-1]:
|
||||
nodes.extend([item, "\n"])
|
||||
nodes.extend([item, sep])
|
||||
nodes.append(items[-1])
|
||||
return Node(*nodes)
|
||||
return Text(*nodes)
|
||||
|
||||
|
||||
def as_marked_list(*items: NodeType, marker: str = "- ") -> Node:
|
||||
return as_list(*(Node(marker, item) for item in items))
|
||||
def as_marked_list(*items: NodeType, marker: str = "- ") -> Text:
|
||||
"""
|
||||
Wrap elements as marked list
|
||||
|
||||
:param items:
|
||||
:param marker: line marker, by default is :code:`- `
|
||||
:return: Text
|
||||
"""
|
||||
return as_list(*(Text(marker, item) for item in items))
|
||||
|
||||
|
||||
def as_numbered_list(*items: NodeType, start: int = 1, fmt: str = "{}. ") -> Node:
|
||||
return as_list(*(Node(fmt.format(index), item) for index, item in enumerate(items, start)))
|
||||
def as_numbered_list(*items: NodeType, start: int = 1, fmt: str = "{}. ") -> Text:
|
||||
"""
|
||||
Wrap elements as numbered list
|
||||
|
||||
:param items:
|
||||
:param start: initial number, by default 1
|
||||
:param fmt: number format, by default :code:`{}. `
|
||||
:return: Text
|
||||
"""
|
||||
return as_list(*(Text(fmt.format(index), item) for index, item in enumerate(items, start)))
|
||||
|
||||
|
||||
def as_section(title: NodeType, *body: NodeType) -> Text:
|
||||
"""
|
||||
Wrap elements as simple section, section has title and body
|
||||
|
||||
:param title:
|
||||
:param body:
|
||||
:return: Text
|
||||
"""
|
||||
return Text(title, "\n", *body)
|
||||
|
||||
|
||||
def as_marked_section(
|
||||
title: NodeType,
|
||||
*body: NodeType,
|
||||
marker: str = "- ",
|
||||
) -> Text:
|
||||
"""
|
||||
Wrap elements as section with marked list
|
||||
|
||||
:param title:
|
||||
:param body:
|
||||
:param marker:
|
||||
:return:
|
||||
"""
|
||||
return as_section(title, as_marked_list(*body, marker=marker))
|
||||
|
||||
|
||||
def as_numbered_section(
|
||||
title: NodeType,
|
||||
*body: NodeType,
|
||||
start: int = 1,
|
||||
fmt: str = "{}. ",
|
||||
) -> Text:
|
||||
"""
|
||||
Wrap elements as section with numbered list
|
||||
|
||||
:param title:
|
||||
:param body:
|
||||
:param start:
|
||||
:param fmt:
|
||||
:return:
|
||||
"""
|
||||
return as_section(title, as_numbered_list(*body, start=start, fmt=fmt))
|
||||
|
||||
|
||||
def as_key_value(key: NodeType, value: NodeType) -> Text:
|
||||
"""
|
||||
Wrap elements pair as key-value line. (:code:`<b>{key}:</b> {value}`)
|
||||
|
||||
:param key:
|
||||
:param value:
|
||||
:return: Text
|
||||
"""
|
||||
return Text(Bold(key, ":"), " ", value)
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
##################
|
||||
setStickerSetThumb
|
||||
##################
|
||||
|
||||
Returns: :obj:`bool`
|
||||
|
||||
.. automodule:: aiogram.methods.set_sticker_set_thumb
|
||||
:members:
|
||||
:member-order: bysource
|
||||
:undoc-members: True
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
As bot method
|
||||
-------------
|
||||
|
||||
.. code-block::
|
||||
|
||||
result: bool = await bot.set_sticker_set_thumb(...)
|
||||
|
||||
|
||||
Method as object
|
||||
----------------
|
||||
|
||||
Imports:
|
||||
|
||||
- :code:`from aiogram.methods.set_sticker_set_thumb import SetStickerSetThumb`
|
||||
- alias: :code:`from aiogram.methods import SetStickerSetThumb`
|
||||
|
||||
With specific bot
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
result: bool = await bot(SetStickerSetThumb(...))
|
||||
|
||||
As reply into Webhook in handler
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
return SetStickerSetThumb(...)
|
||||
197
docs/utils/formatting.rst
Normal file
197
docs/utils/formatting.rst
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
==========
|
||||
Formatting
|
||||
==========
|
||||
|
||||
Make your message formatting flexible and simple
|
||||
|
||||
This instrument works on top of Message entities instead of using HTML or Markdown markups,
|
||||
you can easily construct your message and sent it to the Telegram without the need to
|
||||
remember tag parity (opening and closing) or escaping user input.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Basic scenario
|
||||
--------------
|
||||
|
||||
Construct your message and send it to the Telegram.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
content = Text("Hello, ", Bold(message.from_user.full_name), "!")
|
||||
await message.answer(**content.as_kwargs())
|
||||
|
||||
Is the same as the next example, but without usage markup
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
await message.answer(
|
||||
text=f"Hello, <b>{html.quote(message.from_user.full_name)}!",
|
||||
parse_mode=ParseMode.HTML
|
||||
)
|
||||
|
||||
Literally when you execute :code:`as_kwargs` method the Text object is converted
|
||||
into text :code:`Hello, Alex!` with entities list :code:`[MessageEntity(type='bold', offset=7, length=4)]`
|
||||
and passed into dict which can be used as :code:`**kwargs` in API call.
|
||||
|
||||
The complete list of elements is listed `on this page below <#available-elements>`_.
|
||||
|
||||
Advanced scenario
|
||||
-----------------
|
||||
|
||||
On top of base elements can be implemented content rendering structures,
|
||||
so, out of the box aiogram has a few already implemented functions that helps you to format
|
||||
your messages:
|
||||
|
||||
.. autofunction:: aiogram.utils.formatting.as_line
|
||||
|
||||
.. autofunction:: aiogram.utils.formatting.as_list
|
||||
|
||||
.. autofunction:: aiogram.utils.formatting.as_marked_list
|
||||
|
||||
.. autofunction:: aiogram.utils.formatting.as_numbered_list
|
||||
|
||||
.. autofunction:: aiogram.utils.formatting.as_section
|
||||
|
||||
.. autofunction:: aiogram.utils.formatting.as_marked_section
|
||||
|
||||
.. autofunction:: aiogram.utils.formatting.as_numbered_section
|
||||
|
||||
.. autofunction:: aiogram.utils.formatting.as_key_value
|
||||
|
||||
and lets complete them all:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
content = as_list(
|
||||
as_marked_section(
|
||||
Bold("Success:"),
|
||||
"Test 1",
|
||||
"Test 3",
|
||||
"Test 4",
|
||||
marker="✅ ",
|
||||
),
|
||||
as_marked_section(
|
||||
Bold("Failed:"),
|
||||
"Test 2",
|
||||
marker="❌ ",
|
||||
),
|
||||
as_marked_section(
|
||||
Bold("Summary:"),
|
||||
as_key_value("Total", 4),
|
||||
as_key_value("Success", 3),
|
||||
as_key_value("Failed", 1),
|
||||
marker=" ",
|
||||
),
|
||||
HashTag("#test"),
|
||||
sep="\n\n",
|
||||
)
|
||||
|
||||
Will be rendered into:
|
||||
|
||||
**Success:**
|
||||
|
||||
✅ Test 1
|
||||
|
||||
✅ Test 3
|
||||
|
||||
✅ Test 4
|
||||
|
||||
**Failed:**
|
||||
|
||||
❌ Test 2
|
||||
|
||||
**Summary:**
|
||||
|
||||
**Total**: 4
|
||||
|
||||
**Success**: 3
|
||||
|
||||
**Failed**: 1
|
||||
|
||||
#test
|
||||
|
||||
|
||||
Or as HTML:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<b>Success:</b>
|
||||
✅ Test 1
|
||||
✅ Test 3
|
||||
✅ Test 4
|
||||
|
||||
<b>Failed:</b>
|
||||
❌ Test 2
|
||||
|
||||
<b>Summary:</b>
|
||||
<b>Total:</b> 4
|
||||
<b>Success:</b> 3
|
||||
<b>Failed:</b> 1
|
||||
|
||||
#test
|
||||
|
||||
Available methods
|
||||
=================
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Text
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:member-order: bysource
|
||||
:special-members: __init__
|
||||
|
||||
|
||||
Available elements
|
||||
==================
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Text
|
||||
:show-inheritance:
|
||||
:noindex:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.HashTag
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.CashTag
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.BotCommand
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Url
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Email
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.PhoneNumber
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Bold
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Italic
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Underline
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Strikethrough
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Spoiler
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Code
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.Pre
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.TextLink
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.TextMention
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: aiogram.utils.formatting.CustomEmoji
|
||||
:show-inheritance:
|
||||
|
|
@ -9,3 +9,4 @@ Utils
|
|||
chat_action
|
||||
web_app
|
||||
callback_answer
|
||||
formatting
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import pytest
|
|||
|
||||
from aiogram.utils.link import (
|
||||
BRANCH,
|
||||
create_channel_bot_link,
|
||||
create_telegram_link,
|
||||
create_tg_link,
|
||||
docs_url,
|
||||
create_channel_bot_link,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue