1
0
mirror of https://github.com/eternnoir/pyTelegramBotAPI.git synced 2023-08-10 21:12:57 +03:00

Merge pull request #1206 from MAIKS1900/master

2 of 3 Bot API 5.3 changes
This commit is contained in:
Badiboy 2021-06-27 17:33:04 +03:00 committed by GitHub
commit 8d8f234138
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 175 additions and 14 deletions

View File

@ -1703,21 +1703,52 @@ class TeleBot:
"""
return apihelper.delete_chat_photo(self.token, chat_id)
def get_my_commands(self) -> List[types.BotCommand]:
def get_my_commands(self,
scope: Optional[Union[
types.BotCommandScopeDefault, types.BotCommandScopeAllPrivateChats,
types.BotCommandScopeAllGroupChats, types.BotCommandScopeAllChatAdministrators,
types.BotCommandScopeChat,
types.BotCommandScopeChatAdministrators, types.BotCommandScopeChatMember]]=None,
language_code: Optional[str]=None) -> List[types.BotCommand]:
"""
Use this method to get the current list of the bot's commands.
Use this method to get the current list of the bot's commands for the given scope and user language
:param scope: scope of users for which the commands are relevant
:param language_code: A two-letter ISO 639-1 language code
Returns List of BotCommand on success.
"""
result = apihelper.get_my_commands(self.token)
result = apihelper.get_my_commands(self.token, scope, language_code)
return [types.BotCommand.de_json(cmd) for cmd in result]
def set_my_commands(self, commands: List[types.BotCommand]) -> bool:
def set_my_commands(self, commands: List[types.BotCommand],
scope: Optional[Union[
types.BotCommandScopeDefault, types.BotCommandScopeAllPrivateChats,
types.BotCommandScopeAllGroupChats, types.BotCommandScopeAllChatAdministrators,
types.BotCommandScopeChat,
types.BotCommandScopeChatAdministrators, types.BotCommandScopeChatMember]] = None,
language_code: Optional[str]=None) -> bool:
"""
Use this method to change the list of the bot's commands.
:param commands: List of BotCommand. At most 100 commands can be specified.
:param scope: scope of users for which the commands are relevant
:param language_code: A two-letter ISO 639-1 language code
:return:
"""
return apihelper.set_my_commands(self.token, commands)
return apihelper.set_my_commands(self.token, commands, scope, language_code)
def delete_my_commands(self,
scope: Optional[Union[
types.BotCommandScopeDefault, types.BotCommandScopeAllPrivateChats,
types.BotCommandScopeAllGroupChats, types.BotCommandScopeAllChatAdministrators,
types.BotCommandScopeChat,
types.BotCommandScopeChatAdministrators, types.BotCommandScopeChatMember]]=None,
language_code: Optional[str]=None) -> bool:
"""
Use this method to delete the list of the bot's commands for the given scope and user language.
:param scope: scope of users for which the commands are relevant
:param language_code: A two-letter ISO 639-1 language code
:return:
"""
return apihelper.delete_my_commands(self.token, scope, language_code)
def set_chat_title(self, chat_id: Union[int, str], title: str) -> bool:
"""

View File

@ -169,11 +169,6 @@ def get_me(token):
return _make_request(token, method_url)
def get_my_commands(token):
method_url = r'getMyCommands'
return _make_request(token, method_url)
def log_out(token):
method_url = r'logOut'
return _make_request(token, method_url)
@ -1032,9 +1027,33 @@ def set_chat_title(token, chat_id, title):
return _make_request(token, method_url, params=payload, method='post')
def set_my_commands(token, commands):
def get_my_commands(token, scope, language_code):
method_url = r'getMyCommands'
payload = {}
if scope is not None:
payload['scope'] = scope.to_json()
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')
def set_my_commands(token, commands, scope, language_code):
method_url = r'setMyCommands'
payload = {'commands': _convert_list_json_serializable(commands)}
if scope is not None:
payload['scope'] = scope.to_json()
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')
def delete_my_commands(token, scope, language_code):
method_url = r'deleteMyCommands'
payload = {}
if scope is not None:
payload['scope'] = scope.to_json()
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')

View File

