Compare commits

...

57 Commits

Author SHA1 Message Date
leandrotoledo d740ce89cf Keep off some features still in progress 2015-09-04 18:11:47 -03:00
leandrotoledo 245238b3a2 Keep off some features still in progress 2015-09-04 18:03:04 -03:00
Leandro Toledo e693922fe8 Merge pull request #54 from leandrotoledo/testing
Merge Testing branch
2015-09-04 17:59:37 -03:00
leandrotoledo 62f06da897 Move command_handler tests to tests/ folder 2015-09-04 17:54:30 -03:00
leandrotoledo 05b7fda4a1 Add certificate arg to setWebhook function 2015-09-04 17:53:39 -03:00
leandrotoledo 910959b672 Raises error when chat_id is not set 2015-09-04 17:15:44 -03:00
Leandro Toledo 881b0b3d06 Update README.rst 2015-09-02 13:23:11 -03:00
Leandro Toledo 95ecd44c0e Merge pull request #51 from njittam/testing
Adding command handler
2015-09-02 13:20:33 -03:00
njittam 9241534ba6 Create command_handler_example.py
this is an example of how to write a commandHandler
2015-09-02 16:21:11 +02:00
njittam 256d219862 A command handler
I saw in the TODO list on pypi that you wanted a commandhandler. 
I am not sure about the run and run_once commands.
and  I didn't implement logging yet.
2015-09-02 16:17:57 +02:00
njittam 8fddd3b027 test for commandHandler
Not everything has a test. and I'm quite new to unit testing so I'm not sure if I am doing this the right way.
2015-09-02 16:11:21 +02:00
njittam 3f3cb1edc5 Update AUTHORS.rst 2015-09-02 16:04:15 +02:00
Leandro Toledo f037a8c776 Update README.rst 2015-08-29 10:55:23 -03:00
Leandro Toledo 98c489c44f Fix Python 3 2015-08-28 17:53:31 -03:00
Leandro Toledo a86fc6c2ac Improving the design of existing Telegram classes 2015-08-28 17:45:44 -03:00
Leandro Toledo 1c4595123c Add improvements to tests 2015-08-28 13:28:58 -03:00
Leandro Toledo 942706e20f Add PyPy to travis 2015-08-28 13:09:47 -03:00
Leandro Toledo 6837bef9bb Fix tests for Py2.6 2015-08-28 13:07:12 -03:00
Leandro Toledo 6132e65dc3 Fix travis 2015-08-28 13:04:36 -03:00
Leandro Toledo 0f924508f7 Fix tests and minor changes 2015-08-28 13:02:02 -03:00
Leandro Toledo b20f5af1e1 Improving the design of existing Telegram classes and adding docstrings 2015-08-28 12:19:30 -03:00
Leandro Toledo ce58f72566 Merge branch 'testing' of https://github.com/leandrotoledo/python-telegram-bot into testing 2015-08-28 11:11:32 -03:00
Leandro Toledo f4839a3afe Merge pull request #47 from mASOUDd/testing
Extended the Bot class. Added a dispatching mechanism, and decorators to add commands.
2015-08-28 10:50:18 -03:00
Masoud Naservand 25f9eb7898 Extended the Bot class. Added a dispatching mechanism,
and decorators to add command to the bot the flask routing style, e.g:
>>> @bot.command('/start')
... def start(command, user_id):
...    return ('Hello, there', None, None)
2015-08-28 18:08:03 +04:30
Leandro Toledo c625b9a449 Update README.rst 2015-08-26 21:45:09 -03:00
Leandro Toledo e239315cca Merge pull request #46 from rahiel/master
add remaining chat actions
2015-08-25 11:22:03 -03:00
rahiel ccdb999e37 add remaining chat actions 2015-08-25 13:45:02 +02:00
Leandro Toledo 2f99b785b2 Merge pull request #45 from rahiel/master
use long polling in examples
2015-08-24 09:26:20 -03:00
rahiel 41eb45918c use long polling in examples 2015-08-24 11:46:33 +02:00
leandrotoledo d43e292499 Adding required comments 2015-08-21 23:22:58 -03:00
leandrotoledo fdb5f2339c Improving the design of existing Telegram classes and adding docstrings 2015-08-21 23:15:29 -03:00
leandrotoledo d03a394075 Refactoring, improving the design of existing message class and adding docstrings 2015-08-21 14:49:07 -03:00
Leandro Toledo 3658b4231c Update README.rst 2015-08-21 14:09:13 -03:00
leandrotoledo 1d6e9502cb Adding botan.io support 2015-08-20 21:07:49 -03:00
Leandro Toledo 92ca92341a Merge pull request #43 from rahiel/master
confirm processed message in examples
2015-08-20 15:49:21 -03:00
rahiel 0691b1e971 confirm processed message in examples 2015-08-20 19:58:57 +02:00
leandrotoledo 8746222cf6 Releasing v2.7.1 2015-08-19 16:16:06 -03:00
leandrotoledo 32dc05ed36 Fix lines too long 2015-08-19 16:08:03 -03:00
leandrotoledo ba5902c1d4 Fix serialization when message has reply_to_message, new_chat_participant or new_chat_photo #42 2015-08-19 15:41:09 -03:00
Leandro Toledo 80371c9f6e Merge branch 'master' of https://github.com/leandrotoledo/python-telegram-bot 2015-08-17 13:15:41 -03:00
Leandro Toledo a8fd6b5061 Releasing v2.7 2015-08-17 13:15:29 -03:00
Leandro Toledo 53f5911aad Update README.rst 2015-08-17 11:45:28 -03:00
Leandro Toledo d4870148c7 Add telegram.voice to docs and minor docstring fixes #39 2015-08-17 11:40:21 -03:00
Leandro Toledo 6e2881b31b Adding support for Voice object and sendVoice method #39 2015-08-17 11:34:42 -03:00
Leandro Toledo 686aecb914 Fix tests for Python 3 2015-08-17 10:01:17 -03:00
Leandro Toledo 35f31bf136 Merge branch 'master' of https://github.com/leandrotoledo/python-telegram-bot 2015-08-17 09:57:07 -03:00
Leandro Toledo 56f6845969 Adding is_json tests and fixes json serialization when a forwared message #38 2015-08-17 09:56:51 -03:00
Leandro Toledo 505df01ae1 Update AUTHORS.rst 2015-08-15 15:19:17 -03:00
Leandro Toledo 3be58b759f Releasing v2.6.1 2015-08-15 15:06:32 -03:00
Leandro Toledo 5dc1e4cac1 Use imghdr instead re to match image headers. Fixes #37 2015-08-15 15:00:28 -03:00
Leandro Toledo 2cecca8324 Releasing v2.6.0 2015-08-14 16:36:39 -03:00
Leandro Toledo 109439022f Minor fixes and cfg for setuptools 2015-08-14 16:30:30 -03:00
Leandro Toledo 59ff1b68b5 clearCredentians and require_authentication are now decapred, bot properties will be called when needed only #33 2015-08-14 16:25:27 -03:00
Leandro Toledo fda1843593 Remove import pdb 2015-08-14 15:48:33 -03:00
Leandro Toledo 9b6ccaf94b Convert unix timestamp from date and forward_date in messages to date object #35 2015-08-14 15:47:31 -03:00
Leandro Toledo ea1614631e Update and rename CONTRIBUTING to CONTRIBUTING.rst 2015-08-12 18:57:46 -03:00
Leandro Toledo 6bcc8cdcfd Update AUTHORS.rst 2015-08-12 18:44:40 -03:00
46 changed files with 1356 additions and 660 deletions
+3 -1
View File
@@ -4,9 +4,11 @@ python:
- "2.7"
- "3.3"
- "3.4"
- "pypy"
- "pypy3"
install:
- pip install coveralls
script:
coverage run telegram_test.py
coverage run tests/test_*.py
after_success:
coveralls
+22 -1
View File
@@ -1 +1,22 @@
* Leandro Toledo
Credits
=======
``python-telegram-bot`` is written and maintained by `Leandro Toledo <https://github.com/leandrotoledo>`_.
Contributors
------------
The following wonderful people contributed directly or indirectly to this project:
- `Avanatiker <https://github.com/Avanatiker>`_
- `bimmlerd <https://github.com/bimmlerd>`_
- `franciscod <https://github.com/franciscod>`_
- `JASON0916 <https://github.com/JASON0916>`_
- `JRoot3D <https://github.com/JRoot3D>`_
- `macrojames <https://github.com/macrojames>`_
- `njittam <https://github.com/njittam>`_
- `Rahiel Kasim <https://github.com/rahiel>`_
- `sooyhwang <https://github.com/sooyhwang>`_
- `wjt <https://github.com/wjt>`_
Please add yourself here alphabetically when you submit your first pull request.
+24
View File
@@ -1,3 +1,27 @@
2015-08-19
Released 2.7.1
Fixed JSON serialization for message
2015-08-17
Released 2.7
Added support for Voice object and sendVoice method
Due backward compatibility performer or/and title will be required for sendAudio
Fixed JSON serialization when forwarded message
2015-08-15
Released 2.6.1
Fixed parsing image header issue on < Python 2.7.3
2015-08-14
Released 2.6.0
Depreciation of require_authentication and clearCredentials methods
Giving AUTHORS the proper credits for their contribution for this project
Message.date and Message.forward_date are now datetime objects
2015-08-12
Released 2.5.3
telegram.Bot now supports to be unpickled
View File
+39
View File
@@ -0,0 +1,39 @@
How To Contribute
=================
Every open source project lives from the generous help by contributors that sacrifice their time and ``python-telegram-bot`` is no different.
To make participation as pleasant as possible, this project adheres to the `Code of Conduct`_ by the Python Software Foundation.
Here are a few guidelines to get you started:
- Add yourself to the AUTHORS.rst_ file in an alphabetical fashion.
Every contribution is valuable and shall be credited.
- If your change is noteworthy, add an entry to the CHANGES_.
- No contribution is too small; please submit as many fixes for typos and grammar bloopers as you can!
- Dont break backward compatibility.
- *Always* add tests and docs for your code.
This is a hard rule; patches with missing tests or documentation wont be merged.
If a feature is not tested or documented, it doesnt exist.
- Obey `PEP 8`_ and `PEP 257`_.
- Follow `Google Python Style Guide`_ and `Google Python Style Docstrings`_.
- Write `good commit messages`_.
.. note::
If you have something great but arent sure whether it adheres -- or even can adhere -- to the rules above: **please submit a pull request anyway**!
In the best case, we can mold it into something, in the worst case the pull request gets politely closed.
Theres absolutely nothing to fear.
Thank you for considering to contribute to ``python-telegram-bot``!
If you have any question or concerns, feel free to reach out to me.
.. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/
.. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/
.. _`good commit messages`: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
.. _`Code of Conduct`: https://www.python.org/psf/codeofconduct/
.. _`Google Python Style Guide`: https://google-styleguide.googlecode.com/svn/trunk/pyguide.html
.. _`Google Python Style Docstrings`: http://sphinx-doc.org/latest/ext/example_google.html
.. _CHANGES: https://github.com/leandrotoledo/python-telegram-bot/blob/master/CHANGES
.. _AUTHORS.rst: https://github.com/leandrotoledo/python-telegram-bot/blob/master/AUTHORS.rst
+13 -6
View File
@@ -1,7 +1,4 @@
help:
@echo " clean remove unwanted stuff"
@echo " lint check style with flake8"
@echo " test run tests"
.PHONY: clean pep8 lint test
clean:
rm -fr build
@@ -10,8 +7,18 @@ clean:
find . -name '*.pyo' -exec rm -f {} \;
find . -name '*~' -exec rm -f {} \;
pep8:
flake8 telegram
lint:
flake8 --doctests --max-complexity 10 telegram
pylint -E telegram
test:
python telegram_test.py
@- $(foreach TEST, $(wildcard tests/test_*.py), python $(TEST))
help:
@echo "Available targets:"
@echo "- clean Clean up the source directory"
@echo "- pep8 Check style with flake8"
@echo "- lint Check style with pylint"
@echo "- test Run tests"
+6 -3
View File
@@ -89,6 +89,7 @@ sendAudio Yes
sendDocument Yes
sendSticker Yes
sendVideo Yes
sendVoice Yes
sendLocation Yes
sendChatAction Yes
getUpdates Yes
@@ -194,9 +195,9 @@ To post an image file via URL (right now only sendPhoto supports this)::
>>> bot.sendPhoto(chat_id=chat_id, photo='https://telegram.org/img/t_logo.png')
To post an audio file::
To post a voice file::
>>> bot.sendAudio(chat_id=chat_id, audio=open('tests/telegram.ogg', 'rb'))
>>> bot.sendVoice(chat_id=chat_id, voice=open('tests/telegram.ogg', 'rb'))
To tell the user that something is happening on bot's side::
@@ -261,7 +262,9 @@ You may copy, distribute and modify the software provided that modifications are
_`Contact`
==========
Feel free to join to our `Telegram group <https://telegram.me/joinchat/00b9c0f802509b949c1563d56eb053b0>`_.
Feel free to join to our `Telegram group <https://telegram.me/joinchat/00b9c0f802509b94d52953d3fa1ec504>`_.
*If you face trouble joining in the group please ping me on Telegram (@leandrotoledo), I'll be glad to add you.*
=======
_`TODO`
@@ -1,2 +1,3 @@
sphinx
sphinx_rtd_theme
sphinx-pypi-upload
+1
View File
@@ -29,6 +29,7 @@ Submodules
telegram.user
telegram.userprofilephotos
telegram.video
telegram.voice
Module contents
---------------
+7
View File
@@ -0,0 +1,7 @@
telegram.voice module
=====================
.. automodule:: telegram.voice
:members:
:undoc-members:
:show-inheritance:
+11 -14
View File
@@ -19,7 +19,6 @@
import logging
import telegram
import time
LAST_UPDATE_ID = None
@@ -43,26 +42,24 @@ def main():
while True:
echo(bot)
time.sleep(3)
def echo(bot):
global LAST_UPDATE_ID
# Request updates from last updated_id
for update in bot.getUpdates(offset=LAST_UPDATE_ID):
if LAST_UPDATE_ID < update.update_id:
# chat_id is required to reply any message
chat_id = update.message.chat_id
message = update.message.text.encode('utf-8')
# Request updates after the last updated_id
for update in bot.getUpdates(offset=LAST_UPDATE_ID, timeout=10):
# chat_id is required to reply any message
chat_id = update.message.chat_id
message = update.message.text.encode('utf-8')
if (message):
# Reply the message
bot.sendMessage(chat_id=chat_id,
text=message)
if (message):
# Reply the message
bot.sendMessage(chat_id=chat_id,
text=message)
# Updates global offset to get the new updates
LAST_UPDATE_ID = update.update_id
# Updates global offset to get the new updates
LAST_UPDATE_ID = update.update_id + 1
if __name__ == '__main__':
+5 -7
View File
@@ -33,17 +33,15 @@ def main():
LAST_UPDATE_ID = bot.getUpdates()[-1].update_id # Get lastest update
while True:
for update in bot.getUpdates(offset=LAST_UPDATE_ID):
for update in bot.getUpdates(offset=LAST_UPDATE_ID, timeout=10):
text = update.message.text
chat_id = update.message.chat.id
update_id = update.update_id
if LAST_UPDATE_ID < update_id: # If newer than the initial
# LAST_UPDATE_ID
if text:
roboed = ed(text) # Ask something to Robô Ed
bot.sendMessage(chat_id=chat_id, text=roboed)
LAST_UPDATE_ID = update_id
if text:
roboed = ed(text) # Ask something to Robô Ed
bot.sendMessage(chat_id=chat_id, text=roboed)
LAST_UPDATE_ID = update_id + 1
def ed(text):
+6 -1
View File
@@ -1,5 +1,10 @@
[wheel]
universal = 1
[upload_docs]
[build_sphinx]
source-dir = docs/source
build-dir = docs/build
all_files = 1
[upload_sphinx]
upload-dir = docs/build/html
+1 -1
View File
@@ -15,7 +15,7 @@ def read(*paths):
setup(
name='python-telegram-bot',
version='2.5.3',
version='2.7.1',
author='Leandro Toledo',
author_email='leandrotoledodesouza@gmail.com',
license='LGPLv3',
+8 -5
View File
@@ -16,17 +16,17 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""A library that provides a Python interface to the Telegram Bot API"""
__author__ = 'leandrotoledodesouza@gmail.com'
__version__ = '2.5.3'
__version__ = '2.7.1'
from .base import TelegramObject
from .user import User
from .message import Message
from .update import Update
from .groupchat import GroupChat
from .photosize import PhotoSize
from .audio import Audio
from .voice import Voice
from .document import Document
from .sticker import Sticker
from .video import Video
@@ -38,14 +38,17 @@ from .replymarkup import ReplyMarkup
from .replykeyboardmarkup import ReplyKeyboardMarkup
from .replykeyboardhide import ReplyKeyboardHide
from .forcereply import ForceReply
from .inputfile import InputFile
from .error import TelegramError
from .inputfile import InputFile
from .nullhandler import NullHandler
from .emoji import Emoji
from .message import Message
from .update import Update
from .bot import Bot
__all__ = ['Bot', 'Emoji', 'TelegramError', 'InputFile', 'ReplyMarkup',
'ForceReply', 'ReplyKeyboardHide', 'ReplyKeyboardMarkup',
'UserProfilePhotos', 'ChatAction', 'Location', 'Contact',
'Video', 'Sticker', 'Document', 'Audio', 'PhotoSize', 'GroupChat',
'Update', 'Message', 'User', 'TelegramObject', 'NullHandler']
'Update', 'Message', 'User', 'TelegramObject', 'NullHandler',
'Voice']
+41 -17
View File
@@ -16,33 +16,57 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Audio"""
from telegram import TelegramObject
class Audio(TelegramObject):
"""This object represents a Telegram Audio.
Attributes:
file_id (str):
duration (int):
performer (str):
title (str):
mime_type (str):
file_size (int):
Args:
file_id (str):
duration (int):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
performer (Optional[str]):
title (Optional[str]):
mime_type (Optional[str]):
file_size (Optional[int]):
"""
def __init__(self,
file_id,
duration,
mime_type=None,
file_size=None):
**kwargs):
# Required
self.file_id = file_id
self.duration = duration
self.mime_type = mime_type
self.file_size = file_size
self.duration = int(duration)
# Optionals
self.performer = kwargs.get('performer', '')
self.title = kwargs.get('title', '')
self.mime_type = kwargs.get('mime_type', '')
self.file_size = int(kwargs.get('file_size', 0))
@staticmethod
def de_json(data):
return Audio(file_id=data.get('file_id', None),
duration=data.get('duration', None),
mime_type=data.get('mime_type', None),
file_size=data.get('file_size', None))
"""
Args:
data (str):
def to_dict(self):
data = {'file_id': self.file_id,
'duration': self.duration}
if self.mime_type:
data['mime_type'] = self.mime_type
if self.file_size:
data['file_size'] = self.file_size
return data
Returns:
telegram.Audio:
"""
if not data:
return None
return Audio(**data)
+28 -4
View File
@@ -16,13 +16,14 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Base class for Telegram Objects"""
import json
from abc import ABCMeta, abstractmethod
from abc import ABCMeta
class TelegramObject(object):
"""Base class for most telegram object"""
"""Base class for most telegram objects"""
__metaclass__ = ABCMeta
@@ -34,11 +35,34 @@ class TelegramObject(object):
@staticmethod
def de_json(data):
"""
Args:
data (str):
Returns:
telegram.TelegramObject:
"""
raise NotImplementedError
def to_json(self):
"""
Returns:
str:
"""
return json.dumps(self.to_dict())
@abstractmethod
def to_dict(self):
return
"""
Returns:
dict:
"""
data = dict()
for key, value in self.__dict__.items():
if value:
if hasattr(value, 'to_dict'):
data[key] = value.to_dict()
else:
data[key] = value
return data
+183 -77
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python
# pylint: disable=E0611,E0213,E1102,C0103,E1101,W0613,R0913,R0904
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
@@ -16,6 +17,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Bot"""
import json
try:
@@ -32,11 +34,27 @@ import logging
from telegram import (User, Message, Update, UserProfilePhotos, TelegramError,
ReplyMarkup, InputFile, TelegramObject, NullHandler)
h = NullHandler()
logging.getLogger(__name__).addHandler(h)
H = NullHandler()
logging.getLogger(__name__).addHandler(H)
class Bot(TelegramObject):
"""This object represents a Telegram Bot.
Attributes:
id (int):
first_name (str):
last_name (str):
username (str):
name (str):
Args:
token (str):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
base_url (Optional[str]):
"""
def __init__(self,
token,
@@ -48,35 +66,71 @@ class Bot(TelegramObject):
else:
self.base_url = base_url + self.token
self.log = logging.getLogger(__name__)
self.bot = None
try:
bot = self.getMe()
self.logger = logging.getLogger(__name__)
self.id = bot.id
self.first_name = bot.first_name
self.last_name = bot.last_name
self.username = bot.username
def info(func):
"""
Returns:
"""
@functools.wraps(func)
def decorator(self, *args, **kwargs):
"""
decorator
"""
if not self.bot:
self.getMe()
self.__auth = True
result = func(self, *args, **kwargs)
return result
return decorator
self.log.info('Starting bot %s' % self.name)
except TelegramError:
raise TelegramError({'message': 'Bad token'})
@property
@info
def id(self):
"""int: """
return self.bot.id
@property
@info
def first_name(self):
"""str: """
return self.bot.first_name
@property
@info
def last_name(self):
"""str: """
return self.bot.last_name
@property
@info
def username(self):
"""str: """
return self.bot.username
@property
def name(self):
"""str: """
return '@%s' % self.username
def log(func):
"""
Returns:
A telegram.Message instance representing the message posted.
"""
logger = logging.getLogger(func.__module__)
@functools.wraps(func)
def decorator(self, *args, **kwargs):
logger.debug('Entering: %s' % func.__name__)
"""
decorator
"""
logger.debug('Entering: %s', func.__name__)
result = func(self, *args, **kwargs)
logger.debug(result)
logger.debug('Exiting: %s' % func.__name__)
logger.debug('Exiting: %s', func.__name__)
return result
return decorator
@@ -87,8 +141,14 @@ class Bot(TelegramObject):
"""
@functools.wraps(func)
def decorator(self, *args, **kwargs):
"""
decorator
"""
url, data = func(self, *args, **kwargs)
if not kwargs.get('chat_id'):
raise TelegramError('Invalid chat_id.')
if kwargs.get('reply_to_message_id'):
reply_to_message_id = kwargs.get('reply_to_message_id')
data['reply_to_message_id'] = reply_to_message_id
@@ -100,8 +160,8 @@ class Bot(TelegramObject):
else:
data['reply_markup'] = reply_markup
json_data = self._requestUrl(url, 'POST', data=data)
data = self._parseAndCheckTelegram(json_data)
json_data = Bot._requestUrl(url, 'POST', data=data)
data = Bot._parseAndCheckTelegram(json_data)
if data is True:
return data
@@ -109,22 +169,6 @@ class Bot(TelegramObject):
return Message.de_json(data)
return decorator
def require_authentication(func):
@functools.wraps(func)
def decorator(self, *args, **kwargs):
if not self.__auth:
raise TelegramError({'message': "API must be authenticated."})
return func(self, *args, **kwargs)
return decorator
@log
@require_authentication
def clearCredentials(self):
"""Clear any credentials for this instance.
"""
self.__auth = False
@log
def getMe(self):
"""A simple method for testing your bot's auth token.
@@ -138,17 +182,17 @@ class Bot(TelegramObject):
json_data = self._requestUrl(url, 'GET')
data = self._parseAndCheckTelegram(json_data)
return User.de_json(data)
self.bot = User.de_json(data)
return self.bot
@log
@message
@require_authentication
def sendMessage(self,
chat_id,
text,
disable_web_page_preview=None,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send text messages.
Args:
@@ -182,7 +226,6 @@ class Bot(TelegramObject):
@log
@message
@require_authentication
def forwardMessage(self,
chat_id,
from_chat_id,
@@ -216,13 +259,11 @@ class Bot(TelegramObject):
@log
@message
@require_authentication
def sendPhoto(self,
chat_id,
photo,
caption=None,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send photos.
Args:
@@ -258,16 +299,23 @@ class Bot(TelegramObject):
@log
@message
@require_authentication
def sendAudio(self,
chat_id,
audio,
reply_to_message_id=None,
reply_markup=None):
duration=None,
performer=None,
title=None,
**kwargs):
"""Use this method to send audio files, if you want Telegram clients to
display the file as a playable voice message. For this to work, your
audio must be in an .ogg file encoded with OPUS (other formats may be
sent as telegram.Document).
display them in the music player. Your audio must be in an .mp3 format.
On success, the sent Message is returned. Bots can currently send audio
files of up to 50 MB in size, this limit may be changed in the future.
For backward compatibility, when both fields title and description are
empty and mime-type of the sent file is not "audio/mpeg", file is sent
as playable voice message. In this case, your audio must be in an .ogg
file encoded with OPUS. This will be removed in the future. You need to
use sendVoice method instead.
Args:
chat_id:
@@ -276,6 +324,12 @@ class Bot(TelegramObject):
Audio file to send. You can either pass a file_id as String to
resend an audio that is already on the Telegram servers, or upload
a new audio file using multipart/form-data.
duration:
Duration of sent audio in seconds. [Optional]
performer:
Performer of sent audio. [Optional]
title:
Title of sent audio. [Optional]
reply_to_message_id:
If the message is a reply, ID of the original message. [Optional]
reply_markup:
@@ -292,16 +346,21 @@ class Bot(TelegramObject):
data = {'chat_id': chat_id,
'audio': audio}
if duration:
data['duration'] = duration
if performer:
data['performer'] = performer
if title:
data['title'] = title
return url, data
@log
@message
@require_authentication
def sendDocument(self,
chat_id,
document,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send general files.
Args:
@@ -331,12 +390,10 @@ class Bot(TelegramObject):
@log
@message
@require_authentication
def sendSticker(self,
chat_id,
sticker,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send .webp stickers.
Args:
@@ -366,14 +423,12 @@ class Bot(TelegramObject):
@log
@message
@require_authentication
def sendVideo(self,
chat_id,
video,
duration=None,
caption=None,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send video files, Telegram clients support mp4
videos (other formats may be sent as telegram.Document).
@@ -414,13 +469,55 @@ class Bot(TelegramObject):
@log
@message
@require_authentication
def sendVoice(self,
chat_id,
voice,
duration=None,
**kwargs):
"""Use this method to send audio files, if you want Telegram clients to
display the file as a playable voice message. For this to work, your
audio must be in an .ogg file encoded with OPUS (other formats may be
sent as Audio or Document). On success, the sent Message is returned.
Bots can currently send audio files of up to 50 MB in size, this limit
may be changed in the future.
Args:
chat_id:
Unique identifier for the message recipient - User or GroupChat id.
voice:
Audio file to send. You can either pass a file_id as String to
resend an audio that is already on the Telegram servers, or upload
a new audio file using multipart/form-data.
duration:
Duration of sent audio in seconds. [Optional]
reply_to_message_id:
If the message is a reply, ID of the original message. [Optional]
reply_markup:
Additional interface options. A JSON-serialized object for a
custom reply keyboard, instructions to hide keyboard or to force a
reply from the user. [Optional]
Returns:
A telegram.Message instance representing the message posted.
"""
url = '%s/sendVoice' % self.base_url
data = {'chat_id': chat_id,
'voice': voice}
if duration:
data['duration'] = duration
return url, data
@log
@message
def sendLocation(self,
chat_id,
latitude,
longitude,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send point on the map.
Args:
@@ -451,7 +548,6 @@ class Bot(TelegramObject):
@log
@message
@require_authentication
def sendChatAction(self,
chat_id,
action):
@@ -468,8 +564,8 @@ class Bot(TelegramObject):
is about to receive:
- ChatAction.TYPING for text messages,
- ChatAction.UPLOAD_PHOTO for photos,
- ChatAction.UPLOAD_VIDEO or upload_video for videos,
- ChatAction.UPLOAD_AUDIO or upload_audio for audio files,
- ChatAction.UPLOAD_VIDEO for videos,
- ChatAction.UPLOAD_AUDIO for audio files,
- ChatAction.UPLOAD_DOCUMENT for general files,
- ChatAction.FIND_LOCATION for location data.
"""
@@ -482,7 +578,6 @@ class Bot(TelegramObject):
return url, data
@log
@require_authentication
def getUserProfilePhotos(self,
user_id,
offset=None,
@@ -518,7 +613,6 @@ class Bot(TelegramObject):
return UserProfilePhotos.de_json(data)
@log
@require_authentication
def getUpdates(self,
offset=None,
limit=100,
@@ -557,17 +651,17 @@ class Bot(TelegramObject):
data = self._parseAndCheckTelegram(json_data)
if data:
self.log.info(
'Getting updates: %s' % [u['update_id'] for u in data])
self.logger.info(
'Getting updates: %s', [u['update_id'] for u in data])
else:
self.log.info('No new updates found.')
self.logger.info('No new updates found.')
return [Update.de_json(x) for x in data]
@log
@require_authentication
def setWebhook(self,
webhook_url):
webhook_url=None,
certificate=None):
"""Use this method to specify a url and receive incoming updates via an
outgoing webhook. Whenever there is an update for the bot, we will send
an HTTPS POST request to the specified url, containing a
@@ -584,15 +678,19 @@ class Bot(TelegramObject):
"""
url = '%s/setWebhook' % self.base_url
data = {'url': webhook_url}
data = {}
if webhook_url:
data['url'] = webhook_url
if certificate:
data['certificate'] = certificate
json_data = self._requestUrl(url, 'POST', data=data)
data = self._parseAndCheckTelegram(json_data)
return True
return data
def _requestUrl(self,
url,
@staticmethod
def _requestUrl(url,
method,
data=None):
"""Request an URL.
@@ -629,12 +727,12 @@ class Bot(TelegramObject):
url,
urlencode(data).encode()
).read()
except IOError as e:
raise TelegramError(str(e))
except HTTPError as e:
raise TelegramError(str(e))
except URLError as e:
raise TelegramError(str(e))
except IOError as e:
raise TelegramError(str(e))
if method == 'GET':
try:
@@ -642,8 +740,8 @@ class Bot(TelegramObject):
except URLError as e:
raise TelegramError(str(e))
def _parseAndCheckTelegram(self,
json_data):
@staticmethod
def _parseAndCheckTelegram(json_data):
"""Try and parse the JSON returned from Telegram and return an empty
dictionary if there is any error.
@@ -666,7 +764,15 @@ class Bot(TelegramObject):
return data['result']
@staticmethod
def de_json(data):
pass
def to_dict(self):
"""
Returns:
dict:
"""
data = {'id': self.id,
'username': self.username,
'first_name': self.username}
+9 -2
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python
# pylint: disable=R0903
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
@@ -16,11 +17,17 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram ChatAction"""
class ChatAction(object):
"""This object represents a Telegram ChatAction."""
TYPING = 'typing'
UPLOAD_PHOTO = 'upload_photo'
RECORD_VIDEO = 'upload_video'
RECORD_AUDIO = 'upload_audio'
RECORD_VIDEO = 'record_video'
UPLOAD_VIDEO = 'upload_video'
RECORD_AUDIO = 'record_audio'
UPLOAD_AUDIO = 'upload_audio'
UPLOAD_DOCUMENT = 'upload_document'
FIND_LOCATION = 'find_location'
+34 -16
View File
@@ -16,33 +16,51 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Contact"""
from telegram import TelegramObject
class Contact(TelegramObject):
"""This object represents a Telegram Contact.
Attributes:
phone_number (str):
first_name (str):
last_name (str):
user_id (int):
Args:
phone_number (str):
first_name (str):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
last_name (Optional[str]):
user_id (Optional[int]):
"""
def __init__(self,
phone_number,
first_name,
last_name=None,
user_id=None):
**kwargs):
# Required
self.phone_number = phone_number
self.first_name = first_name
self.last_name = last_name
self.user_id = user_id
# Optionals
self.last_name = kwargs.get('last_name', '')
self.user_id = int(kwargs.get('user_id', 0))
@staticmethod
def de_json(data):
return Contact(phone_number=data.get('phone_number', None),
first_name=data.get('first_name', None),
last_name=data.get('last_name', None),
user_id=data.get('user_id', None))
"""
Args:
data (str):
def to_dict(self):
data = {'phone_number': self.phone_number,
'first_name': self.first_name}
if self.last_name:
data['last_name'] = self.last_name
if self.user_id:
data['user_id'] = self.user_id
return data
Returns:
telegram.Contact:
"""
if not data:
return None
return Contact(**data)
+38 -30
View File
@@ -16,45 +16,53 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Document"""
from telegram import TelegramObject
from telegram import PhotoSize, TelegramObject
class Document(TelegramObject):
"""This object represents a Telegram Document.
Attributes:
file_id (str):
thumb (:class:`telegram.PhotoSize`):
file_name (str):
mime_type (str):
file_size (int):
Args:
file_id (str):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
thumb (Optional[:class:`telegram.PhotoSize`]):
file_name (Optional[str]):
mime_type (Optional[str]):
file_size (Optional[int]):
"""
def __init__(self,
file_id,
thumb=None,
file_name=None,
mime_type=None,
file_size=None):
**kwargs):
# Required
self.file_id = file_id
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type
self.file_size = file_size
# Optionals
self.thumb = kwargs.get('thumb')
self.file_name = kwargs.get('file_name', '')
self.mime_type = kwargs.get('mime_type', '')
self.file_size = int(kwargs.get('file_size', 0))
@staticmethod
def de_json(data):
if 'thumb' in data:
from telegram import PhotoSize
thumb = PhotoSize.de_json(data['thumb'])
else:
thumb = None
"""
Args:
data (str):
return Document(file_id=data.get('file_id', None),
thumb=thumb,
file_name=data.get('file_name', None),
mime_type=data.get('mime_type', None),
file_size=data.get('file_size', None))
Returns:
telegram.Document:
"""
if not data:
return None
def to_dict(self):
data = {'file_id': self.file_id}
if self.thumb:
data['thumb'] = self.thumb.to_dict()
if self.file_name:
data['file_name'] = self.file_name
if self.mime_type:
data['mime_type'] = self.mime_type
if self.file_size:
data['file_size'] = self.file_size
return data
return Document(**data)
+25 -10
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env python
# flake8: noqa
# pylint: disable=C0103,C0301,R0903
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
@@ -17,8 +18,12 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents an Emoji"""
class Emoji(object):
"""This object represents an Emoji."""
GRINNING_FACE_WITH_SMILING_EYES = b'\xF0\x9F\x98\x81'
FACE_WITH_TEARS_OF_JOY = b'\xF0\x9F\x98\x82'
SMILING_FACE_WITH_OPEN_MOUTH = b'\xF0\x9F\x98\x83'
@@ -155,16 +160,26 @@ class Emoji(object):
SQUARED_SOS = b'\xF0\x9F\x86\x98'
SQUARED_UP_WITH_EXCLAMATION_MARK = b'\xF0\x9F\x86\x99'
SQUARED_VS = b'\xF0\x9F\x86\x9A'
REGIONAL_INDICATOR_SYMBOL_LETTER_D_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_E = b'\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA'
REGIONAL_INDICATOR_SYMBOL_LETTER_G_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_B = b'\xF0\x9F\x87\xAC\xF0\x9F\x87\xA7'
REGIONAL_INDICATOR_SYMBOL_LETTER_C_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_N = b'\xF0\x9F\x87\xA8\xF0\x9F\x87\xB3'
REGIONAL_INDICATOR_SYMBOL_LETTER_J_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_P = b'\xF0\x9F\x87\xAF\xF0\x9F\x87\xB5'
REGIONAL_INDICATOR_SYMBOL_LETTER_K_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_R = b'\xF0\x9F\x87\xB0\xF0\x9F\x87\xB7'
REGIONAL_INDICATOR_SYMBOL_LETTER_F_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_R = b'\xF0\x9F\x87\xAB\xF0\x9F\x87\xB7'
REGIONAL_INDICATOR_SYMBOL_LETTER_E_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_S = b'\xF0\x9F\x87\xAA\xF0\x9F\x87\xB8'
REGIONAL_INDICATOR_SYMBOL_LETTER_I_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_T = b'\xF0\x9F\x87\xAE\xF0\x9F\x87\xB9'
REGIONAL_INDICATOR_SYMBOL_LETTER_U_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_S = b'\xF0\x9F\x87\xBA\xF0\x9F\x87\xB8'
REGIONAL_INDICATOR_SYMBOL_LETTER_R_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_U = b'\xF0\x9F\x87\xB7\xF0\x9F\x87\xBA'
REGIONAL_INDICATOR_SYMBOL_LETTER_D_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_E\
= b'\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA'
REGIONAL_INDICATOR_SYMBOL_LETTER_G_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_B\
= b'\xF0\x9F\x87\xAC\xF0\x9F\x87\xA7'
REGIONAL_INDICATOR_SYMBOL_LETTER_C_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_N\
= b'\xF0\x9F\x87\xA8\xF0\x9F\x87\xB3'
REGIONAL_INDICATOR_SYMBOL_LETTER_J_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_P\
= b'\xF0\x9F\x87\xAF\xF0\x9F\x87\xB5'
REGIONAL_INDICATOR_SYMBOL_LETTER_K_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_R\
= b'\xF0\x9F\x87\xB0\xF0\x9F\x87\xB7'
REGIONAL_INDICATOR_SYMBOL_LETTER_F_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_R\
= b'\xF0\x9F\x87\xAB\xF0\x9F\x87\xB7'
REGIONAL_INDICATOR_SYMBOL_LETTER_E_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_S\
= b'\xF0\x9F\x87\xAA\xF0\x9F\x87\xB8'
REGIONAL_INDICATOR_SYMBOL_LETTER_I_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_T\
= b'\xF0\x9F\x87\xAE\xF0\x9F\x87\xB9'
REGIONAL_INDICATOR_SYMBOL_LETTER_U_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_S\
= b'\xF0\x9F\x87\xBA\xF0\x9F\x87\xB8'
REGIONAL_INDICATOR_SYMBOL_LETTER_R_PLUS_REGIONAL_INDICATOR_SYMBOL_LETTER_U\
= b'\xF0\x9F\x87\xB7\xF0\x9F\x87\xBA'
SQUARED_KATAKANA_KOKO = b'\xF0\x9F\x88\x81'
SQUARED_KATAKANA_SA = b'\xF0\x9F\x88\x82'
SQUARED_CJK_UNIFIED_IDEOGRAPH_7121 = b'\xF0\x9F\x88\x9A'
+7 -2
View File
@@ -16,11 +16,16 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Error"""
class TelegramError(Exception):
"""Base class for Telegram errors."""
"""This object represents a Telegram Error."""
@property
def message(self):
'''Returns the first argument used to construct this error.'''
"""
Returns:
str:
"""
return self.args[0]
+31 -10
View File
@@ -16,24 +16,45 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram ForceReply"""
from telegram import ReplyMarkup
class ForceReply(ReplyMarkup):
"""This object represents a Telegram ForceReply.
Attributes:
force_reply (bool):
selective (bool):
Args:
force_reply (bool):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
selective (Optional[bool]):
"""
def __init__(self,
force_reply=True,
selective=None):
self.force_reply = force_reply
self.selective = selective
**kwargs):
# Required
self.force_reply = bool(force_reply)
# Optionals
self.selective = bool(kwargs.get('selective', False))
@staticmethod
def de_json(data):
return ForceReply(force_reply=data.get('force_reply', None),
selective=data.get('selective', None))
"""
Args:
data (str):
def to_dict(self):
data = {'force_reply': self.force_reply}
if self.selective:
data['selective'] = self.selective
return data
Returns:
telegram.ForceReply:
"""
if not data:
return None
return ForceReply(**data)
+25 -7
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python
# pylint: disable=C0103,W0622
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
@@ -16,23 +17,40 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram GroupChat"""
from telegram import TelegramObject
class GroupChat(TelegramObject):
"""This object represents a Telegram GroupChat.
Attributes:
id (int):
title (str):
Args:
id (int):
title (str):
"""
def __init__(self,
id,
title):
self.id = id
# Required
self.id = int(id)
self.title = title
@staticmethod
def de_json(data):
return GroupChat(id=data.get('id', None),
title=data.get('title', None))
"""
Args:
data (str):
def to_dict(self):
data = {'id': self.id,
'title': self.title}
return data
Returns:
telegram.GroupChat:
"""
if not data:
return None
return GroupChat(**data)
+40 -25
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python
# pylint: disable=W0622,E0611
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
@@ -16,6 +17,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram InputFile"""
try:
from email.generator import _make_boundary as choose_boundary
@@ -26,10 +28,10 @@ except ImportError:
from urllib2 import urlopen
import mimetypes
import os
import re
import sys
import imghdr
from .error import TelegramError
from telegram import TelegramError
DEFAULT_MIME_TYPE = 'application/octet-stream'
USER_AGENT = 'Python Telegram Bot' \
@@ -37,6 +39,8 @@ USER_AGENT = 'Python Telegram Bot' \
class InputFile(object):
"""This object represents a Telegram InputFile."""
def __init__(self,
data):
self.data = data
@@ -54,6 +58,12 @@ class InputFile(object):
if 'video' in data:
self.input_name = 'video'
self.input_file = data.pop('video')
if 'voice' in data:
self.input_name = 'voice'
self.input_file = data.pop('voice')
if 'certificate' in data:
self.input_name = 'certificate'
self.input_file = data.pop('certificate')
if isinstance(self.input_file, file):
self.input_file_content = self.input_file.read()
@@ -68,14 +78,26 @@ class InputFile(object):
@property
def headers(self):
"""
Returns:
str:
"""
return {'User-agent': USER_AGENT,
'Content-type': self.content_type}
@property
def content_type(self):
"""
Returns:
str:
"""
return 'multipart/form-data; boundary=%s' % self.boundary
def to_form(self):
"""
Returns:
str:
"""
form = []
form_boundary = '--' + self.boundary
@@ -102,9 +124,14 @@ class InputFile(object):
form.append('--' + self.boundary + '--')
form.append('')
return self._parse(form)
return InputFile._parse(form)
def _parse(self, form):
@staticmethod
def _parse(form):
"""
Returns:
str:
"""
if sys.version_info > (3,):
# on Python 3 form needs to be byte encoded
encoded_form = []
@@ -122,41 +149,29 @@ class InputFile(object):
"""Check if the content file is an image by analyzing its headers.
Args:
stream:
A str representing the content of a file.
stream (str): A str representing the content of a file.
Returns:
The str mimetype of an image.
str: The str mimetype of an image.
"""
try:
header = stream[:10]
if re.match(b'GIF8', header):
return 'image/gif'
if re.match(b'\x89PNG', header):
return 'image/png'
if re.match(b'\xff\xd8\xff\xe0\x00\x10JFIF', header) or \
re.match(b'\xff\xd8\xff\xe1(.*){2}Exif', header):
return 'image/jpeg'
except IndexError as e:
raise TelegramError(str(e))
image = imghdr.what(None, stream)
if image:
return 'image/%s' % image
raise TelegramError({'message': 'Could not parse file content'})
@staticmethod
def is_inputfile(data):
"""Check if the request is a file request
"""Check if the request is a file request.
Args:
data:
A dict of (str, unicode) key/value pairs
data (str): A dict of (str, unicode) key/value pairs
Returns:
bool
"""
if data:
file_types = ['audio', 'document', 'photo', 'video']
file_types = ['audio', 'document', 'photo', 'video', 'voice']
file_type = [i for i in list(data.keys()) if i in file_types]
if file_type:
+25 -8
View File
@@ -16,23 +16,40 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Location"""
from telegram import TelegramObject
class Location(TelegramObject):
"""This object represents a Telegram Sticker.
Attributes:
longitude (float):
latitude (float):
Args:
longitude (float):
latitude (float):
"""
def __init__(self,
longitude,
latitude):
self.longitude = longitude
self.latitude = latitude
# Required
self.longitude = float(longitude)
self.latitude = float(latitude)
@staticmethod
def de_json(data):
return Location(longitude=data.get('longitude', None),
latitude=data.get('latitude', None))
"""
Args:
data (str):
def to_dict(self):
data = {'longitude': self.longitude,
'latitude': self.latitude}
return data
Returns:
telegram.Location:
"""
if not data:
return None
return Location(**data)
+178 -174
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python
# pylint: disable=R0902,R0912,R0913
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
@@ -16,206 +17,209 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Message"""
from telegram import TelegramObject
from datetime import datetime
from time import mktime
from telegram import (Audio, Contact, Document, GroupChat, Location, PhotoSize,
Sticker, TelegramObject, User, Video, Voice)
class Message(TelegramObject):
"""This object represents a Telegram Message.
Note:
* In Python `from` is a reserved word, use `from_user` instead.
Attributes:
message_id (int):
from_user (:class:`telegram.User`):
date (:class:`datetime.datetime`):
forward_from (:class:`telegram.User`):
forward_date (:class:`datetime.datetime`):
reply_to_message (:class:`telegram.Message`):
text (str):
audio (:class:`telegram.Audio`):
document (:class:`telegram.Document`):
photo (List[:class:`telegram.PhotoSize`]):
sticker (:class:`telegram.Sticker`):
video (:class:`telegram.Video`):
voice (:class:`telegram.Voice`):
caption (str):
contact (:class:`telegram.Contact`):
location (:class:`telegram.Location`):
new_chat_participant (:class:`telegram.User`):
left_chat_participant (:class:`telegram.User`):
new_chat_title (str):
new_chat_photo (List[:class:`telegram.PhotoSize`]):
delete_chat_photo (bool):
group_chat_created (bool):
Args:
message_id (int):
from_user (:class:`telegram.User`):
date (:class:`datetime.datetime`):
chat (:class:`telegram.User` or :class:`telegram.GroupChat`):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
forward_from (Optional[:class:`telegram.User`]):
forward_date (Optional[:class:`datetime.datetime`]):
reply_to_message (Optional[:class:`telegram.Message`]):
text (Optional[str]):
audio (Optional[:class:`telegram.Audio`]):
document (Optional[:class:`telegram.Document`]):
photo (Optional[List[:class:`telegram.PhotoSize`]]):
sticker (Optional[:class:`telegram.Sticker`]):
video (Optional[:class:`telegram.Video`]):
voice (Optional[:class:`telegram.Voice`]):
caption (Optional[str]):
contact (Optional[:class:`telegram.Contact`]):
location (Optional[:class:`telegram.Location`]):
new_chat_participant (Optional[:class:`telegram.User`]):
left_chat_participant (Optional[:class:`telegram.User`]):
new_chat_title (Optional[str]):
new_chat_photo (Optional[List[:class:`telegram.PhotoSize`]):
delete_chat_photo (Optional[bool]):
group_chat_created (Optional[bool]):
"""
def __init__(self,
message_id,
from_user,
date,
chat,
forward_from=None,
forward_date=None,
reply_to_message=None,
text=None,
audio=None,
document=None,
photo=None,
sticker=None,
video=None,
caption=None,
contact=None,
location=None,
new_chat_participant=None,
left_chat_participant=None,
new_chat_title=None,
new_chat_photo=None,
delete_chat_photo=None,
group_chat_created=None):
self.message_id = message_id
**kwargs):
# Required
self.message_id = int(message_id)
self.from_user = from_user
self.date = date
self.chat = chat
self.forward_from = forward_from
self.forward_date = forward_date
self.reply_to_message = reply_to_message
self.text = text
self.audio = audio
self.document = document
self.photo = photo
self.sticker = sticker
self.video = video
self.caption = caption
self.contact = contact
self.location = location
self.new_chat_participant = new_chat_participant
self.left_chat_participant = left_chat_participant
self.new_chat_title = new_chat_title
self.new_chat_photo = new_chat_photo
self.delete_chat_photo = delete_chat_photo
self.group_chat_created = group_chat_created
# Optionals
self.forward_from = kwargs.get('forward_from')
self.forward_date = kwargs.get('forward_date')
self.reply_to_message = kwargs.get('reply_to_message')
self.text = kwargs.get('text', '')
self.audio = kwargs.get('audio')
self.document = kwargs.get('document')
self.photo = kwargs.get('photo')
self.sticker = kwargs.get('sticker')
self.video = kwargs.get('video')
self.voice = kwargs.get('voice')
self.caption = kwargs.get('caption', '')
self.contact = kwargs.get('contact')
self.location = kwargs.get('location')
self.new_chat_participant = kwargs.get('new_chat_participant')
self.left_chat_participant = kwargs.get('left_chat_participant')
self.new_chat_title = kwargs.get('new_chat_title', '')
self.new_chat_photo = kwargs.get('new_chat_photo')
self.delete_chat_photo = bool(kwargs.get('delete_chat_photo', False))
self.group_chat_created = bool(kwargs.get('group_chat_created', False))
@property
def chat_id(self):
"""int: Short for :attr:`Message.chat.id`"""
return self.chat.id
@staticmethod
def de_json(data):
if 'from' in data: # from is a reserved word, use from_user instead.
from telegram import User
from_user = User.de_json(data['from'])
else:
from_user = None
"""
Args:
data (str):
if 'chat' in data:
if 'first_name' in data['chat']:
from telegram import User
chat = User.de_json(data['chat'])
if 'title' in data['chat']:
from telegram import GroupChat
chat = GroupChat.de_json(data['chat'])
else:
chat = None
Returns:
telegram.Message:
"""
if not data:
return None
if 'forward_from' in data:
from telegram import User
forward_from = User.de_json(data['forward_from'])
else:
forward_from = None
data['from_user'] = User.de_json(data['from'])
data['date'] = datetime.fromtimestamp(data['date'])
if 'first_name' in data.get('chat', ''):
data['chat'] = User.de_json(data.get('chat'))
elif 'title' in data.get('chat', ''):
data['chat'] = GroupChat.de_json(data.get('chat'))
data['forward_from'] = \
User.de_json(data.get('forward_from'))
data['forward_date'] = \
Message._fromtimestamp(data.get('forward_date'))
data['reply_to_message'] = \
Message.de_json(data.get('reply_to_message'))
data['audio'] = \
Audio.de_json(data.get('audio'))
data['document'] = \
Document.de_json(data.get('document'))
data['photo'] = \
PhotoSize.de_list(data.get('photo'))
data['sticker'] = \
Sticker.de_json(data.get('sticker'))
data['video'] = \
Video.de_json(data.get('video'))
data['voice'] = \
Voice.de_json(data.get('voice'))
data['contact'] = \
Contact.de_json(data.get('contact'))
data['location'] = \
Location.de_json(data.get('location'))
data['new_chat_participant'] = \
User.de_json(data.get('new_chat_participant'))
data['left_chat_participant'] = \
User.de_json(data.get('left_chat_participant'))
data['new_chat_photo'] = \
PhotoSize.de_list(data.get('new_chat_photo'))
if 'reply_to_message' in data:
reply_to_message = Message.de_json(data['reply_to_message'])
else:
reply_to_message = None
if 'audio' in data:
from telegram import Audio
audio = Audio.de_json(data['audio'])
else:
audio = None
if 'document' in data:
from telegram import Document
document = Document.de_json(data['document'])
else:
document = None
if 'photo' in data:
from telegram import PhotoSize
photo = [PhotoSize.de_json(x) for x in data['photo']]
else:
photo = None
if 'sticker' in data:
from telegram import Sticker
sticker = Sticker.de_json(data['sticker'])
else:
sticker = None
if 'video' in data:
from telegram import Video
video = Video.de_json(data['video'])
else:
video = None
if 'contact' in data:
from telegram import Contact
contact = Contact.de_json(data['contact'])
else:
contact = None
if 'location' in data:
from telegram import Location
location = Location.de_json(data['location'])
else:
location = None
if 'new_chat_participant' in data:
from telegram import User
new_chat_participant = User.de_json(data['new_chat_participant'])
else:
new_chat_participant = None
if 'left_chat_participant' in data:
from telegram import User
left_chat_participant = User.de_json(data['left_chat_participant'])
else:
left_chat_participant = None
return Message(message_id=data.get('message_id', None),
from_user=from_user,
date=data.get('date', None),
chat=chat,
forward_from=forward_from,
forward_date=data.get('forward_date', None),
reply_to_message=reply_to_message,
text=data.get('text', ''),
audio=audio,
document=document,
photo=photo,
sticker=sticker,
video=video,
caption=data.get('caption', ''),
contact=contact,
location=location,
new_chat_participant=new_chat_participant,
left_chat_participant=left_chat_participant,
new_chat_title=data.get('new_chat_title', None),
new_chat_photo=data.get('new_chat_photo', None),
delete_chat_photo=data.get('delete_chat_photo', None),
group_chat_created=data.get('group_chat_created', None))
return Message(**data)
def to_dict(self):
data = {'message_id': self.message_id,
'from': self.from_user.to_dict(),
'date': self.date,
'chat': self.chat.to_dict()}
if self.forward_from:
data['forward_from'] = self.forward_from
"""
Returns:
dict:
"""
data = super(Message, self).to_dict()
# Required
data['from'] = data.pop('from_user')
data['date'] = self._totimestamp(self.date)
# Optionals
if self.forward_date:
data['forward_date'] = self.forward_date
if self.reply_to_message:
data['reply_to_message'] = self.reply_to_message
if self.text:
data['text'] = self.text
if self.audio:
data['audio'] = self.audio.to_dict()
if self.document:
data['document'] = self.document.to_dict()
data['forward_date'] = self._totimestamp(self.forward_date)
if self.photo:
data['photo'] = [p.to_dict() for p in self.photo]
if self.sticker:
data['sticker'] = self.sticker.to_dict()
if self.video:
data['video'] = self.video.to_dict()
if self.caption:
data['caption'] = self.caption
if self.contact:
data['contact'] = self.contact.to_dict()
if self.location:
data['location'] = self.location.to_dict()
if self.new_chat_participant:
data['new_chat_participant'] = self.new_chat_participant
if self.left_chat_participant:
data['left_chat_participant'] = self.left_chat_participant
if self.new_chat_title:
data['new_chat_title'] = self.new_chat_title
if self.new_chat_photo:
data['new_chat_photo'] = self.new_chat_photo
if self.delete_chat_photo:
data['delete_chat_photo'] = self.delete_chat_photo
if self.group_chat_created:
data['group_chat_created'] = self.group_chat_created
data['new_chat_photo'] = [p.to_dict() for p in self.new_chat_photo]
return data
@staticmethod
def _fromtimestamp(unixtime):
"""
Args:
unixtime (int):
Returns:
datetime.datetime:
"""
if not unixtime:
return None
return datetime.fromtimestamp(unixtime)
@staticmethod
def _totimestamp(dt_obj):
"""
Args:
dt_obj (:class:`datetime.datetime`):
Returns:
int:
"""
if not dt_obj:
return None
try:
# Python 3.3+
return int(dt_obj.timestamp())
except AttributeError:
# Python 3 (< 3.3) and Python 2
return int(mktime(dt_obj.timetuple()))
+7
View File
@@ -16,10 +16,17 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a logging NullHandler"""
import logging
class NullHandler(logging.Handler):
"""This object represents a logging NullHandler."""
def emit(self, record):
"""
Args:
record (str):
"""
pass
+53 -15
View File
@@ -16,32 +16,70 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram PhotoSize"""
from telegram import TelegramObject
class PhotoSize(TelegramObject):
"""This object represents a Telegram PhotoSize.
Attributes:
file_id (str):
width (int):
height (int):
file_size (int):
Args:
file_id (str):
width (int):
height (int):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
file_size (Optional[int]):
"""
def __init__(self,
file_id,
width,
height,
file_size=None):
**kwargs):
# Required
self.file_id = file_id
self.width = width
self.height = height
self.file_size = file_size
self.width = int(width)
self.height = int(height)
# Optionals
self.file_size = int(kwargs.get('file_size', 0))
@staticmethod
def de_json(data):
return PhotoSize(file_id=data.get('file_id', None),
width=data.get('width', None),
height=data.get('height', None),
file_size=data.get('file_size', None))
"""
Args:
data (str):
def to_dict(self):
data = {'file_id': self.file_id,
'width': self.width,
'height': self.height}
if self.file_size:
data['file_size'] = self.file_size
return data
Returns:
telegram.PhotoSize:
"""
if not data:
return None
return PhotoSize(**data)
@staticmethod
def de_list(data):
"""
Args:
data (list):
Returns:
List<telegram.PhotoSize>:
"""
if not data:
return []
photos = list()
for photo in data:
photos.append(PhotoSize.de_json(photo))
return photos
+31 -10
View File
@@ -16,24 +16,45 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram
ReplyKeyboardHide"""
from telegram import ReplyMarkup
class ReplyKeyboardHide(ReplyMarkup):
"""This object represents a Telegram ReplyKeyboardHide.
Attributes:
hide_keyboard (bool):
selective (bool):
Args:
hide_keyboard (bool):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
selective (Optional[bool]):
"""
def __init__(self,
hide_keyboard=True,
selective=None):
self.hide_keyboard = hide_keyboard
self.selective = selective
**kwargs):
# Required
self.hide_keyboard = bool(hide_keyboard)
# Optionals
self.selective = bool(kwargs.get('selective', False))
@staticmethod
def de_json(data):
return ReplyKeyboardHide(hide_keyboard=data.get('hide_keyboard', None),
selective=data.get('selective', None))
"""
Args:
data (str):
def to_dict(self):
data = {'hide_keyboard': self.hide_keyboard}
if self.selective:
data['selective'] = self.selective
return data
Returns:
telegram.ReplyKeyboardHide:
"""
if not data:
return None
return ReplyKeyboardHide(**data)
+36 -23
View File
@@ -16,38 +16,51 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram
ReplyKeyboardMarkup"""
from telegram import ReplyMarkup
class ReplyKeyboardMarkup(ReplyMarkup):
"""This object represents a Telegram ReplyKeyboardMarkup.
Attributes:
keyboard (List[List[str]]):
resize_keyboard (bool):
one_time_keyboard (bool):
selective (bool):
Args:
keyboard (List[List[str]]):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
resize_keyboard (Optional[bool]):
one_time_keyboard (Optional[bool]):
selective (Optional[bool]):
"""
def __init__(self,
keyboard,
resize_keyboard=None,
one_time_keyboard=None,
selective=None):
**kwargs):
# Required
self.keyboard = keyboard
self.resize_keyboard = resize_keyboard
self.one_time_keyboard = one_time_keyboard
self.selective = selective
# Optionals
self.resize_keyboard = bool(kwargs.get('resize_keyboard', False))
self.one_time_keyboard = bool(kwargs.get('one_time_keyboard', False))
self.selective = bool(kwargs.get('selective', False))
@staticmethod
def de_json(data):
return ReplyKeyboardMarkup(keyboard=data.get('keyboard', None),
resize_keyboard=data.get(
'resize_keyboard', None
),
one_time_keyboard=data.get(
'one_time_keyboard', None
),
selective=data.get('selective', None))
"""
Args:
data (str):
def to_dict(self):
data = {'keyboard': self.keyboard}
if self.resize_keyboard:
data['resize_keyboard'] = self.resize_keyboard
if self.one_time_keyboard:
data['one_time_keyboard'] = self.one_time_keyboard
if self.selective:
data['selective'] = self.selective
return data
Returns:
telegram.ReplyKeyboardMarkup:
"""
if not data:
return None
return ReplyKeyboardMarkup(**data)
+9 -1
View File
@@ -16,9 +16,17 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Base class for Telegram ReplyMarkup Objects"""
from telegram import TelegramObject
class ReplyMarkup(TelegramObject):
pass
"""Base class for Telegram ReplyMarkup Objects"""
@staticmethod
def de_json(data):
pass
def to_dict(self):
pass
+38 -25
View File
@@ -16,42 +16,55 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Sticker"""
from telegram import TelegramObject
from telegram import PhotoSize, TelegramObject
class Sticker(TelegramObject):
"""This object represents a Telegram Sticker.
Attributes:
file_id (str):
width (int):
height (int):
thumb (:class:`telegram.PhotoSize`):
file_size (int):
Args:
file_id (str):
width (int):
height (int):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
thumb (Optional[:class:`telegram.PhotoSize`]):
file_size (Optional[int]):
"""
def __init__(self,
file_id,
width,
height,
thumb=None,
file_size=None):
**kwargs):
# Required
self.file_id = file_id
self.width = width
self.height = height
self.thumb = thumb
self.file_size = file_size
self.width = int(width)
self.height = int(height)
# Optionals
self.thumb = kwargs.get('thumb')
self.file_size = int(kwargs.get('file_size', 0))
@staticmethod
def de_json(data):
if 'thumb' in data:
from telegram import PhotoSize
thumb = PhotoSize.de_json(data['thumb'])
else:
thumb = None
"""
Args:
data (str):
return Sticker(file_id=data.get('file_id', None),
width=data.get('width', None),
height=data.get('height', None),
thumb=thumb,
file_size=data.get('file_size', None))
Returns:
telegram.Sticker:
"""
if not data:
return None
def to_dict(self):
data = {'file_id': self.file_id,
'width': self.width,
'height': self.height,
'thumb': self.thumb.to_dict()}
if self.file_size:
data['file_size'] = self.file_size
return data
return Sticker(**data)
+30 -15
View File
@@ -16,30 +16,45 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Update"""
from telegram import TelegramObject
from telegram import Message, TelegramObject
class Update(TelegramObject):
"""This object represents a Telegram Update.
Attributes:
update_id (int):
message (:class:`telegram.Message`):
Args:
update_id (int):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
message (Optional[:class:`telegram.Message`]):
"""
def __init__(self,
update_id,
message=None):
**kwargs):
# Required
self.update_id = update_id
self.message = message
# Optionals
self.message = kwargs.get('message')
@staticmethod
def de_json(data):
if 'message' in data:
from telegram import Message
message = Message.de_json(data['message'])
else:
message = None
"""
Args:
data (str):
return Update(update_id=data.get('update_id', None),
message=message)
Returns:
telegram.Update:
"""
if not data:
return None
def to_dict(self):
data = {'update_id': self.update_id}
if self.message:
data['message'] = self.message.to_dict()
return data
data['message'] = Message.de_json(data['message'])
return Update(**data)
+37 -17
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python
# pylint: disable=C0103,W0622
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
@@ -16,23 +17,44 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram User"""
from telegram import TelegramObject
class User(TelegramObject):
"""This object represents a Telegram Sticker.
Attributes:
id (int):
first_name (str):
last_name (str):
username (str):
Args:
id (int):
first_name (str):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
last_name (Optional[str]):
username (Optional[str]):
"""
def __init__(self,
id,
first_name,
last_name=None,
username=None):
self.id = id
**kwargs):
# Required
self.id = int(id)
self.first_name = first_name
self.last_name = last_name
self.username = username
# Optionals
self.last_name = kwargs.get('last_name', '')
self.username = kwargs.get('username', '')
@property
def name(self):
"""str: """
if self.username:
return '@%s' % self.username
if self.last_name:
@@ -41,16 +63,14 @@ class User(TelegramObject):
@staticmethod
def de_json(data):
return User(id=data.get('id', None),
first_name=data.get('first_name', None),
last_name=data.get('last_name', None),
username=data.get('username', None))
"""
Args:
data (str):
def to_dict(self):
data = {'id': self.id,
'first_name': self.first_name}
if self.last_name:
data['last_name'] = self.last_name
if self.username:
data['username'] = self.username
return data
Returns:
telegram.User:
"""
if not data:
return None
return User(**data)
+38 -18
View File
@@ -16,36 +16,56 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram
UserProfilePhotos"""
from telegram import TelegramObject
from telegram import PhotoSize, TelegramObject
class UserProfilePhotos(TelegramObject):
"""This object represents a Telegram UserProfilePhotos.
Attributes:
total_count (int):
photos (List[List[:class:`telegram.PhotoSize`]]):
Args:
total_count (int):
photos (List[List[:class:`telegram.PhotoSize`]]):
"""
def __init__(self,
total_count,
photos):
self.total_count = total_count
# Required
self.total_count = int(total_count)
self.photos = photos
@staticmethod
def de_json(data):
if 'photos' in data:
from telegram import PhotoSize
photos = []
for photo in data['photos']:
photos.append([PhotoSize.de_json(x) for x in photo])
else:
photos = None
"""
Args:
data (str):
return UserProfilePhotos(total_count=data.get('total_count', None),
photos=photos)
Returns:
telegram.UserProfilePhotos:
"""
if not data:
return None
data['photos'] = [PhotoSize.de_list(photo) for photo in data['photos']]
return UserProfilePhotos(**data)
def to_dict(self):
data = {}
if self.total_count:
data['total_count'] = self.total_count
if self.photos:
data['photos'] = []
for photo in self.photos:
data['photos'].append([x.to_dict() for x in photo])
"""
Returns:
dict:
"""
data = super(UserProfilePhotos, self).to_dict()
data['photos'] = []
for photo in self.photos:
data['photos'].append([x.to_dict() for x in photo])
return data
+44 -34
View File
@@ -16,52 +16,62 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Video"""
from telegram import TelegramObject
from telegram import PhotoSize, TelegramObject
class Video(TelegramObject):
"""This object represents a Telegram Video.
Attributes:
file_id (str):
width (int):
height (int):
duration (int):
thumb (:class:`telegram.PhotoSize`):
mime_type (str):
file_size (int):
Args:
file_id (str):
width (int):
height (int):
duration (int):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
thumb (Optional[:class:`telegram.PhotoSize`]):
mime_type (Optional[str]):
file_size (Optional[int]):
"""
def __init__(self,
file_id,
width,
height,
duration,
thumb=None,
mime_type=None,
file_size=None):
**kwargs):
# Required
self.file_id = file_id
self.width = width
self.height = height
self.duration = duration
self.thumb = thumb
self.mime_type = mime_type
self.file_size = file_size
self.width = int(width)
self.height = int(height)
self.duration = int(duration)
# Optionals
self.thumb = kwargs.get('thumb')
self.mime_type = kwargs.get('mime_type', '')
self.file_size = int(kwargs.get('file_size', 0))
@staticmethod
def de_json(data):
if 'thumb' in data:
from telegram import PhotoSize
thumb = PhotoSize.de_json(data['thumb'])
else:
thumb = None
"""
Args:
data (str):
return Video(file_id=data.get('file_id', None),
width=data.get('width', None),
height=data.get('height', None),
duration=data.get('duration', None),
thumb=thumb,
mime_type=data.get('mime_type', None),
file_size=data.get('file_size', None))
Returns:
telegram.Video:
"""
if not data:
return None
def to_dict(self):
data = {'file_id': self.file_id,
'width': self.width,
'height': self.height,
'duration': self.duration}
if self.thumb:
data['thumb'] = self.thumb.to_dict()
if self.mime_type:
data['mime_type'] = self.mime_type
if self.file_size:
data['file_size'] = self.file_size
return data
return Video(**data)
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Voice"""
from telegram import TelegramObject
class Voice(TelegramObject):
"""This object represents a Telegram Voice.
Attributes:
file_id (str):
duration (int):
mime_type (str):
file_size (int):
Args:
file_id (str):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
duration (Optional[int]):
mime_type (Optional[str]):
file_size (Optional[int]):
"""
def __init__(self,
file_id,
**kwargs):
# Required
self.file_id = file_id
# Optionals
self.duration = int(kwargs.get('duration', 0))
self.mime_type = kwargs.get('mime_type', '')
self.file_size = int(kwargs.get('file_size', 0))
@staticmethod
def de_json(data):
"""
Args:
data (str):
Returns:
telegram.Voice:
"""
if not data:
return None
return Voice(**data)
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import logging
import unittest
from tests.test_bot import BotTest
if __name__ == '__main__':
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
testsuite = unittest.TestLoader().loadTestsFromTestCase(BotTest)
unittest.TextTestRunner(verbosity=1).run(testsuite)
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

+157 -51
View File
@@ -19,138 +19,244 @@
import os
import sys
sys.path.append('.')
import json
import telegram
import unittest
from datetime import datetime
class BotTest(unittest.TestCase):
@staticmethod
def is_json(string):
try:
json.loads(string)
except ValueError:
return False
return True
def setUp(self):
bot = telegram.Bot(token=os.environ.get('TOKEN'))
chat_id = os.environ.get('CHAT_ID')
self._bot = bot
self._chat_id = chat_id
print('Testing the Bot API class')
def testGetMe(self):
'''Test the telegram.Bot getMe method'''
print('Testing getMe')
bot = self._bot.getMe()
self.assertEqual(120405045, bot.id)
self.assertEqual('Toledo\'s Palace Bot', bot.first_name)
self.assertEqual(None, bot.last_name)
self.assertEqual('ToledosPalaceBot', bot.username)
self.assertTrue(self.is_json(bot.to_json()))
self.assertEqual(bot.id, 120405045)
self.assertEqual(bot.first_name, 'Toledo\'s Palace Bot')
self.assertEqual(bot.last_name, '')
self.assertEqual(bot.username, 'ToledosPalaceBot')
self.assertEqual(bot.name, '@ToledosPalaceBot')
def testSendMessage(self):
'''Test the telegram.Bot sendMessage method'''
print('Testing sendMessage')
message = self._bot.sendMessage(chat_id=12173560,
message = self._bot.sendMessage(chat_id=self._chat_id,
text='Моё судно на воздушной подушке полно угрей')
self.assertEqual(u'Моё судно на воздушной подушке полно угрей', message.text)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.text, u'Моё судно на воздушной подушке полно угрей')
self.assertTrue(isinstance(message.date, datetime))
def testGetUpdates(self):
'''Test the telegram.Bot getUpdates method'''
print('Testing getUpdates')
updates = self._bot.getUpdates()
self.assertIsInstance(updates[0], telegram.Update)
if updates:
self.assertTrue(self.is_json(updates[0].to_json()))
self.assertTrue(isinstance(updates[0], telegram.Update))
def testForwardMessage(self):
'''Test the telegram.Bot forwardMessage method'''
print('Testing forwardMessage')
message = self._bot.forwardMessage(chat_id=12173560,
from_chat_id=12173560,
message = self._bot.forwardMessage(chat_id=self._chat_id,
from_chat_id=self._chat_id,
message_id=138)
self.assertEqual('Oi', message.text)
self.assertEqual('leandrotoledo', message.forward_from.username)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.text, 'Oi')
self.assertEqual(message.forward_from.username, 'leandrotoledo')
self.assertTrue(isinstance(message.forward_date, datetime))
def testSendPhoto(self):
'''Test the telegram.Bot sendPhoto method'''
print('Testing sendPhoto - File')
message = self._bot.sendPhoto(photo=open('tests/telegram.png', 'rb'),
message = self._bot.sendPhoto(photo=open('tests/data/telegram.png', 'rb'),
caption='testSendPhoto',
chat_id=12173560)
self.assertEqual(1451, message.photo[0].file_size)
self.assertEqual('testSendPhoto', message.caption)
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.photo[0].file_size, 1451)
self.assertEqual(message.caption, 'testSendPhoto')
def testResendPhoto(self):
'''Test the telegram.Bot sendPhoto method'''
print('Testing sendPhoto - Resend')
message = self._bot.sendPhoto(photo=str('AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI'),
chat_id=12173560)
self.assertEqual('AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI', message.photo[0].file_id)
message = self._bot.sendPhoto(photo='AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI',
chat_id=self._chat_id)
def testSendURLPhoto(self):
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.photo[0].file_id, 'AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI')
def testSendJPGURLPhoto(self):
'''Test the telegram.Bot sendPhoto method'''
print('Testing sendPhoto - URL')
message = self._bot.sendPhoto(photo=str('http://dummyimage.com/600x400/000/fff.jpg&text=telegram'),
chat_id=12173560)
self.assertEqual(822, message.photo[0].file_size)
print('Testing testSendJPGURLPhoto - URL')
message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.jpg&text=telegram',
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.photo[0].file_size, 822)
def testSendPNGURLPhoto(self):
'''Test the telegram.Bot sendPhoto method'''
print('Testing testSendPNGURLPhoto - URL')
message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.png&text=telegram',
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.photo[0].file_size, 684)
def testSendGIFURLPhoto(self):
'''Test the telegram.Bot sendPhoto method'''
print('Testing testSendGIFURLPhoto - URL')
message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.gif&text=telegram',
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.photo[0].file_size, 684)
def testSendAudio(self):
'''Test the telegram.Bot sendAudio method'''
print('Testing sendAudio - File')
message = self._bot.sendAudio(audio=open('tests/telegram.ogg', 'rb'),
chat_id=12173560)
self.assertEqual(9199, message.audio.file_size)
message = self._bot.sendAudio(audio=open('tests/data/telegram.mp3', 'rb'),
chat_id=self._chat_id,
performer='Leandro Toledo',
title='Teste')
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.audio.file_size, 28232)
self.assertEqual(message.audio.performer, 'Leandro Toledo')
self.assertEqual(message.audio.title, 'Teste')
def testResendAudio(self):
'''Test the telegram.Bot sendAudio method'''
print('Testing sendAudio - Resend')
message = self._bot.sendAudio(audio=str('AwADAQADIQEAAvjAuQABSAXg_GhkhZcC'),
chat_id=12173560)
self.assertEqual('AwADAQADIQEAAvjAuQABSAXg_GhkhZcC', message.audio.file_id)
message = self._bot.sendAudio(audio='BQADAQADwwcAAjU8LQdBRsl3_qD2TAI',
chat_id=self._chat_id,
performer='Leandro Toledo', # Bug #39
title='Teste') # Bug #39
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.audio.file_id, 'BQADAQADwwcAAjU8LQdBRsl3_qD2TAI')
def testSendVoice(self):
'''Test the telegram.Bot sendVoice method'''
print('Testing sendVoice - File')
message = self._bot.sendVoice(voice=open('tests/data/telegram.ogg', 'rb'),
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.voice.file_size, 9199)
def testResendVoice(self):
'''Test the telegram.Bot sendVoice method'''
print('Testing sendVoice - Resend')
message = self._bot.sendVoice(voice='AwADAQADIQEAAvjAuQABSAXg_GhkhZcC',
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.voice.file_id, 'AwADAQADIQEAAvjAuQABSAXg_GhkhZcC')
def testSendDocument(self):
'''Test the telegram.Bot sendDocument method'''
print('Testing sendDocument - File')
message = self._bot.sendDocument(document=open('tests/telegram.png', 'rb'),
chat_id=12173560)
self.assertEqual(12948, message.document.file_size)
message = self._bot.sendDocument(document=open('tests/data/telegram.png', 'rb'),
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.document.file_size, 12948)
def testSendGIFURLDocument(self):
'''Test the telegram.Bot sendDocument method'''
print('Testing sendDocument - File')
message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.gif&text=telegram',
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.photo[0].file_size, 684)
def testResendDocument(self):
'''Test the telegram.Bot sendDocument method'''
print('Testing sendDocument - Resend')
message = self._bot.sendDocument(document=str('BQADAQADHAADNTwtBxZxUGKyxYbYAg'),
chat_id=12173560)
self.assertEqual('BQADAQADHAADNTwtBxZxUGKyxYbYAg', message.document.file_id)
message = self._bot.sendDocument(document='BQADAQADHAADNTwtBxZxUGKyxYbYAg',
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.document.file_id, 'BQADAQADHAADNTwtBxZxUGKyxYbYAg')
def testSendVideo(self):
'''Test the telegram.Bot sendVideo method'''
print('Testing sendVideo - File')
message = self._bot.sendVideo(video=open('tests/telegram.mp4', 'rb'),
message = self._bot.sendVideo(video=open('tests/data/telegram.mp4', 'rb'),
caption='testSendVideo',
chat_id=12173560)
self.assertEqual(326534, message.video.file_size)
self.assertEqual('testSendVideo', message.caption)
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.video.file_size, 326534)
self.assertEqual(message.caption, 'testSendVideo')
def testResendVideo(self):
'''Test the telegram.Bot sendVideo method'''
print('Testing sendVideo - Resend')
message = self._bot.sendVideo(video=str('BAADAQADIgEAAvjAuQABOuTB937fPTgC'),
chat_id=12173560)
self.assertEqual(4, message.video.duration)
message = self._bot.sendVideo(video='BAADAQADIgEAAvjAuQABOuTB937fPTgC',
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.video.duration, 4)
def testResendSticker(self):
'''Test the telegram.Bot sendSticker method'''
print('Testing sendSticker - Resend')
message = self._bot.sendSticker(sticker=str('BQADAQADHAADyIsGAAFZfq1bphjqlgI'),
chat_id=12173560)
self.assertEqual(39518, message.sticker.file_size)
message = self._bot.sendSticker(sticker='BQADAQADHAADyIsGAAFZfq1bphjqlgI',
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.sticker.file_size, 39518)
def testSendLocation(self):
'''Test the telegram.Bot sendLocation method'''
print('Testing sendLocation')
message = self._bot.sendLocation(latitude=-23.558873,
longitude=-46.659732,
chat_id=12173560)
self.assertEqual(-23.558873, message.location.latitude)
self.assertEqual(-46.659732, message.location.longitude)
chat_id=self._chat_id)
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.location.latitude, -23.558873)
self.assertEqual(message.location.longitude, -46.659732)
def testSendChatAction(self):
'''Test the telegram.Bot sendChatAction method'''
print('Testing sendChatAction - ChatAction.TYPING')
self._bot.sendChatAction(action=telegram.ChatAction.TYPING,
chat_id=12173560)
chat_id=self._chat_id)
def testGetUserProfilePhotos(self):
'''Test the telegram.Bot getUserProfilePhotos method'''
print('Testing getUserProfilePhotos')
upf = self._bot.getUserProfilePhotos(user_id=12173560)
self.assertEqual(6547, upf.photos[0][0].file_size)
upf = self._bot.getUserProfilePhotos(user_id=self._chat_id)
self.assertTrue(self.is_json(upf.to_json()))
self.assertEqual(upf.photos[0][0].file_size, 6547)
unittest.main()