Skip to content

Commit

Permalink
Allow Input of Type Sticker for Several Methods (python-telegram-bo…
Browse files Browse the repository at this point in the history
  • Loading branch information
Bibo-Joshi authored Dec 29, 2024
1 parent df20e49 commit a6cd9c5
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 55 deletions.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ markers = [
"req",
]
asyncio_mode = "auto"
log_format = "%(funcName)s - Line %(lineno)d - %(message)s"
# log_level = "DEBUG" # uncomment to see DEBUG logs
log_cli_format = "%(funcName)s - Line %(lineno)d - %(message)s"
# log_cli_level = "DEBUG" # uncomment to see DEBUG logs

# MYPY:
[tool.mypy]
Expand Down
72 changes: 54 additions & 18 deletions telegram/_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6622,7 +6622,7 @@ async def add_sticker_to_set(

async def set_sticker_position_in_set(
self,
sticker: str,
sticker: Union[str, "Sticker"],
position: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand All @@ -6634,7 +6634,11 @@ async def set_sticker_position_in_set(
"""Use this method to move a sticker in a set created by the bot to a specific position.
Args:
sticker (:obj:`str`): File identifier of the sticker.
sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or
the sticker object.
.. versionchanged:: NEXT.VERSION
Accepts also :class:`telegram.Sticker` instances.
position (:obj:`int`): New sticker position in the set, zero-based.
Returns:
Expand All @@ -6644,7 +6648,10 @@ async def set_sticker_position_in_set(
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {"sticker": sticker, "position": position}
data: JSONDict = {
"sticker": sticker if isinstance(sticker, str) else sticker.file_id,
"position": position,
}
return await self._post(
"setStickerPositionInSet",
data,
Expand Down Expand Up @@ -6749,7 +6756,7 @@ async def create_new_sticker_set(

async def delete_sticker_from_set(
self,
sticker: str,
sticker: Union[str, "Sticker"],
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
Expand All @@ -6760,7 +6767,11 @@ async def delete_sticker_from_set(
"""Use this method to delete a sticker from a set created by the bot.
Args:
sticker (:obj:`str`): File identifier of the sticker.
sticker (:obj:`str` | :class:`telegram.Sticker`): File identifier of the sticker or
the sticker object.
.. versionchanged:: NEXT.VERSION
Accepts also :class:`telegram.Sticker` instances.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
Expand All @@ -6769,7 +6780,7 @@ async def delete_sticker_from_set(
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {"sticker": sticker}
data: JSONDict = {"sticker": sticker if isinstance(sticker, str) else sticker.file_id}
return await self._post(
"deleteStickerFromSet",
data,
Expand Down Expand Up @@ -6937,7 +6948,7 @@ async def set_sticker_set_title(

async def set_sticker_emoji_list(
self,
sticker: str,
sticker: Union[str, "Sticker"],
emoji_list: Sequence[str],
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand All @@ -6953,7 +6964,11 @@ async def set_sticker_emoji_list(
.. versionadded:: 20.2
Args:
sticker (:obj:`str`): File identifier of the sticker.
sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or
the sticker object.
.. versionchanged:: NEXT.VERSION
Accepts also :class:`telegram.Sticker` instances.
emoji_list (Sequence[:obj:`str`]): A sequence of
:tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI`-
:tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with
Expand All @@ -6965,7 +6980,10 @@ async def set_sticker_emoji_list(
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {"sticker": sticker, "emoji_list": emoji_list}
data: JSONDict = {
"sticker": sticker if isinstance(sticker, str) else sticker.file_id,
"emoji_list": emoji_list,
}
return await self._post(
"setStickerEmojiList",
data,
Expand All @@ -6978,7 +6996,7 @@ async def set_sticker_emoji_list(

async def set_sticker_keywords(
self,
sticker: str,
sticker: Union[str, "Sticker"],
keywords: Optional[Sequence[str]] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand All @@ -6994,7 +7012,11 @@ async def set_sticker_keywords(
.. versionadded:: 20.2
Args:
sticker (:obj:`str`): File identifier of the sticker.
sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or
the sticker object.
.. versionchanged:: NEXT.VERSION
Accepts also :class:`telegram.Sticker` instances.
keywords (Sequence[:obj:`str`]): A sequence of
0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords
for the sticker with total length up to
Expand All @@ -7006,7 +7028,10 @@ async def set_sticker_keywords(
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {"sticker": sticker, "keywords": keywords}
data: JSONDict = {
"sticker": sticker if isinstance(sticker, str) else sticker.file_id,
"keywords": keywords,
}
return await self._post(
"setStickerKeywords",
data,
Expand All @@ -7019,7 +7044,7 @@ async def set_sticker_keywords(

async def set_sticker_mask_position(
self,
sticker: str,
sticker: Union[str, "Sticker"],
mask_position: Optional[MaskPosition] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand All @@ -7035,7 +7060,11 @@ async def set_sticker_mask_position(
.. versionadded:: 20.2
Args:
sticker (:obj:`str`): File identifier of the sticker.
sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or
the sticker object.
.. versionchanged:: NEXT.VERSION
Accepts also :class:`telegram.Sticker` instances.
mask_position (:class:`telegram.MaskPosition`, optional): A object with the position
where the mask should be placed on faces. Omit the parameter to remove the mask
position.
Expand All @@ -7046,7 +7075,10 @@ async def set_sticker_mask_position(
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {"sticker": sticker, "mask_position": mask_position}
data: JSONDict = {
"sticker": sticker if isinstance(sticker, str) else sticker.file_id,
"mask_position": mask_position,
}
return await self._post(
"setStickerMaskPosition",
data,
Expand Down Expand Up @@ -9248,7 +9280,7 @@ async def replace_sticker_in_set(
self,
user_id: int,
name: str,
old_sticker: str,
old_sticker: Union[str, "Sticker"],
sticker: "InputSticker",
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand All @@ -9266,7 +9298,11 @@ async def replace_sticker_in_set(
Args:
user_id (:obj:`int`): User identifier of the sticker set owner.
name (:obj:`str`): Sticker set name.
old_sticker (:obj:`str`): File identifier of the replaced sticker.
old_sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the replaced
sticker or the sticker object itself.
.. versionchanged:: NEXT.VERSION
Accepts also :class:`telegram.Sticker` instances.
sticker (:class:`telegram.InputSticker`): An object with information about the added
sticker. If exactly the same sticker had already been added to the set, then the
set remains unchanged.
Expand All @@ -9280,7 +9316,7 @@ async def replace_sticker_in_set(
data: JSONDict = {
"user_id": user_id,
"name": name,
"old_sticker": old_sticker,
"old_sticker": old_sticker if isinstance(old_sticker, str) else old_sticker.file_id,
"sticker": sticker,
}

Expand Down
12 changes: 6 additions & 6 deletions telegram/ext/_extbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,7 @@ async def delete_my_commands(

async def delete_sticker_from_set(
self,
sticker: str,
sticker: Union[str, "Sticker"],
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
Expand Down Expand Up @@ -3660,7 +3660,7 @@ async def set_passport_data_errors(

async def set_sticker_position_in_set(
self,
sticker: str,
sticker: Union[str, "Sticker"],
position: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand Down Expand Up @@ -4114,7 +4114,7 @@ async def delete_sticker_set(

async def set_sticker_emoji_list(
self,
sticker: str,
sticker: Union[str, "Sticker"],
emoji_list: Sequence[str],
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand All @@ -4136,7 +4136,7 @@ async def set_sticker_emoji_list(

async def set_sticker_keywords(
self,
sticker: str,
sticker: Union[str, "Sticker"],
keywords: Optional[Sequence[str]] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand All @@ -4158,7 +4158,7 @@ async def set_sticker_keywords(

async def set_sticker_mask_position(
self,
sticker: str,
sticker: Union[str, "Sticker"],
mask_position: Optional[MaskPosition] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand Down Expand Up @@ -4250,7 +4250,7 @@ async def replace_sticker_in_set(
self,
user_id: int,
name: str,
old_sticker: str,
old_sticker: Union[str, "Sticker"],
sticker: "InputSticker",
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand Down
48 changes: 48 additions & 0 deletions tests/_files/test_sticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,54 @@ async def make_assertion(*_, **kwargs):
monkeypatch.setattr(sticker.get_bot(), "get_file", make_assertion)
assert await sticker.get_file()

async def test_delete_sticker_from_set_sticker_input(self, offline_bot, sticker, monkeypatch):
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
return request_data.json_parameters["sticker"] == sticker.file_id

monkeypatch.setattr(offline_bot.request, "post", make_assertion)
assert await offline_bot.delete_sticker_from_set(sticker)

async def test_replace_sticker_in_set_sticker_input(self, offline_bot, sticker, monkeypatch):
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
return request_data.json_parameters["old_sticker"] == sticker.file_id

monkeypatch.setattr(offline_bot.request, "post", make_assertion)
assert await offline_bot.replace_sticker_in_set(
user_id=1, name="name", sticker="sticker", old_sticker=sticker
)

async def test_set_sticker_emoji_list_sticker_input(self, offline_bot, sticker, monkeypatch):
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
return request_data.json_parameters["sticker"] == sticker.file_id

monkeypatch.setattr(offline_bot.request, "post", make_assertion)
assert await offline_bot.set_sticker_emoji_list(sticker, ["emoji"])

async def test_set_sticker_mask_position_sticker_input(
self, offline_bot, sticker, monkeypatch
):
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
return request_data.json_parameters["sticker"] == sticker.file_id

monkeypatch.setattr(offline_bot.request, "post", make_assertion)
assert await offline_bot.set_sticker_mask_position(sticker, MaskPosition("eyes", 1, 2, 3))

async def test_set_sticker_position_in_set_sticker_input(
self, offline_bot, sticker, monkeypatch
):
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
return request_data.json_parameters["sticker"] == sticker.file_id

monkeypatch.setattr(offline_bot.request, "post", make_assertion)
assert await offline_bot.set_sticker_position_in_set(sticker, 1)

async def test_set_sticker_keywords_sticker_input(self, offline_bot, sticker, monkeypatch):
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
return request_data.json_parameters["sticker"] == sticker.file_id

monkeypatch.setattr(offline_bot.request, "post", make_assertion)
assert await offline_bot.set_sticker_keywords(sticker, ["keyword"])


@pytest.mark.xdist_group("stickerset")
class TestStickerSetWithRequest:
Expand Down
11 changes: 11 additions & 0 deletions tests/auxil/bot_method_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
InputTextMessageContent,
LinkPreviewOptions,
ReplyParameters,
Sticker,
TelegramObject,
)
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
Expand Down Expand Up @@ -317,6 +318,16 @@ def build_kwargs(
kws["error_message"] = "error"
elif name == "options":
kws[name] = ["option1", "option2"]
elif name in ("sticker", "old_sticker"):
kws[name] = Sticker(
file_id="file_id",
file_unique_id="file_unique_id",
width=1,
height=1,
is_animated=False,
is_video=False,
type="regular",
)
else:
kws[name] = True

Expand Down
18 changes: 10 additions & 8 deletions tests/test_official/arg_type_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
_get_params_base,
_unionizer,
cached_type_hints,
extract_mappings,
resolve_forward_refs_in_type,
wrap_with_none,
)
Expand Down Expand Up @@ -144,7 +145,7 @@ def check_param_type(
)

# CHECKING:
# Each branch manipulates the `mapped_type` (except for 4) ) to match the `ptb_annotation`.
# Each branch manipulates the `mapped_type` (except for 5) ) to match the `ptb_annotation`.

# 1) HANDLING ARRAY TYPES:
# Now let's do the checking, starting with "Array of ..." types.
Expand Down Expand Up @@ -174,9 +175,11 @@ def check_param_type(

# 2) HANDLING OTHER TYPES:
# Special case for send_* methods where we accept more types than the official API:
elif ptb_param.name in PTCE.ADDITIONAL_TYPES and obj.__name__.startswith("send"):
log("Checking that `%s` has an additional argument!\n", ptb_param.name)
mapped_type = mapped_type | PTCE.ADDITIONAL_TYPES[ptb_param.name]
elif additional_types := extract_mappings(PTCE.ADDITIONAL_TYPES, obj, ptb_param.name):
log("Checking that `%s` accepts additional types for some parameters!\n", obj.__name__)
for at in additional_types:
log("Checking that `%s` is an additional type for `%s`!\n", at, ptb_param.name)
mapped_type = mapped_type | at

# 3) HANDLING DATETIMES:
elif (
Expand Down Expand Up @@ -205,11 +208,10 @@ def check_param_type(

# 5) COMPLEX TYPES:
# Some types are too complicated, so we replace our annotation with a simpler type:
elif any(ptb_param.name in key for key in PTCE.COMPLEX_TYPES):
elif overrides := extract_mappings(PTCE.COMPLEX_TYPES, obj, ptb_param.name):
exception_type = overrides[0]
log("Converting `%s` to a simpler type!\n", ptb_param.name)
for (param_name, is_expected_class), exception_type in PTCE.COMPLEX_TYPES.items():
if ptb_param.name == param_name and is_class is is_expected_class:
ptb_annotation = wrap_with_none(tg_parameter, exception_type, obj)
ptb_annotation = wrap_with_none(tg_parameter, exception_type, obj)

# 6) HANDLING DEFAULTS PARAMETERS:
# Classes whose parameters are all ODVInput should be converted and checked.
Expand Down
Loading

0 comments on commit a6cd9c5

Please sign in to comment.