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

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Badiboy 2020-09-22 01:34:55 +03:00
commit 29711e2425
5 changed files with 117 additions and 36 deletions

View File

@ -663,5 +663,6 @@ Get help. Discuss. Chat.
* [RandomInfoBot](https://t.me/RandomInfoBot) by [@Akash](https://github.com/BLUE-DEVIL1134) - A Telegram Bot Which Generates Random Information Of Humans Scraped From Over 13 Websites.
* [TasksListsBot](https://t.me/TasksListsBot) ([source](https://github.com/Pablo-Davila/TasksListsBot)) by [@Pablo-Davila](https://github.com/Pablo-Davila) - A (tasks) lists manager bot for Telegram.
* [MyElizaPsychologistBot](https://t.me/TasksListsBot) ([source](https://github.com/Pablo-Davila/MyElizaPsychologistBot)) by [@Pablo-Davila](https://github.com/Pablo-Davila) - An implementation of the famous Eliza psychologist chatbot.
* [Evdembot](https://t.me/Evdembot) by Adem Kavak. A bot that informs you about everything you want.
Want to have your bot listed here? Send a Telegram message to @eternnoir or @pevdh.

View File

@ -93,7 +93,7 @@ class TeleBot:
def __init__(
self, token, parse_mode=None, threaded=True, skip_pending=False, num_threads=2,
next_step_backend=None, reply_backend=None, exception_handler=None
next_step_backend=None, reply_backend=None, exception_handler=None, last_update_id=0
):
"""
:param token: bot API token
@ -107,7 +107,7 @@ class TeleBot:
self.skip_pending = skip_pending
self.__stop_polling = threading.Event()
self.last_update_id = 0
self.last_update_id = last_update_id
self.exc_info = None
self.next_step_backend = next_step_backend

View File

@ -385,6 +385,8 @@ class Message(JsonDeserializable):
if 'passport_data' in obj:
opts['passport_data'] = obj['passport_data']
content_type = 'passport_data'
if 'reply_markup' in obj:
opts['reply_markup'] = InlineKeyboardMarkup.de_json(obj['reply_markup'])
return cls(message_id, from_user, date, chat, content_type, opts, json_string)
@classmethod
@ -455,6 +457,7 @@ class Message(JsonDeserializable):
self.invoice = None
self.successful_payment = None
self.connected_website = None
self.reply_markup = None
for key in options:
setattr(self, key, options[key])
self.json = json_string
@ -586,13 +589,15 @@ class PhotoSize(JsonDeserializable):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
file_unique_id = obj['file_unique_id']
width = obj['width']
height = obj['height']
file_size = obj.get('file_size')
return cls(file_id, width, height, file_size)
return cls(file_id, file_unique_id, width, height, file_size)
def __init__(self, file_id, width, height, file_size=None):
def __init__(self, file_id, file_unique_id, width, height, file_size=None):
self.file_size = file_size
self.file_unique_id = file_unique_id
self.height = height
self.width = width
self.file_id = file_id
@ -604,15 +609,17 @@ class Audio(JsonDeserializable):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
file_unique_id = obj['file_unique_id']
duration = obj['duration']
performer = obj.get('performer')
title = obj.get('title')
mime_type = obj.get('mime_type')
file_size = obj.get('file_size')
return cls(file_id, duration, performer, title, mime_type, file_size)
return cls(file_id, file_unique_id, duration, performer, title, mime_type, file_size)
def __init__(self, file_id, duration, performer=None, title=None, mime_type=None, file_size=None):
def __init__(self, file_id, file_unique_id, duration, performer=None, title=None, mime_type=None, file_size=None):
self.file_id = file_id
self.file_unique_id = file_unique_id
self.duration = duration
self.performer = performer
self.title = title
@ -626,13 +633,15 @@ class Voice(JsonDeserializable):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
file_unique_id = obj['file_unique_id']
duration = obj['duration']
mime_type = obj.get('mime_type')
file_size = obj.get('file_size')
return cls(file_id, duration, mime_type, file_size)
return cls(file_id, file_unique_id, duration, mime_type, file_size)
def __init__(self, file_id, duration, mime_type=None, file_size=None):
def __init__(self, file_id, file_unique_id, duration, mime_type=None, file_size=None):
self.file_id = file_id
self.file_unique_id = file_unique_id
self.duration = duration
self.mime_type = mime_type
self.file_size = file_size
@ -644,16 +653,18 @@ class Document(JsonDeserializable):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
file_unique_id = obj['file_unique_id']
thumb = None
if 'thumb' in obj and 'file_id' in obj['thumb']:
thumb = PhotoSize.de_json(obj['thumb'])
file_name = obj.get('file_name')
mime_type = obj.get('mime_type')
file_size = obj.get('file_size')
return cls(file_id, thumb, file_name, mime_type, file_size)
return cls(file_id, file_unique_id, thumb, file_name, mime_type, file_size)
def __init__(self, file_id, thumb=None, file_name=None, mime_type=None, file_size=None):
def __init__(self, file_id, file_unique_id, thumb=None, file_name=None, mime_type=None, file_size=None):
self.file_id = file_id
self.file_unique_id = file_unique_id
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type
@ -667,16 +678,18 @@ class Video(JsonDeserializable):
return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
file_unique_id = obj['file_unique_id']
width = obj['width']
height = obj['height']
duration = obj['duration']
thumb = PhotoSize.de_json(obj.get('thumb'))
mime_type = obj.get('mime_type')
file_size = obj.get('file_size')
return cls(file_id, width, height, duration, thumb, mime_type, file_size)
return cls(file_id, file_unique_id, width, height, duration, thumb, mime_type, file_size)
def __init__(self, file_id, width, height, duration, thumb=None, mime_type=None, file_size=None):
def __init__(self, file_id, file_unique_id, width, height, duration, thumb=None, mime_type=None, file_size=None):
self.file_id = file_id
self.file_unique_id = file_unique_id
self.width = width
self.height = height
self.duration = duration
@ -692,14 +705,16 @@ class VideoNote(JsonDeserializable):
return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
file_unique_id = obj['file_unique_id']
length = obj['length']
duration = obj['duration']
thumb = PhotoSize.de_json(obj.get('thumb'))
file_size = obj.get('file_size')
return cls(file_id, length, duration, thumb, file_size)
return cls(file_id, file_unique_id, length, duration, thumb, file_size)
def __init__(self, file_id, length, duration, thumb=None, file_size=None):
def __init__(self, file_id, file_unique_id, length, duration, thumb=None, file_size=None):
self.file_id = file_id
self.file_unique_id = file_unique_id
self.length = length
self.duration = duration
self.thumb = thumb
@ -785,12 +800,14 @@ class File(JsonDeserializable):
return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
file_unique_id = obj['file_unique_id']
file_size = obj.get('file_size')
file_path = obj.get('file_path')
return cls(file_id, file_size, file_path)
return cls(file_id, file_unique_id, file_size, file_path)
def __init__(self, file_id, file_size, file_path):
def __init__(self, file_id, file_unique_id, file_size, file_path):
self.file_id = file_id
self.file_unique_id = file_unique_id
self.file_size = file_size
self.file_path = file_path
@ -923,10 +940,18 @@ class KeyboardButtonPollType(Dictionaryable):
return {'type': self.type}
class InlineKeyboardMarkup(Dictionaryable, JsonSerializable):
class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable):
max_row_keys = 8
@classmethod
def de_json(cls, json_string):
if (json_string is None):
return None
obj = cls.check_json(json_string)
keyboard = [[InlineKeyboardButton.de_json(button) for button in row] for row in obj['inline_keyboard']]
return cls(keyboard)
def __init__(self, row_width=3):
def __init__(self, keyboard=[] ,row_width=3):
"""
This object represents an inline keyboard that appears
right next to the message it belongs to.
@ -939,7 +964,7 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable):
row_width = self.max_row_keys
self.row_width = row_width
self.keyboard = []
self.keyboard = keyboard
def add(self, *args, row_width=None):
"""
@ -965,7 +990,7 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable):
row_width = self.max_row_keys
for row in util.chunks(args, row_width):
button_array = [button.to_dict() for button in row]
button_array = [button for button in row]
self.keyboard.append(button_array)
return self
@ -995,16 +1020,28 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable):
return json.dumps(self.to_dict())
def to_dict(self):
json_dict = {'inline_keyboard': self.keyboard}
json_dict = dict()
json_dict['inline_keyboard'] = [[button.to_dict() for button in row] for row in self.keyboard]
return json_dict
class LoginUrl(Dictionaryable, JsonSerializable):
class LoginUrl(Dictionaryable, JsonSerializable, JsonDeserializable):
def __init__(self, url, forward_text=None, bot_username=None, request_write_access=None):
self.url = url
self.forward_text = forward_text
self.bot_username = bot_username
self.request_write_access = request_write_access
@classmethod
def de_json(cls, json_string):
if (json_string is None):
return None
obj = cls.check_json(json_string)
url = obj['url']
forward_text = obj.get('forward_text')
bot_username = obj.get('bot_username')
request_write_access = obj.get('request_write_access')
return cls(url, forward_text, bot_username, request_write_access)
def to_json(self):
return json.dumps(self.to_dict())
@ -1020,7 +1057,7 @@ class LoginUrl(Dictionaryable, JsonSerializable):
return json_dict
class InlineKeyboardButton(Dictionaryable, JsonSerializable):
class InlineKeyboardButton(Dictionaryable, JsonSerializable, JsonDeserializable):
def __init__(self, text, url=None, callback_data=None, switch_inline_query=None,
switch_inline_query_current_chat=None, callback_game=None, pay=None, login_url=None):
self.text = text
@ -1031,6 +1068,21 @@ class InlineKeyboardButton(Dictionaryable, JsonSerializable):
self.callback_game = callback_game
self.pay = pay
self.login_url = login_url
@classmethod
def de_json(cls, json_string):
if (json_string is None):
return None
obj = cls.check_json(json_string)
text = obj['text']
url = obj.get('url')
callback_data = obj.get('callback_data')
switch_inline_query = obj.get('switch_inline_query')
switch_inline_query_current_chat = obj.get('switch_inline_query_current_chat')
callback_game = obj.get('callback_game')
pay = obj.get('pay')
login_url = LoginUrl.de_json(obj.get('login_url'))
return cls(text, url, callback_data, switch_inline_query, switch_inline_query_current_chat, callback_game, pay, login_url)
def to_json(self):
return json.dumps(self.to_dict())
@ -1085,12 +1137,16 @@ class ChatPhoto(JsonDeserializable):
return None
obj = cls.check_json(json_string)
small_file_id = obj['small_file_id']
small_file_unique_id = obj['small_file_unique_id']
big_file_id = obj['big_file_id']
return cls(small_file_id, big_file_id)
big_file_unique_id = obj['big_file_unique_id']
return cls(small_file_id, small_file_unique_id, big_file_id, big_file_unique_id)
def __init__(self, small_file_id, big_file_id):
def __init__(self, small_file_id, small_file_unique_id, big_file_id, big_file_unique_id):
self.small_file_id = small_file_id
self.small_file_unique_id = small_file_unique_id
self.big_file_id = big_file_id
self.big_file_unique_id = big_file_unique_id
class ChatMember(JsonDeserializable):
@ -2034,14 +2090,16 @@ class Animation(JsonDeserializable):
if (json_string is None): return None
obj = cls.check_json(json_string)
file_id = obj['file_id']
file_unique_id = obj['file_unique_id']
thumb = PhotoSize.de_json(obj.get('thumb'))
file_name = obj.get('file_name')
mime_type = obj.get('mime_type')
file_size = obj.get('file_size')
return cls(file_id, thumb, file_name, mime_type, file_size)
return cls(file_id, file_unique_id, thumb, file_name, mime_type, file_size)
def __init__(self, file_id, thumb=None, file_name=None, mime_type=None, file_size=None):
def __init__(self, file_id, file_unique_id, thumb=None, file_name=None, mime_type=None, file_size=None):
self.file_id = file_id
self.file_unique_id = file_unique_id
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type

View File

@ -11,7 +11,7 @@ import queue as Queue
import logging
try:
import PIL
from PIL import Image
from io import BytesIO
pil_imported = True
except:
@ -164,7 +164,7 @@ def is_bytes(var):
return isinstance(var, bytes)
def is_pil_image(var):
return pil_imported and isinstance(var, PIL.Image.Image)
return pil_imported and isinstance(var, Image.Image)
def pil_image_to_file(image, extension='JPEG', quality='web_low'):
if pil_imported:

View File

@ -17,6 +17,28 @@ def test_json_message():
assert msg.text == 'HIHI'
def test_json_message_with_reply_markup():
jsonstring = r'{"message_id":48,"from":{"id":153587469,"is_bot":false,"first_name":"Neko","username":"Neko"},"chat":{"id":153587469,"first_name":"Neko","username":"Neko","type":"private"},"date":1598879570,"text":"test","reply_markup":{"inline_keyboard":[[{"text":"Google","url":"http://www.google.com"},{"text":"Yahoo","url":"http://www.yahoo.com"}]]}}'
msg = types.Message.de_json(jsonstring)
assert msg.content_type == 'text'
assert msg.reply_markup.keyboard[0][0].text == 'Google'
def test_json_InlineKeyboardMarkup():
jsonstring = r'{"inline_keyboard":[[{"text":"Google","url":"http://www.google.com"},{"text":"Yahoo","url":"http://www.yahoo.com"}]]}'
markup = types.InlineKeyboardMarkup.de_json(jsonstring)
assert markup.keyboard[0][0].text == 'Google'
assert markup.keyboard[0][1].url == 'http://www.yahoo.com'
def test_json_InlineKeyboardButton():
jsonstring = r'{"text":"Google","url":"http://www.google.com"}'
button = types.InlineKeyboardButton.de_json(jsonstring)
assert button.text == 'Google'
assert button.url == 'http://www.google.com'
def test_json_message_with_dice():
jsonstring = r'{"message_id":5560,"from":{"id":879343317,"is_bot":false,"first_name":"George","last_name":"Forse","username":"dr_fxrse","language_code":"ru"},"chat":{"id":879343317,"first_name":"George","last_name":"Forse","username":"dr_fxrse","type":"private"},"date":1586926330,"dice":{"value": 4, "emoji": "\ud83c\udfaf"}}'
msg = types.Message.de_json(jsonstring)
@ -41,14 +63,14 @@ def test_json_GroupChat():
def test_json_Document():
json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}'
json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}'
doc = types.Document.de_json(json_string)
assert doc.thumb is None
assert doc.file_name == 'Text File'
def test_json_Message_Audio():
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd","is_bot":true },"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_size":20096}}'
json_string = r'{"message_id":131,"from":{"id":12775,"first_name":"dd","username":"dd","is_bot":true },"chat":{"id":10834,"first_name":"dd","type":"private","type":"private","last_name":"dd","username":"dd"},"date":1439978364,"audio":{"duration":1,"mime_type":"audio\/mpeg","title":"pyTelegram","performer":"eternnoir","file_id":"BQADBQADDH1JaB8-1KyWUss2-Ag","file_unique_id": "AgADawEAAn8VSFY","file_size":20096}}'
msg = types.Message.de_json(json_string)
assert msg.audio.duration == 1
assert msg.content_type == 'audio'
@ -73,21 +95,21 @@ def test_json_Message_Sticker_without_thumb():
def test_json_Message_Document():
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_size":446}}'
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}'
msg = types.Message.de_json(json_string)
assert msg.document.file_name == 'Text File'
assert msg.content_type == 'document'
def test_json_Message_Photo():
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_size":53013,"width":759,"height":570}]}'
json_string = r'{"message_id":96,"from":{"id":109734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10734,"first_name":"Fd","type":"private","last_name":"dd","username":"dd"},"date":1435478191,"photo":[{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":615,"width":90,"height":67},{"file_id":"AgADBQADIagxG8YifgYv8yLSj76i-dd","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":10174,"width":320,"height":240},{"file_id":"dd-A_LsTIABFNx-FUOaEa_3AABAQABAg","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":53013,"width":759,"height":570}]}'
msg = types.Message.de_json(json_string)
assert len(msg.photo) == 3
assert msg.content_type == 'photo'
def test_json_Message_Video():
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_size":260699}}'
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}'
msg = types.Message.de_json(json_string)
assert msg.video
assert msg.video.duration == 3
@ -103,7 +125,7 @@ def test_json_Message_Location():
def test_json_UserProfilePhotos():
json_string = r'{"total_count":1,"photos":[[{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATZH_SpyZjzIwdVAAIC","file_size":6150,"width":160,"height":160},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATOiTNi_YoJMghVAAIC","file_size":13363,"width":320,"height":320},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAQW4DyFv0-lhglVAAIC","file_size":28347,"width":640,"height":640},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAT50RvJCg0GQApVAAIC","file_size":33953,"width":800,"height":800}]]}'
json_string = r'{"total_count":1,"photos":[[{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATZH_SpyZjzIwdVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":6150,"width":160,"height":160},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAATOiTNi_YoJMghVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":13363,"width":320,"height":320},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAQW4DyFv0-lhglVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":28347,"width":640,"height":640},{"file_id":"AgADAgADqacxG6wpRwABvEB6fpeIcKS4HAIkAAT50RvJCg0GQApVAAIC","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":33953,"width":800,"height":800}]]}'
upp = types.UserProfilePhotos.de_json(json_string)
assert upp.photos[0][0].width == 160
assert upp.photos[0][-1].height == 800
@ -117,7 +139,7 @@ def test_json_contact():
def test_json_voice():
json_string = r'{"duration": 0,"mime_type": "audio/ogg","file_id": "AwcccccccDH1JaB7w_gyFjYQxVAg","file_size": 10481}'
json_string = r'{"duration": 0,"mime_type": "audio/ogg","file_id": "AwcccccccDH1JaB7w_gyFjYQxVAg","file_unique_id": "AgADbAEAAn8VSFY","file_size": 10481}'
voice = types.Voice.de_json(json_string)
assert voice.duration == 0
assert voice.file_size == 10481