Skip to content

Commit

Permalink
Merge pull request #1206 from MAIKS1900/master
Browse files Browse the repository at this point in the history
2 of 3 Bot API 5.3 changes
  • Loading branch information
Badiboy authored Jun 27, 2021
2 parents fb290dc + 491cc05 commit 8d8f234
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 15 deletions.
43 changes: 37 additions & 6 deletions telebot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1703,21 +1703,52 @@ def delete_chat_photo(self, chat_id: Union[int, str]) -> bool:
"""
return apihelper.delete_chat_photo(self.token, chat_id)

def get_my_commands(self) -> List[types.BotCommand]:
"""
Use this method to get the current list of the bot's commands.
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 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, 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.set_my_commands(self.token, commands)
return apihelper.delete_my_commands(self.token, scope, language_code)

def set_chat_title(self, chat_id: Union[int, str], title: str) -> bool:
"""
Expand Down
31 changes: 25 additions & 6 deletions telebot/apihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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')


Expand Down
99 changes: 96 additions & 3 deletions telebot/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import logging
from typing import Dict, List, Optional, Union
from abc import ABC

try:
import ujson as json
Expand Down Expand Up @@ -848,13 +849,16 @@ def __init__(self, file_id, file_unique_id, file_size, file_path, **kwargs):


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)


Expand All @@ -872,7 +876,8 @@ def to_json(self):
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:
Expand All @@ -883,6 +888,7 @@ def __init__(self, resize_keyboard=None, one_time_keyboard=None, selective=None,
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):
Expand Down Expand Up @@ -926,7 +932,7 @@ def row(self, *args):
:param args: strings
:return: self, to allow function chaining.
"""

return self.add(*args, row_width=self.max_row_keys)

def to_json(self):
Expand All @@ -942,6 +948,8 @@ def to_json(self):
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)


Expand Down Expand Up @@ -1270,6 +1278,91 @@ def to_dict(self):
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):
Expand Down
18 changes: 18 additions & 0 deletions tests/test_telebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,24 @@ def test_send_document_formating_caption(self):
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

Expand Down

0 comments on commit 8d8f234

Please sign in to comment.