@ -2,6 +2,7 @@
import logging
from typing import Dict, List, Optional, Union
from abc import ABC
try:
import ujson as json
@ -848,13 +849,16 @@ class File(JsonDeserializable):
class ForceReply(JsonSerializable):
def __init__(self, selective=None):
def __init__(self, selective=None, input_field_placeholder=None):
self.selective: bool = selective
self.input_field_placeholder = input_field_placeholder
def to_json(self):
json_dict = {'force_reply': True}
if self.selective:
json_dict['selective'] = True
if self.input_field_placeholder:
json_dict['input_field_placeholder'] = self.input_field_placeholder
return json.dumps(json_dict)
@ -872,7 +876,8 @@ class ReplyKeyboardRemove(JsonSerializable):
class ReplyKeyboardMarkup(JsonSerializable):
max_row_keys = 12
def __init__(self, resize_keyboard=None, one_time_keyboard=None, selective=None, row_width=3):
def __init__(self, resize_keyboard=None, one_time_keyboard=None, selective=None, row_width=3,
input_field_placeholder=None):
if row_width > self.max_row_keys:
# Todo: Will be replaced with Exception in future releases
if not DISABLE_KEYLEN_ERROR:
@ -883,6 +888,7 @@ class ReplyKeyboardMarkup(JsonSerializable):
self.one_time_keyboard: bool = one_time_keyboard
self.selective: bool = selective
self.row_width: int = row_width
self.input_field_placeholder = input_field_placeholder
self.keyboard: List[List[KeyboardButton]] = []
def add(self, *args, row_width=None):
@ -926,7 +932,7 @@ class ReplyKeyboardMarkup(JsonSerializable):
:param args: strings
:return: self, to allow function chaining.
"""
return self.add(*args, row_width=self.max_row_keys)
def to_json(self):
@ -942,6 +948,8 @@ class ReplyKeyboardMarkup(JsonSerializable):
json_dict['resize_keyboard'] = True
if self.selective:
json_dict['selective'] = True
if self.input_field_placeholder:
json_dict['input_field_placeholder'] = self.input_field_placeholder
return json.dumps(json_dict)
@ -1270,6 +1278,91 @@ class BotCommand(JsonSerializable, JsonDeserializable):
return {'command': self.command, 'description': self.description}
# BotCommandScopes
class BotCommandScope(ABC, JsonSerializable):
def __init__(self, type='default', chat_id=None, user_id=None):
"""
Abstract class.
Use BotCommandScopeX classes to set a specific scope type:
BotCommandScopeDefault
BotCommandScopeAllPrivateChats
BotCommandScopeAllGroupChats
BotCommandScopeAllChatAdministrators
BotCommandScopeChat
BotCommandScopeChatAdministrators
BotCommandScopeChatMember
"""
self.type: str = type
self.chat_id: Optional[Union[int, str]] = chat_id
self.user_id: Optional[Union[int, str]] = user_id
def to_json(self):
json_dict = {'type': self.type}
if self.chat_id:
json_dict['chat_id'] = self.chat_id
if self.user_id:
json_dict['user_id'] = self.user_id
return json.dumps(json_dict)
class BotCommandScopeDefault(BotCommandScope):
def __init__(self):
"""
Represents the default scope of bot commands.
Default commands are used if no commands with a narrower scope are specified for the user.
"""
super(BotCommandScopeDefault, self).__init__(type='default')
class BotCommandScopeAllPrivateChats(BotCommandScope):
def __init__(self):
"""
Represents the scope of bot commands, covering all private chats.
"""
super(BotCommandScopeAllPrivateChats, self).__init__(type='all_private_chats')
class BotCommandScopeAllGroupChats(BotCommandScope):
def __init__(self):
"""
Represents the scope of bot commands, covering all group and supergroup chats.
"""
super(BotCommandScopeAllGroupChats, self).__init__(type='all_group_chats')
class BotCommandScopeAllChatAdministrators(BotCommandScope):
def __init__(self):
"""
Represents the scope of bot commands, covering all group and supergroup chat administrators.
"""
super(BotCommandScopeAllChatAdministrators, self).__init__(type='all_chat_administrators')
class BotCommandScopeChat(BotCommandScope):
def __init__(self, chat_id=None):
super(BotCommandScopeChat, self).__init__(type='chat', chat_id=chat_id)
class BotCommandScopeChatAdministrators(BotCommandScope):
def __init__(self, chat_id=None):
"""
Represents the scope of bot commands, covering a specific chat.
@param chat_id: Unique identifier for the target chat
"""
super(BotCommandScopeChatAdministrators, self).__init__(type='chat_administrators', chat_id=chat_id)
class BotCommandScopeChatMember(BotCommandScope):
def __init__(self, chat_id=None, user_id=None):
"""
Represents the scope of bot commands, covering all administrators of a specific group or supergroup chat
@param chat_id: Unique identifier for the target chat
@param user_id: Unique identifier of the target user
"""
super(BotCommandScopeChatMember, self).__init__(type='chat_administrators', chat_id=chat_id, user_id=user_id)
# InlineQuery
class InlineQuery(JsonDeserializable):

View File

@ -546,6 +546,24 @@ class TestTeleBot:
ret_msg = tb.send_document(CHAT_ID, file_data, caption='_italic_', parse_mode='Markdown')
assert ret_msg.caption_entities[0].type == 'italic'
def test_chat_commands(self):
tb = telebot.TeleBot(TOKEN)
command, description, lang = 'command_1', 'description of command 1', 'en'
scope = telebot.types.BotCommandScopeChat(CHAT_ID)
ret_msg = tb.set_my_commands([telebot.types.BotCommand(command, description)], scope, lang)
assert ret_msg is True
ret_msg = tb.get_my_commands(scope, lang)
assert ret_msg[0].command == command
assert ret_msg[0].description == description
ret_msg = tb.delete_my_commands(scope, lang)
assert ret_msg is True
ret_msg = tb.get_my_commands(scope, lang)
assert ret_msg == []
def test_typed_middleware_handler(self):
from telebot import apihelper