mirror of
https://github.com/eternnoir/pyTelegramBotAPI.git
synced 2023-08-10 21:12:57 +03:00
Created util.py to clean up __init__.py and apihelper.py and updated README accordingly
Fixed failing send_document_by_id and send_photo_by_id
This commit is contained in:
parent
6f34a22c4b
commit
3c8faa155f
@ -282,7 +282,7 @@ To enable this behaviour, create an instance of AsyncTeleBot instead of TeleBot.
|
||||
```python
|
||||
tb = telebot.AsyncTeleBot("TOKEN")
|
||||
```
|
||||
Now, every function that calls the Telegram API is executed in a separate Thread. The functions are modified to return an AsyncTask instance (defined in \__init__.py). Using AsyncTeleBot allows you to do the following:
|
||||
Now, every function that calls the Telegram API is executed in a separate Thread. The functions are modified to return an AsyncTask instance (defined in util.py). Using AsyncTeleBot allows you to do the following:
|
||||
```python
|
||||
import telebot
|
||||
|
||||
@ -300,12 +300,12 @@ result = task.wait() # Get the result of the execution
|
||||
### Sending large text messages
|
||||
Sometimes you must send messages that exceed 5000 characters. The Telegram API can not handle that many characters in one request, so we need to split the message in multiples. Here is how to do that using the API:
|
||||
```python
|
||||
from telebot import apihelper
|
||||
from telebot import util
|
||||
large_text = open("large_text.txt", "rb").read()
|
||||
|
||||
# Split the text each 3000 characters.
|
||||
# split_string returns a list with the splitted text.
|
||||
splitted_text = apihelper.split_string(large_text, 3000)
|
||||
splitted_text = util.split_string(large_text, 3000)
|
||||
for text in splitted_text:
|
||||
tb.send_message(chat_id, text)
|
||||
```
|
||||
|
@ -2,18 +2,14 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import threading
|
||||
# Python3 queue support.
|
||||
try:
|
||||
import Queue
|
||||
except ImportError:
|
||||
import queue as Queue
|
||||
import time
|
||||
|
||||
import logging
|
||||
logging.basicConfig()
|
||||
logger = logging.getLogger('Telebot')
|
||||
import re
|
||||
from telebot import apihelper, types
|
||||
|
||||
from telebot import apihelper, types, util
|
||||
|
||||
"""
|
||||
Module : telebot
|
||||
@ -21,48 +17,6 @@ Module : telebot
|
||||
|
||||
API_URL = r"https://api.telegram.org/"
|
||||
|
||||
|
||||
class ThreadPool:
|
||||
class WorkerThread(threading.Thread):
|
||||
count = 0
|
||||
|
||||
def __init__(self, queue):
|
||||
threading.Thread.__init__(self, name="WorkerThread{0}".format(self.__class__.count + 1))
|
||||
self.__class__.count += 1
|
||||
self.queue = queue
|
||||
self.daemon = True
|
||||
|
||||
self._running = True
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while self._running:
|
||||
try:
|
||||
task, args, kwargs = self.queue.get()
|
||||
task(*args, **kwargs)
|
||||
except Queue.Empty:
|
||||
time.sleep(0)
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
self._running = False
|
||||
|
||||
def __init__(self, num_threads=4):
|
||||
self.tasks = Queue.Queue()
|
||||
self.workers = [self.WorkerThread(self.tasks) for _ in range(num_threads)]
|
||||
|
||||
self.num_threads = num_threads
|
||||
|
||||
def put(self, func, *args, **kwargs):
|
||||
self.tasks.put((func, args, kwargs))
|
||||
|
||||
def close(self):
|
||||
for worker in self.workers:
|
||||
worker.stop()
|
||||
for worker in self.workers:
|
||||
worker.join()
|
||||
|
||||
|
||||
class TeleBot:
|
||||
""" This is TeleBot Class
|
||||
Methods:
|
||||
@ -82,7 +36,6 @@ class TeleBot:
|
||||
|
||||
def __init__(self, token, create_threads=True, num_threads=4):
|
||||
"""
|
||||
|
||||
:param token: bot API token
|
||||
:param create_threads: Create thread for message handler
|
||||
:param num_threads: Number of worker in thread pool.
|
||||
@ -104,7 +57,7 @@ class TeleBot:
|
||||
|
||||
self.message_handlers = []
|
||||
if self.__create_threads:
|
||||
self.worker_pool = ThreadPool(num_threads)
|
||||
self.worker_pool = util.ThreadPool(num_threads)
|
||||
|
||||
def get_update(self):
|
||||
"""
|
||||
@ -158,7 +111,6 @@ class TeleBot:
|
||||
if block:
|
||||
self.__stop_polling.wait()
|
||||
|
||||
|
||||
def __polling(self, none_stop, interval):
|
||||
logger.info('TeleBot: Started polling.')
|
||||
|
||||
@ -249,7 +201,7 @@ class TeleBot:
|
||||
:param duration:Duration of the audio in seconds
|
||||
:param performer:Performer
|
||||
:param title:Track name
|
||||
:param reply_to_message_id:If the message is a reply, ID of the original messag
|
||||
:param reply_to_message_id:If the message is a reply, ID of the original message
|
||||
:param reply_markup:
|
||||
:return: Message
|
||||
"""
|
||||
@ -438,7 +390,7 @@ class TeleBot:
|
||||
if message.content_type not in message_handler['content_types']:
|
||||
return False
|
||||
if 'commands' in message_handler and message.content_type == 'text':
|
||||
return apihelper.extract_command(message.text) in message_handler['commands']
|
||||
return util.extract_command(message.text) in message_handler['commands']
|
||||
if 'regexp' in message_handler and message.content_type == 'text' and re.search(message_handler['regexp'],
|
||||
message.text):
|
||||
return True
|
||||
@ -452,93 +404,55 @@ class TeleBot:
|
||||
if self._test_message_handler(message_handler, message):
|
||||
if self.__create_threads:
|
||||
self.worker_pool.put(message_handler['function'], message)
|
||||
# t = threading.Thread(target=message_handler['function'], args=(message,))
|
||||
# t.start()
|
||||
else:
|
||||
message_handler['function'](message)
|
||||
break
|
||||
|
||||
|
||||
class AsyncTask:
|
||||
def __init__(self, target, *args, **kwargs):
|
||||
self.target = target
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
self.done = False
|
||||
self.thread = threading.Thread(target=self._run)
|
||||
self.thread.start()
|
||||
|
||||
def _run(self):
|
||||
try:
|
||||
self.result = self.target(*self.args, **self.kwargs)
|
||||
except Exception as e:
|
||||
self.result = e
|
||||
self.done = True
|
||||
|
||||
def wait(self):
|
||||
if not self.done:
|
||||
self.thread.join()
|
||||
if isinstance(self.result, Exception):
|
||||
raise self.result
|
||||
else:
|
||||
return self.result
|
||||
|
||||
|
||||
def async():
|
||||
def decorator(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
return AsyncTask(fn, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
class AsyncTeleBot(TeleBot):
|
||||
def __init__(self, *args, **kwargs):
|
||||
TeleBot.__init__(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def get_me(self):
|
||||
return TeleBot.get_me(self)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def get_user_profile_photos(self, *args, **kwargs):
|
||||
return TeleBot.get_user_profile_photos(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def send_message(self, *args, **kwargs):
|
||||
return TeleBot.send_message(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def forward_message(self, *args, **kwargs):
|
||||
return TeleBot.forward_message(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def send_photo(self, *args, **kwargs):
|
||||
return TeleBot.send_photo(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def send_audio(self, *args, **kwargs):
|
||||
return TeleBot.send_audio(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def send_document(self, *args, **kwargs):
|
||||
return TeleBot.send_document(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def send_sticker(self, *args, **kwargs):
|
||||
return TeleBot.send_sticker(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def send_video(self, *args, **kwargs):
|
||||
return TeleBot.send_video(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def send_location(self, *args, **kwargs):
|
||||
return TeleBot.send_location(self, *args, **kwargs)
|
||||
|
||||
@async()
|
||||
@util.async()
|
||||
def send_chat_action(self, *args, **kwargs):
|
||||
return TeleBot.send_chat_action(self, *args, **kwargs)
|
||||
|
@ -1,9 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import requests
|
||||
from six import string_types
|
||||
import telebot
|
||||
from telebot import types
|
||||
from telebot import util
|
||||
|
||||
logger = telebot.logger
|
||||
|
||||
@ -115,7 +115,7 @@ def send_photo(token, chat_id, photo, caption=None, reply_to_message_id=None, re
|
||||
method_url = r'sendPhoto'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
if not is_string(photo):
|
||||
if not util.is_string(photo):
|
||||
files = {'photo': photo}
|
||||
else:
|
||||
payload['photo'] = photo
|
||||
@ -148,7 +148,7 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
|
||||
method_url = r'sendVideo'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
if not is_string(data):
|
||||
if not util.is_string(data):
|
||||
files = {'video': data}
|
||||
else:
|
||||
payload['video'] = data
|
||||
@ -167,7 +167,7 @@ def send_voice(token, chat_id, voice, duration=None, reply_to_message_id=None, r
|
||||
method_url = r'sendVoice'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
if not is_string(voice):
|
||||
if not util.is_string(voice):
|
||||
files = {'voice': voice}
|
||||
else:
|
||||
payload['voice'] = voice
|
||||
@ -185,7 +185,7 @@ def send_audio(token, chat_id, audio, duration=None, performer=None, title=None,
|
||||
method_url = r'sendAudio'
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
if not is_string(audio):
|
||||
if not util.is_string(audio):
|
||||
files = {'audio': audio}
|
||||
else:
|
||||
payload['audio'] = audio
|
||||
@ -206,7 +206,7 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
|
||||
method_url = get_method_by_type(data_type)
|
||||
payload = {'chat_id': chat_id}
|
||||
files = None
|
||||
if not is_string(data):
|
||||
if not util.is_string(data):
|
||||
files = {data_type: data}
|
||||
else:
|
||||
payload[data_type] = data
|
||||
@ -229,49 +229,6 @@ def _convert_markup(markup):
|
||||
return markup.to_json()
|
||||
return markup
|
||||
|
||||
|
||||
def is_string(var):
|
||||
return isinstance(var, string_types)
|
||||
|
||||
|
||||
def is_command(text):
|
||||
"""
|
||||
Checks if `text` is a command. Telegram chat commands start with the '/' character.
|
||||
:param text: Text to check.
|
||||
:return: True if `text` is a command, else False.
|
||||
"""
|
||||
return text.startswith('/')
|
||||
|
||||
|
||||
def extract_command(text):
|
||||
"""
|
||||
Extracts the command from `text` (minus the '/') if `text` is a command (see is_command).
|
||||
If `text` is not a command, this function returns None.
|
||||
|
||||
Examples:
|
||||
extract_command('/help'): 'help'
|
||||
extract_command('/help@BotName'): 'help'
|
||||
extract_command('/search black eyed peas'): 'search'
|
||||
extract_command('Good day to you'): None
|
||||
|
||||
:param text: String to extract the command from
|
||||
:return: the command if `text` is a command (according to is_command), else None.
|
||||
"""
|
||||
return text.split()[0].split('@')[0][1:] if is_command(text) else None
|
||||
|
||||
|
||||
def split_string(text, chars_per_string):
|
||||
"""
|
||||
Splits one string into multiple strings, with a maximum amount of `chars_per_string` characters per string.
|
||||
This is very useful for splitting one giant message into multiples.
|
||||
|
||||
:param text: The text to split
|
||||
:param chars_per_string: The number of characters per line the text is split into.
|
||||
:return: The splitted text as a list of strings.
|
||||
"""
|
||||
return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)]
|
||||
|
||||
|
||||
class ApiException(Exception):
|
||||
"""
|
||||
This class represents an Exception thrown when a call to the Telegram API fails.
|
||||
|
@ -28,7 +28,6 @@ class JsonSerializable:
|
||||
Subclasses of this class are guaranteed to be able to be converted to JSON format.
|
||||
All subclasses of this class must override to_json.
|
||||
"""
|
||||
|
||||
def to_json(self):
|
||||
"""
|
||||
Returns a JSON string representation of this class.
|
||||
@ -44,7 +43,6 @@ class JsonDeserializable:
|
||||
Subclasses of this class are guaranteed to be able to be created from a json-style dict or json formatted string.
|
||||
All subclasses of this class must override de_json.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, json_type):
|
||||
"""
|
||||
|
126
telebot/util.py
Normal file
126
telebot/util.py
Normal file
@ -0,0 +1,126 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import threading
|
||||
from six import string_types
|
||||
|
||||
# Python3 queue support.
|
||||
try:
|
||||
import Queue
|
||||
except ImportError:
|
||||
import queue as Queue
|
||||
|
||||
|
||||
class ThreadPool:
|
||||
class WorkerThread(threading.Thread):
|
||||
count = 0
|
||||
|
||||
def __init__(self, queue):
|
||||
threading.Thread.__init__(self, name="WorkerThread{0}".format(self.__class__.count + 1))
|
||||
self.__class__.count += 1
|
||||
self.queue = queue
|
||||
self.daemon = True
|
||||
|
||||
self._running = True
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while self._running:
|
||||
try:
|
||||
task, args, kwargs = self.queue.get(block=True, timeout=.01)
|
||||
task(*args, **kwargs)
|
||||
except Queue.Empty:
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
self._running = False
|
||||
|
||||
def __init__(self, num_threads=4):
|
||||
self.tasks = Queue.Queue()
|
||||
self.workers = [self.WorkerThread(self.tasks) for _ in range(num_threads)]
|
||||
|
||||
self.num_threads = num_threads
|
||||
|
||||
def put(self, func, *args, **kwargs):
|
||||
self.tasks.put((func, args, kwargs))
|
||||
|
||||
def close(self):
|
||||
for worker in self.workers:
|
||||
worker.stop()
|
||||
for worker in self.workers:
|
||||
worker.join()
|
||||
|
||||
class AsyncTask:
|
||||
def __init__(self, target, *args, **kwargs):
|
||||
self.target = target
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
self.done = False
|
||||
self.thread = threading.Thread(target=self._run)
|
||||
self.thread.start()
|
||||
|
||||
def _run(self):
|
||||
try:
|
||||
self.result = self.target(*self.args, **self.kwargs)
|
||||
except Exception as e:
|
||||
self.result = e
|
||||
self.done = True
|
||||
|
||||
def wait(self):
|
||||
if not self.done:
|
||||
self.thread.join()
|
||||
if isinstance(self.result, Exception):
|
||||
raise self.result
|
||||
else:
|
||||
return self.result
|
||||
|
||||
|
||||
def async():
|
||||
def decorator(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
return AsyncTask(fn, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def is_string(var):
|
||||
return isinstance(var, string_types)
|
||||
|
||||
def is_command(text):
|
||||
"""
|
||||
Checks if `text` is a command. Telegram chat commands start with the '/' character.
|
||||
:param text: Text to check.
|
||||
:return: True if `text` is a command, else False.
|
||||
"""
|
||||
return text.startswith('/')
|
||||
|
||||
|
||||
def extract_command(text):
|
||||
"""
|
||||
Extracts the command from `text` (minus the '/') if `text` is a command (see is_command).
|
||||
If `text` is not a command, this function returns None.
|
||||
|
||||
Examples:
|
||||
extract_command('/help'): 'help'
|
||||
extract_command('/help@BotName'): 'help'
|
||||
extract_command('/search black eyed peas'): 'search'
|
||||
extract_command('Good day to you'): None
|
||||
|
||||
:param text: String to extract the command from
|
||||
:return: the command if `text` is a command (according to is_command), else None.
|
||||
"""
|
||||
return text.split()[0].split('@')[0][1:] if is_command(text) else None
|
||||
|
||||
|
||||
def split_string(text, chars_per_string):
|
||||
"""
|
||||
Splits one string into multiple strings, with a maximum amount of `chars_per_string` characters per string.
|
||||
This is very useful for splitting one giant message into multiples.
|
||||
|
||||
:param text: The text to split
|
||||
:param chars_per_string: The number of characters per line the text is split into.
|
||||
:return: The splitted text as a list of strings.
|
||||
"""
|
||||
return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)]
|
@ -9,6 +9,7 @@ import os
|
||||
import telebot
|
||||
from telebot import types
|
||||
from telebot import apihelper
|
||||
from telebot import util
|
||||
|
||||
should_skip = 'TOKEN' and 'CHAT_ID' not in os.environ
|
||||
|
||||
@ -67,18 +68,15 @@ class TestTeleBot:
|
||||
time.sleep(1)
|
||||
assert not msg.text == 'got'
|
||||
|
||||
def test_send_file_by_id(self):
|
||||
file_id = 'BQADBQADjAIAAsYifgbvqwq1he9REAI'
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_document(CHAT_ID, file_id)
|
||||
assert ret_msg.message_id
|
||||
|
||||
def test_send_file(self):
|
||||
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_document(CHAT_ID, file_data)
|
||||
assert ret_msg.message_id
|
||||
|
||||
ret_msg = tb.send_document(CHAT_ID, ret_msg.document.file_id)
|
||||
assert ret_msg.message_id
|
||||
|
||||
def test_send_video(self):
|
||||
file_data = open('./test_data/test_video.mp4', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
@ -100,18 +98,15 @@ class TestTeleBot:
|
||||
print(e)
|
||||
assert True
|
||||
|
||||
def test_send_photo_by_id(self):
|
||||
photo_id = 'AgADBQADTKgxG8YifgbcWQAB7Da9yYIx1rEyAAT-HYJ3CrJEqdA2AQABAg'
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_photo(CHAT_ID, photo_id)
|
||||
assert ret_msg.message_id
|
||||
|
||||
def test_send_photo(self):
|
||||
file_data = open('../examples/detailed_example/kitten.jpg', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
ret_msg = tb.send_photo(CHAT_ID, file_data)
|
||||
assert ret_msg.message_id
|
||||
|
||||
ret_msg = tb.send_photo(CHAT_ID, ret_msg.photo[0].file_id)
|
||||
assert ret_msg.message_id
|
||||
|
||||
def test_send_audio(self):
|
||||
file_data = open('./test_data/record.mp3', 'rb')
|
||||
tb = telebot.TeleBot(TOKEN)
|
||||
@ -174,12 +169,12 @@ class TestTeleBot:
|
||||
|
||||
def test_is_string_unicode(self):
|
||||
s1 = u'string'
|
||||
assert apihelper.is_string(s1)
|
||||
assert util.is_string(s1)
|
||||
|
||||
def test_is_string_string(self):
|
||||
s1 = 'string'
|
||||
assert apihelper.is_string(s1)
|
||||
assert util.is_string(s1)
|
||||
|
||||
def test_not_string(self):
|
||||
i1 = 10
|
||||
assert not apihelper.is_string(i1)
|
||||
assert not util.is_string(i1)
|
||||
|
Loading…
Reference in New Issue
Block a user