Compare commits

...

15 Commits

Author SHA1 Message Date
Jannes Höke 71530f404d Bump version to v5.3.0 2016-12-11 23:51:51 +01:00
Jannes Höke 0cd7ecab50 fix test_filters_reply 2016-12-11 23:16:10 +01:00
Jeong Arm c5f9e53d44 Add "reply" filter (#465)
* Add "reply" filter

This filter will filter messages that reply to other's message.

* Add test for "reply" filter

* Add "Kjwon15" to AUTHORS.rst
2016-12-11 22:45:51 +01:00
Noam Meltzer acf1541395 Botapi2.3 (#471)
* New fields channel_post and edited_channel_post for Update

refs #468

* setGameScore() changes

 - Changed behaviour: messages with high scores will be update with new
   high scores by default. (documentation fix)
 - Use (new) disable_edit_message in setGameScore to disable the above new
   behaviour.
 - The edit_message parameter from setGameScore is no longer in use. For
   backward compatibility, it will be taken into account for a while,
   unless disable_edit_message is passed explicitly.

refs #468

* New field forward_from_message_id for Message.

refs #468

* New parameter cache_time for answerCallbackQuery

refs #468

* replykeyboardhide renamed to replykeyboardremove

refs #468

* Unitests for updated setGameScore semantics

refs #468

* Backward compatibility for ReplyKeyboardHide

refs #468

* Fix docstrings of wrapper methods in Message

* Unitest new field forward_from_message_id of Message

refs #468

* Fix testMaxCaptionLength

Telegram servers changed their behaviour - now they truncate a long
caption instead of returning an error.

* MessageHandler: Added support for channel posts

* Fix flake8 complaints in a manner which yapf will like it too.

* fix rst markup
2016-12-11 22:44:52 +01:00
Jacob Bom 906a1b8d7d message.edit_reply_markup now correctly edits reply_markup (#473) 2016-12-08 13:23:51 +01:00
lisitsky a2fddbe85c Fix telegram API change, returning '404 Not found' (#461)
* Fix telegram API change, returning '404 Not found' with raising own TelegramError rather native exception

* Change exception to InvalidToken in test and request util

* Added myself to AUTHORS. Thx for appreciation :)
2016-11-09 14:36:42 +01:00
Wesley Gahr 68e87db909 Job queue time units (#452)
* Adding timeunit and day support to the jobqueue

* Adding tests

* Changed the file permission back to 644.

* Changed AssertEqual argument order to (actual, expectd).

* Removed the TimeUnit enum and unit param, instead use datetime.time for interval.

* Removing the TimeUnits enum and unit param in favour of optionally using a datetime.time as the interval.

* Removing the TimeUnits enumeration, forgot the remove it in the last one.

* Removed some old docstrings refering to the TimeUnits enum.

* Removed the old TimeUnits import.

* Adding some error handling for the 'days' argument (only a 'tuple' with 'Days')

* Writing the error message directly in the exception.

* Moving a debug statement wrongfully saying a job would be running on days it wouldn't.

* Writing error messages directly in the exceptions instead of making an extra variable.

* Replacing datetime.time in favour of datetime.timedelta because of the get_seconds() method.

* Adding error handling for the method .

* Splitting the tests up in multiple ones, no float test because I haven't found a reliable way to test it.

* Excluding .exrc file.

* Removing \ at EOF of ValueError.

* Replacing Enums with plain new-style classes.

* Using numbers.number to check for ints/floats instead of seperate int/float checks.

* Fixing typo, number -> Number.

* Changed lower_case Days attributes to UPPER_CASE.

* Different formatting for Days class, removed the get_days function in favour of a tuple.

* Removed redundant function get_days.

* Edited the docstring for next_t to also take datetime.timedelta.

* Removed for-loop in favour of any().

* Changed docstring for interval.

* Removed debug print.

* Changing some docstrings.

* Changing some docstrings (again).
2016-11-08 23:39:25 +01:00
Blue a7bfb0c3a1 hide inline keyboard in conversationbot example (#439) 2016-11-08 22:14:11 +01:00
Jannes Höke e76ee6bb57 [ci skip] docs: add even more missing classes (wtf) 2016-11-01 09:37:03 +01:00
Jannes Höke 65061f8a99 [ci skip] docs: add all missing classes 2016-11-01 09:01:36 +01:00
Jannes Höke dabbbcafcb [ci skip] docs: remove superfluous text in index.rst 2016-11-01 08:15:51 +01:00
Jannes Höke 1eb4b40dbf [ci skip] docs: add logo to html and pdf builds 2016-11-01 08:09:25 +01:00
Jannes Höke 7167936692 [ci skip] pdf docs: use a4paper, update motto 2016-11-01 07:54:04 +01:00
Jannes Höke aa3ca38837 Sphinx restructuring: Now builds PDF and better HTML docs (#449)
* update sphinx source files to properly build latexpdf and improve html build

* fix docstrings and sphinx sources to get rid of warnings

* add telegram.contrib.rst
2016-11-01 06:53:51 +01:00
Jannes Höke b22c3cc5c0 [ci skip] add state diagrams for conversation handler examples 2016-10-28 08:26:02 +02:00
86 changed files with 684 additions and 217 deletions
+3
View File
@@ -71,3 +71,6 @@ telegram.webp
# original files from merges
*.orig
# Exclude .exrc file for Vim
.exrc
+3
View File
@@ -13,12 +13,14 @@ The following wonderful people contributed directly or indirectly to this projec
- `bimmlerd <https://github.com/bimmlerd>`_
- `Eli Gao <https://github.com/eligao>`_
- `ErgoZ Riftbit Vaper <https://github.com/ergoz>`_
- `Eugene Lisitsky <https://github.com/lisitsky>`_
- `franciscod <https://github.com/franciscod>`_
- `Jacob Bom <https://github.com/bomjacob>`_
- `JASON0916 <https://github.com/JASON0916>`_
- `jh0ker <https://github.com/jh0ker>`_
- `JRoot3D <https://github.com/JRoot3D>`_
- `jlmadurga <https://github.com/jlmadurga>`_
- `Kjwon15 <https://github.com/kjwon15>`_
- `Li-aung Yip <https://github.com/LiaungYip>`_
- `macrojames <https://github.com/macrojames>`_
- `Michael Elovskikh <https://github.com/wronglink>`_
@@ -32,6 +34,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Shelomentsev D <https://github.com/shelomentsevd>`_
- `sooyhwang <https://github.com/sooyhwang>`_
- `Valentijn <https://github.com/Faalentijn>`_
- `voider1 <https://github.com/voider1>`_
- `wjt <https://github.com/wjt>`_
Please add yourself here alphabetically when you submit your first pull request.
+11
View File
@@ -2,6 +2,17 @@
Changes
=======
**2016-12-11**
*Released 5.3*
- Implement API changes of November 21st (Bot API 2.3)
- ``JobQueue`` now supports ``datetime.timedelta`` in addition to seconds
- ``JobQueue`` now supports running jobs only on certain days
- New ``Filters.reply`` filter
- Bugfix for ``Message.edit_reply_markup``
- Other bugfixes
**2016-10-25**
*Released 5.2*
+11 -8
View File
@@ -59,9 +59,9 @@ author = u'Leandro Toledo'
# built documents.
#
# The short X.Y version.
version = '5.2' # telegram.__version__[:3]
version = '5.3' # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = '5.2.0' # telegram.__version__
release = '5.3.0' # telegram.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -131,7 +131,7 @@ html_theme = 'sphinx_rtd_theme'
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
html_logo = 'ptb-logo-orange.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
@@ -209,14 +209,17 @@ htmlhelp_basename = 'PythonTelegramBotdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
'papersize': 'a4paper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
'preamble': r'''\setcounter{tocdepth}{2}
\usepackage{enumitem}
\setlistdepth{99}''',
# Latex figure (float) alignment
#'figure_align': 'htbp',
@@ -227,12 +230,12 @@ latex_elements = {
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'PythonTelegramBot.tex', u'Python Telegram Bot Documentation',
u'Leandro Toledo', 'manual'),
author, 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
latex_logo = 'ptb-logo_1024.png'
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
@@ -271,7 +274,7 @@ man_pages = [
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'PythonTelegramBot', u'Python Telegram Bot Documentation',
author, 'PythonTelegramBot', 'Not just a Python wrapper around the Telegram Bot API',
author, 'PythonTelegramBot', "We have made you a wrapper you can't refuse",
'Miscellaneous'),
]
+1 -5
View File
@@ -6,12 +6,8 @@
Welcome to Python Telegram Bot's documentation!
===============================================
Contents:
telegram
.. toctree::
:maxdepth: 2
telegram
Indices and tables
-7
View File
@@ -1,7 +0,0 @@
telegram
========
.. toctree::
:maxdepth: 4
telegram
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

+7
View File
@@ -0,0 +1,7 @@
telegram.animation module
=========================
.. automodule:: telegram.animation
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.callbackgame module
============================
.. automodule:: telegram.callbackgame
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.callbackquery module
=============================
.. automodule:: telegram.callbackquery
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.chatmember module
==========================
.. automodule:: telegram.chatmember
:members:
:undoc-members:
:show-inheritance:
+17
View File
@@ -0,0 +1,17 @@
telegram.contrib package
========================
Submodules
----------
.. toctree::
telegram.contrib.botan
Module contents
---------------
.. automodule:: telegram.contrib
:members:
:undoc-members:
:show-inheritance:
+1
View File
@@ -10,6 +10,7 @@ Submodules
telegram.ext.dispatcher
telegram.ext.jobqueue
telegram.ext.handler
telegram.ext.callbackqueryhandler
telegram.ext.choseninlineresulthandler
telegram.ext.conversationhandler
telegram.ext.commandhandler
+7
View File
@@ -0,0 +1,7 @@
telegram.file module
====================
.. automodule:: telegram.file
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.game module
====================
.. automodule:: telegram.game
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.gamehighscore module
=============================
.. automodule:: telegram.gamehighscore
:members:
:undoc-members:
:show-inheritance:
@@ -1,5 +1,5 @@
telegram.inlinekeyboardbutton module
===========================
====================================
.. automodule:: telegram.inlinekeyboardbutton
:members:
@@ -1,5 +1,5 @@
telegram.inlinekeyboardmarkup module
==========================
====================================
.. automodule:: telegram.inlinekeyboardmarkup
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultarticle module
=================================
========================================
.. automodule:: telegram.inlinequeryresultarticle
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultaudio module
=================================
======================================
.. automodule:: telegram.inlinequeryresultaudio
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedaudio module
=================================
============================================
.. automodule:: telegram.inlinequeryresultcachedaudio
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcacheddocument module
=================================
===============================================
.. automodule:: telegram.inlinequeryresultcacheddocument
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedgif module
=================================
==========================================
.. automodule:: telegram.inlinequeryresultcachedgif
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedmpeg4gif module
=================================
===============================================
.. automodule:: telegram.inlinequeryresultcachedmpeg4gif
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedphoto module
=================================
============================================
.. automodule:: telegram.inlinequeryresultcachedphoto
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedsticker module
=================================
==============================================
.. automodule:: telegram.inlinequeryresultcachedsticker
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedvideo module
=================================
============================================
.. automodule:: telegram.inlinequeryresultcachedvideo
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedvoice module
=================================
============================================
.. automodule:: telegram.inlinequeryresultcachedvoice
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcontact module
=================================
========================================
.. automodule:: telegram.inlinequeryresultcontact
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultdocument module
=================================
=========================================
.. automodule:: telegram.inlinequeryresultdocument
:members:
@@ -0,0 +1,7 @@
telegram.inlinequeryresultgame module
=====================================
.. automodule:: telegram.inlinequeryresultgame
:members:
:undoc-members:
:show-inheritance:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultgif module
=================================
====================================
.. automodule:: telegram.inlinequeryresultgif
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultlocation module
=================================
=========================================
.. automodule:: telegram.inlinequeryresultlocation
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultmpeg4gif module
=================================
=========================================
.. automodule:: telegram.inlinequeryresultmpeg4gif
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultphoto module
=================================
======================================
.. automodule:: telegram.inlinequeryresultphoto
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultvenue module
=================================
======================================
.. automodule:: telegram.inlinequeryresultvenue
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultvideo module
=================================
======================================
.. automodule:: telegram.inlinequeryresultvideo
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultvoice module
=================================
======================================
.. automodule:: telegram.inlinequeryresultvoice
:members:
@@ -0,0 +1,7 @@
telegram.inputcontactmessagecontent module
==========================================
.. automodule:: telegram.inputcontactmessagecontent
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.inputlocationmessagecontent module
===========================================
.. automodule:: telegram.inputlocationmessagecontent
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.inputmessagecontent module
===================================
.. automodule:: telegram.inputmessagecontent
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.inputtextmessagecontent module
=======================================
.. automodule:: telegram.inputtextmessagecontent
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.inputvenuemessagecontent module
========================================
.. automodule:: telegram.inputvenuemessagecontent
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.keyboardbutton module
==============================
.. automodule:: telegram.keyboardbutton
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.messageentity module
=============================
.. automodule:: telegram.messageentity
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.parsemode module
=========================
.. automodule:: telegram.parsemode
:members:
:undoc-members:
:show-inheritance:
@@ -1,7 +0,0 @@
telegram.replykeyboardhide module
=================================
.. automodule:: telegram.replykeyboardhide
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.replykeyboardremove module
===================================
.. automodule:: telegram.replykeyboardremove
:members:
:undoc-members:
:show-inheritance:
+31 -13
View File
@@ -6,14 +6,30 @@ Submodules
.. toctree::
telegram.contrib
telegram.ext
telegram.animation
telegram.audio
telegram.base
telegram.bot
telegram.ext
telegram.inlinequery
telegram.inlinequeryresult
telegram.callbackgame
telegram.callbackquery
telegram.chat
telegram.chataction
telegram.chatmember
telegram.choseninlineresult
telegram.constants
telegram.contact
telegram.document
telegram.error
telegram.file
telegram.forcereply
telegram.game
telegram.gamehighscore
telegram.inlinekeyboardbutton
telegram.inlinekeyboardmarkup
telegram.inlinequery
telegram.inlinequeryresult
telegram.inlinequeryresultarticle
telegram.inlinequeryresultaudio
telegram.inlinequeryresultcachedaudio
@@ -26,6 +42,7 @@ Submodules
telegram.inlinequeryresultcachedvoice
telegram.inlinequeryresultcontact
telegram.inlinequeryresultdocument
telegram.inlinequeryresultgame
telegram.inlinequeryresultgif
telegram.inlinequeryresultlocation
telegram.inlinequeryresultmpeg4gif
@@ -33,28 +50,29 @@ Submodules
telegram.inlinequeryresultvenue
telegram.inlinequeryresultvideo
telegram.inlinequeryresultvoice
telegram.choseninlineresult
telegram.chataction
telegram.contact
telegram.document
telegram.emoji
telegram.error
telegram.forcereply
telegram.chat
telegram.inputcontactmessagecontent
telegram.inputfile
telegram.inputlocationmessagecontent
telegram.inputmessagecontent
telegram.inputtextmessagecontent
telegram.inputvenuemessagecontent
telegram.keyboardbutton
telegram.location
telegram.message
telegram.nullhandler
telegram.messageentity
telegram.parsemode
telegram.photosize
telegram.replykeyboardhide
telegram.replykeyboardremove
telegram.replykeyboardmarkup
telegram.replymarkup
telegram.sticker
telegram.update
telegram.user
telegram.userprofilephotos
telegram.venue
telegram.video
telegram.voice
telegram.webhookinfo
Module contents
---------------
+7
View File
@@ -0,0 +1,7 @@
telegram.venue module
=====================
.. automodule:: telegram.venue
:members:
:undoc-members:
:show-inheritance:
@@ -1,7 +1,7 @@
telegram.nullhandler module
telegram.webhookinfo module
===========================
.. automodule:: telegram.nullhandler
.. automodule:: telegram.webhookinfo
:members:
:undoc-members:
:show-inheritance:
+2 -2
View File
@@ -11,10 +11,10 @@ This is probably the base for most of the bots made with `python-telegram-bot`.
This bot uses the [`JobQueue`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.jobqueue.html) class to send timed messages. The user sets a timer by using `/set` command with a specific time, for example `/set 30`. The bot then sets up a job to send a message to that user after 30 seconds. The user can also cancel the timer by sending `/unset`. To learn more about the `JobQueue`, read [this wiki article](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-JobQueue).
### [`conversationbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.py)
A common task for a bot is to ask information from the user. In v5.0 of this library, we introduced the [`ConversationHandler`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.conversationhandler.html) for that exact purpose. This example uses it to retrieve user-information in a conversation-like style.
A common task for a bot is to ask information from the user. In v5.0 of this library, we introduced the [`ConversationHandler`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.conversationhandler.html) for that exact purpose. This example uses it to retrieve user-information in a conversation-like style. To get a better understanding, take a look at the [state diagram](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.png).
### [`conversationbot2.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot2.py)
A more complex example of a bot that uses the `ConversationHandler`
A more complex example of a bot that uses the `ConversationHandler`. It is also more confusing. Good thing there is a [fancy state diagram](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot2.png) for this one, too!
### [`inlinekeyboard.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/inlinekeyboard.py)
This example sheds some light on inline keyboards, callback queries and message editing.
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

+5 -3
View File
@@ -17,7 +17,7 @@ Press Ctrl-C on the command line or send a signal to the process to stop the
bot.
"""
from telegram import (ReplyKeyboardMarkup)
from telegram import (ReplyKeyboardMarkup, ReplyKeyboardRemove)
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters, RegexHandler,
ConversationHandler)
@@ -48,7 +48,8 @@ def gender(bot, update):
user = update.message.from_user
logger.info("Gender of %s: %s" % (user.first_name, update.message.text))
update.message.reply_text('I see! Please send me a photo of yourself, '
'so I know what you look like, or send /skip if you don\'t want to.')
'so I know what you look like, or send /skip if you don\'t want to.',
reply_markup=ReplyKeyboardRemove())
return PHOTO
@@ -104,7 +105,8 @@ def bio(bot, update):
def cancel(bot, update):
user = update.message.from_user
logger.info("User %s canceled the conversation." % user.first_name)
update.message.reply_text('Bye! I hope we can talk again some day.')
update.message.reply_text('Bye! I hope we can talk again some day.',
reply_markup=ReplyKeyboardRemove())
return ConversationHandler.END
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

+1 -1
View File
@@ -30,7 +30,7 @@ with codecs.open('README.rst', 'r', 'utf-8') as fd:
license='LGPLv3',
url='https://python-telegram-bot.org/',
keywords='python telegram bot api wrapper',
description='Not just a Python wrapper around the Telegram Bot API',
description="We have made you a wrapper you can't refuse",
long_description=fd.read(),
packages=find_packages(exclude=['tests*']),
install_requires=requirements(),
+4 -4
View File
@@ -38,7 +38,7 @@ from .userprofilephotos import UserProfilePhotos
from .keyboardbutton import KeyboardButton
from .replymarkup import ReplyMarkup
from .replykeyboardmarkup import ReplyKeyboardMarkup
from .replykeyboardhide import ReplyKeyboardHide
from .replykeyboardremove import ReplyKeyboardRemove, ReplyKeyboardHide
from .forcereply import ForceReply
from .error import TelegramError
from .inputfile import InputFile
@@ -106,9 +106,9 @@ __all__ = [
'InlineQueryResultVoice', 'InlineQueryResultGame', 'InputContactMessageContent', 'InputFile',
'InputLocationMessageContent', 'InputMessageContent', 'InputTextMessageContent',
'InputVenueMessageContent', 'KeyboardButton', 'Location', 'Message', 'MessageEntity',
'ParseMode', 'PhotoSize', 'ReplyKeyboardHide', 'ReplyKeyboardMarkup', 'ReplyMarkup', 'Sticker',
'TelegramError', 'TelegramObject', 'Update', 'User', 'UserProfilePhotos', 'Venue', 'Video',
'Voice', 'MAX_MESSAGE_LENGTH', 'MAX_CAPTION_LENGTH', 'SUPPORTED_WEBHOOK_PORTS',
'ParseMode', 'PhotoSize', 'ReplyKeyboardRemove', 'ReplyKeyboardMarkup', 'ReplyMarkup',
'Sticker', 'TelegramError', 'TelegramObject', 'Update', 'User', 'UserProfilePhotos', 'Venue',
'Video', 'Voice', 'MAX_MESSAGE_LENGTH', 'MAX_CAPTION_LENGTH', 'SUPPORTED_WEBHOOK_PORTS',
'MAX_FILESIZE_DOWNLOAD', 'MAX_FILESIZE_UPLOAD', 'MAX_MESSAGES_PER_SECOND_PER_CHAT',
'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation',
'Game', 'GameHighScore'
+7 -2
View File
@@ -14,5 +14,10 @@ def print_ver_info():
print('future {0}'.format(future.__version__))
print('Python {0}'.format(sys.version.replace('\n', ' ')))
# main
print_ver_info()
def main():
print_ver_info()
if __name__ == '__main__':
main()
+64 -25
View File
@@ -21,6 +21,7 @@
import functools
import logging
import warnings
from telegram import (User, Message, Update, Chat, ChatMember, UserProfilePhotos, File,
ReplyMarkup, TelegramObject, WebhookInfo, GameHighScore)
@@ -208,7 +209,7 @@ class Bot(TelegramObject):
ID of the original message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional
interface options. A JSON-serialized object for an inline
keyboard, custom reply keyboard, instructions to hide reply
keyboard, custom reply keyboard, instructions to remove reply
keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as
the definitive timeout (in seconds) for urlopen() operations.
@@ -299,7 +300,7 @@ class Bot(TelegramObject):
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -347,20 +348,20 @@ class Bot(TelegramObject):
Args:
chat_id: Unique identifier for the message recipient - Chat id.
audio Audio file to send. You can either pass a file_id as String to resend an audio
audio: 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 (Optional[int]): Duration of sent audio in seconds.
performer: Performer of sent audio. [Optional]
title: Title of sent audio. [Optional]
caption: Audio caption [Optional]
performer (Optional[str]): Performer of sent audio.
title (Optional[str]): Title of sent audio.
caption (Optional[str]): Audio caption
disable_notification (Optional[bool]): Sends the message silently. iOS users will not
receive a notification, Android users will receive a notification with no sound.
reply_to_message_id (Optional[int]): If the message is a reply, ID of the original
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -405,8 +406,8 @@ class Bot(TelegramObject):
chat_id: Unique identifier for the message recipient - Chat id.
document: File to send. You can either pass a file_id as String to resend a file that
is already on the Telegram servers, or upload a new file using multipart/form-data.
filename: File name that shows in telegram message (it is usefull when you send file
generated by temp module, for example). [Optional]
filename (Optional[str]): File name that shows in telegram message (it is usefull when
you send file generated by temp module, for example).
caption (Optional[str]): Document caption (may also be used when resending documents by
file_id), 0-200 characters.
disable_notification (Optional[bool]): Sends the message silently. iOS users will not
@@ -415,7 +416,7 @@ class Bot(TelegramObject):
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -461,7 +462,7 @@ class Bot(TelegramObject):
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -508,7 +509,7 @@ class Bot(TelegramObject):
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
@@ -554,14 +555,14 @@ class Bot(TelegramObject):
that is already on the Telegram servers, or upload a new audio file using
multipart/form-data.
duration (Optional[int]): Duration of sent audio in seconds.
caption: Voice caption [Optional]
caption (Optional[str]): Voice caption
disable_notification (Optional[bool]): Sends the message silently. iOS users will not
receive a notification, Android users will receive a notification with no sound.
reply_to_message_id (Optional[int]): If the message is a reply, ID of the original
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -607,7 +608,7 @@ class Bot(TelegramObject):
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -656,7 +657,7 @@ class Bot(TelegramObject):
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -710,7 +711,7 @@ class Bot(TelegramObject):
message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -749,7 +750,7 @@ class Bot(TelegramObject):
ID of the original message.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options.
A JSON-serialized object for an inline keyboard, custom reply keyboard,
instructions to hide reply keyboard or to force a reply from the user.
instructions to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as
the definitive timeout (in seconds) for urlopen() operations.
@@ -777,6 +778,7 @@ class Bot(TelegramObject):
chat_id: Unique identifier for the message recipient - Chat id.
action: Type of action to broadcast. Choose one, depending on what the user is about to
receive:
- ChatAction.TYPING for text messages,
- ChatAction.UPLOAD_PHOTO for photos,
- ChatAction.UPLOAD_VIDEO for videos,
@@ -862,8 +864,8 @@ class Bot(TelegramObject):
Args:
user_id: Unique identifier of the target user.
offset (Optional[int]: Sequential number of the first photo to be returned. By default,
all photos are returned.
offset (Optional[int]): Sequential number of the first photo to be returned. By
default, all photos are returned.
limit (Optional[int]): Limits the number of photos to be retrieved. Values between
1-100 are accepted. Defaults to 100.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
@@ -960,7 +962,7 @@ class Bot(TelegramObject):
Args:
chat_id: Unique identifier for the target group or username of the target supergroup
(in the format @supergroupusername).
user_id: Unique identifier of the target user.
user_id: Unique identifier of the target user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -986,6 +988,7 @@ class Bot(TelegramObject):
text=None,
show_alert=False,
url=None,
cache_time=None,
timeout=None,
**kwargs):
"""Use this method to send answers to callback queries sent from inline keyboards. The
@@ -998,9 +1001,12 @@ class Bot(TelegramObject):
to the user.
show_alert (Optional[bool]): If `True`, an alert will be shown by the client instead of
a notification at the top of the chat screen. Defaults to `False`.
url (Optional[str]): URL that will be opened by the user's client.
cache_time (Optional[int]): The maximum amount of time in seconds that the result of
the callback query may be cached client-side. Telegram apps will support caching
starting in version 3.14. Defaults to 0.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
url (Optional[str]): URL that will be opened by the user's client.
**kwargs (dict): Arbitrary keyword arguments.
Returns:
@@ -1020,6 +1026,8 @@ class Bot(TelegramObject):
data['show_alert'] = show_alert
if url:
data['url'] = url
if cache_time is not None:
data['cache_time'] = cache_time
result = self._request.post(url_, data, timeout=timeout)
@@ -1053,7 +1061,7 @@ class Bot(TelegramObject):
reply_markup: A JSON-serialized object for an inline keyboard.
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to hide reply keyboard or to force a reply from the user.
to remove reply keyboard or to force a reply from the user.
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
**kwargs (dict): Arbitrary keyword arguments.
@@ -1433,9 +1441,32 @@ class Bot(TelegramObject):
message_id=None,
inline_message_id=None,
edit_message=None,
force=None,
disable_edit_message=None,
**kwargs):
"""Use this method to set the score of the specified user in a game.
Args:
user_id (int): User identifier.
score (int): New score, must be non-negative.
chat_id (Optional[int|str]): Required if `inline_message_id` is not specified. Unique
identifier for the target chat (or username of the target channel in the format
`@channelusername`)
message_id (Optional[int]): Required if inline_message_id is not specified. Identifier
of the sent message.
inline_message_id (Optional[str]): Required if chat_id and message_id are not
specified. Identifier of the inline message.
force (Optional[bool]): Pass True, if the high score is allowed to decrease. This can
be useful when fixing mistakes or banning cheaters.
disable_edit_message (Optional[bool]): Pass True, if the game message should not be
automatically edited to include the current scoreboard.
edit_message (Optional[bool]): Deprecated. Has the opposite logic for
`disable_edit_message`.
Keyword Args:
timeout (Optional[float]): If this value is specified, use it as the definitive timeout
(in seconds) for urlopen() operations.
Returns:
:class:`telegram.Message` or True: The edited message, or if the
message wasn't sent by the bot, True.
@@ -1451,8 +1482,16 @@ class Bot(TelegramObject):
data['message_id'] = message_id
if inline_message_id:
data['inline_message_id'] = inline_message_id
if edit_message:
data['edit_message'] = edit_message
if force is not None:
data['force'] = force
if disable_edit_message is not None:
data['disable_edit_message'] = disable_edit_message
if edit_message is not None:
warnings.warn('edit_message is deprecated, use disable_edit_message instead')
if disable_edit_message is None:
data['edit_message'] = edit_message
else:
warnings.warn('edit_message is ignored when disable_edit_message is used')
result = self._request.post(url, data, timeout=kwargs.get('timeout'))
if result is True:
+1 -1
View File
@@ -39,7 +39,7 @@ class CallbackQueryHandler(Handler):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
+1 -1
View File
@@ -35,7 +35,7 @@ class ChosenInlineResultHandler(Handler):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
+1 -1
View File
@@ -44,7 +44,7 @@ class CommandHandler(Handler):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
+2 -2
View File
@@ -309,7 +309,7 @@ class Dispatcher(object):
which handlers were added to the group defines the priority.
Args:
handler (Handler): A Handler instance
handler (telegram.ext.Handler): A Handler instance
group (Optional[int]): The group identifier. Default is 0
"""
@@ -330,7 +330,7 @@ class Dispatcher(object):
Remove a handler from the specified group
Args:
handler (Handler): A Handler instance
handler (telegram.ext.Handler): A Handler instance
group (optional[object]): The group identifier. Default is 0
"""
if handler in self.handlers[group]:
+7
View File
@@ -107,6 +107,13 @@ class Filters(object):
def filter(self, message):
return bool(message.text and message.text.startswith('/'))
class _Reply(BaseFilter):
def filter(self, message):
return bool(message.reply_to_message)
reply = _Reply()
command = _Command()
class _Audio(BaseFilter):
+3 -3
View File
@@ -35,7 +35,7 @@ class Handler(object):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
@@ -85,7 +85,7 @@ class Handler(object):
Args:
update (object): The update to be handled
dispatcher (Dispatcher): The dispatcher to collect optional args
dispatcher (telegram.ext.Dispatcher): The dispatcher to collect optional args
"""
raise NotImplementedError
@@ -96,7 +96,7 @@ class Handler(object):
handlers
Args:
dispatcher (Dispatcher):
dispatcher (telegram.ext.Dispatcher):
"""
optional_args = dict()
+1 -1
View File
@@ -38,7 +38,7 @@ class InlineQueryHandler(Handler):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
+44 -13
View File
@@ -21,19 +21,26 @@
import logging
import time
import warnings
import datetime
from numbers import Number
from threading import Thread, Lock, Event
from queue import PriorityQueue, Empty
class Days(object):
MON, TUE, WED, THU, FRI, SAT, SUN = range(7)
EVERY_DAY = tuple(range(7))
class JobQueue(object):
"""This class allows you to periodically perform tasks with the bot.
Attributes:
queue (PriorityQueue):
bot (Bot):
bot (telegram.Bot):
Args:
bot (Bot): The bot instance that should be passed to the jobs
bot (telegram.Bot): The bot instance that should be passed to the jobs
Deprecated: 5.2
prevent_autostart (Optional[bool]): Thread does not start during initialisation.
@@ -60,15 +67,26 @@ class JobQueue(object):
"""Queue a new job.
Args:
job (Job): The ``Job`` instance representing the new job
next_t (Optional[float]): Time in seconds in which the job should be executed first.
Defaults to ``job.interval``
job (telegram.ext.Job): The ``Job`` instance representing the new job
next_t (Optional[int, float, datetime.timedelta]): Time in which the job
should be executed first. Defaults to ``job.interval``. ``int`` and ``float``
will be interpreted as seconds.
"""
job.job_queue = self
if next_t is None:
next_t = job.interval
interval = job.interval
if isinstance(interval, Number):
next_t = interval
elif isinstance(interval, datetime.timedelta):
next_t = interval.total_seconds()
else:
raise ValueError("The interval argument should be of type datetime.timedelta,"
" int or float")
elif isinstance(next_t, datetime.timedelta):
next_t = next_t.total_second()
now = time.time()
next_t += now
@@ -123,11 +141,11 @@ class JobQueue(object):
continue
if job.enabled:
self.logger.debug('Running job %s', job.name)
try:
job.run(self.bot)
current_week_day = datetime.datetime.now().weekday()
if any(day == current_week_day for day in job.days):
self.logger.debug('Running job %s', job.name)
job.run(self.bot)
except:
self.logger.exception('An uncaught error was raised while executing job %s',
job.name)
@@ -200,6 +218,7 @@ class Job(object):
Attributes:
callback (function):
interval (float):
days: (tuple)
repeat (bool):
name (str):
enabled (bool): Boolean property that decides if this job is currently active
@@ -208,22 +227,34 @@ class Job(object):
callback (function): The callback function that should be executed by the Job. It should
take two parameters ``bot`` and ``job``, where ``job`` is the ``Job`` instance. It
can be used to terminate the job or modify its interval.
interval (float): The interval in which this job should execute its callback function in
seconds.
interval ([int, float, datetime.timedelta]): The interval in which the job will execute its
callback function. ``int`` and ``float`` will be interpreted as seconds.
repeat (Optional[bool]): If this job should be periodically execute its callback function
(``True``) or only once (``False``). Defaults to ``True``
context (Optional[object]): Additional data needed for the callback function. Can be
accessed through ``job.context`` in the callback. Defaults to ``None``
days (Tuple): Defines on which days the job should be ran.
"""
job_queue = None
def __init__(self, callback, interval, repeat=True, context=None):
def __init__(self, callback, interval, repeat=True, context=None, days=Days.EVERY_DAY):
self.callback = callback
self.interval = interval
self.repeat = repeat
self.context = context
if not isinstance(days, tuple):
raise ValueError("The 'days argument should be of type 'tuple'")
if not all(isinstance(day, int) for day in days):
raise ValueError("The elements of the 'days' argument should be of type 'int'")
if not all(day >= 0 and day <= 6 for day in days):
raise ValueError("The elements of the 'days' argument should be from 0 up to and "
"including 6")
self.days = days
self.name = callback.__name__
self._remove = Event()
self._enabled = Event()
+26 -5
View File
@@ -32,8 +32,8 @@ class MessageHandler(Handler):
Args:
filters (telegram.ext.BaseFilter): A filter inheriting from
:class:`telegram.filters.BaseFilter`. Standard filters can be found in
:class:`telegram.filters.Filters`. Filters can be combined using bitwise
:class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in
:class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise
operators (& for and, | for or).
callback (function): A function that takes ``bot, update`` as
positional arguments. It will be called when the ``check_update``
@@ -51,6 +51,11 @@ class MessageHandler(Handler):
``chat_data`` will be passed to the callback function. It will be a ``dict`` you
can use to keep any data related to the chat that the update was sent in.
For each update in the same chat, it will be the same ``dict``. Default is ``False``.
message_updates (Optional[bool]): Should "normal" message updates be handled? Default is
``True``.
channel_posts_updates (Optional[bool]): Should channel posts updates be handled? Default is
``True``.
"""
def __init__(self,
@@ -60,7 +65,12 @@ class MessageHandler(Handler):
pass_update_queue=False,
pass_job_queue=False,
pass_user_data=False,
pass_chat_data=False):
pass_chat_data=False,
message_updates=True,
channel_posts_updates=True):
if not message_updates and not channel_posts_updates:
raise ValueError('Both message_updates & channel_post_updates are False')
super(MessageHandler, self).__init__(
callback,
pass_update_queue=pass_update_queue,
@@ -69,6 +79,8 @@ class MessageHandler(Handler):
pass_chat_data=pass_chat_data)
self.filters = filters
self.allow_edited = allow_edited
self.message_updates = message_updates
self.channel_posts_updates = channel_posts_updates
# We put this up here instead of with the rest of checking code
# in check_update since we don't wanna spam a ton
@@ -77,15 +89,24 @@ class MessageHandler(Handler):
'deprecated, please use bitwise operators (& and |) '
'instead. More info: https://git.io/vPTbc.')
def _is_allowed_message(self, update):
return (self.message_updates
and (update.message or (update.edited_message and self.allow_edited)))
def _is_allowed_channel_post(self, update):
return (self.channel_posts_updates
and (update.channel_post or (update.edited_channel_post and self.allow_edited)))
def check_update(self, update):
if (isinstance(update, Update)
and (update.message or update.edited_message and self.allow_edited)):
and (self._is_allowed_message(update) or self._is_allowed_channel_post(update))):
if not self.filters:
res = True
else:
message = update.message or update.edited_message
message = (update.message or update.edited_message or update.channel_post
or update.edited_channel_post)
if isinstance(self.filters, list):
res = any(func(message) for func in self.filters)
else:
+1 -1
View File
@@ -48,7 +48,7 @@ class RegexHandler(Handler):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
+1 -1
View File
@@ -40,7 +40,7 @@ class StringCommandHandler(Handler):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
+1 -1
View File
@@ -47,7 +47,7 @@ class StringRegexHandler(Handler):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
+1 -1
View File
@@ -37,7 +37,7 @@ class TypeHandler(Handler):
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
+2 -2
View File
@@ -101,8 +101,8 @@ class Game(TelegramObject):
(That is, you can't just slice ``Message.text`` with the offset and length.)
Args:
entity (MessageEntity): The entity to extract the text from. It must be an entity that
belongs to this message.
entity (telegram.MessageEntity): The entity to extract the text from. It must be an
entity that belongs to this message.
Returns:
str: The text of the given entity
+1 -1
View File
@@ -44,7 +44,7 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
caption (Optional[str]):
reply_markup (Optional[:class:`telegram.InlineKeyboardMarkup`]):
input_message_content (Optional[:class:`telegram.InputMessageContent`]):
**kwargs (dict): Arbitrary keyword arguments.
**kwargs (dict): Arbitrary keyword arguments.
"""
+72 -25
View File
@@ -39,6 +39,7 @@ class Message(TelegramObject):
date (:class:`datetime.datetime`):
forward_from (:class:`telegram.User`):
forward_from_chat (:class:`telegram.Chat`):
forward_from_message_id (int):
forward_date (:class:`datetime.datetime`):
reply_to_message (:class:`telegram.Message`):
edit_date (:class:`datetime.datetime`):
@@ -76,11 +77,9 @@ class Message(TelegramObject):
from_user (:class:`telegram.User`):
date (:class:`datetime.datetime`):
chat (:class:`telegram.Chat`):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
forward_from (Optional[:class:`telegram.User`]):
forward_from_chat (:class:`telegram.Chat`):
forward_from_chat (Optional[:class:`telegram.Chat`]):
forward_from_message_id (Optional[int]):
forward_date (Optional[:class:`datetime.datetime`]):
reply_to_message (Optional[:class:`telegram.Message`]):
edit_date (Optional[:class:`datetime.datetime`]):
@@ -141,6 +140,7 @@ class Message(TelegramObject):
migrate_from_chat_id=0,
channel_chat_created=False,
pinned_message=None,
forward_from_message_id=None,
bot=None,
**kwargs):
# Required
@@ -178,6 +178,7 @@ class Message(TelegramObject):
self.migrate_from_chat_id = int(migrate_from_chat_id)
self.channel_chat_created = bool(channel_chat_created)
self.pinned_message = pinned_message
self.forward_from_message_id = forward_from_message_id
self.bot = bot
@@ -326,6 +327,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the photo is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -339,6 +344,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the audio is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -352,6 +361,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the document is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -365,6 +378,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the sticker is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -378,6 +395,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the video is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -391,6 +412,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the voice is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -404,6 +429,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the location is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -417,6 +446,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the venue is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -430,6 +463,10 @@ class Message(TelegramObject):
quote (Optional[bool]): If set to ``True``, the contact is sent as an actual reply to
this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter
will be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
"""
self._quote(kwargs)
@@ -438,10 +475,13 @@ class Message(TelegramObject):
def forward(self, chat_id, disable_notification=False):
"""Shortcut for
bot.forwardMessage(chat_id=chat_id,
from_chat_id=update.message.chat_id,
disable_notification=disable_notification,
message_id=update.message.message_id)
>>> bot.forwardMessage(chat_id=chat_id,
... from_chat_id=update.message.chat_id,
... disable_notification=disable_notification,
... message_id=update.message.message_id)
Returns:
:class:`telegram.Message`: On success, instance representing the message forwarded.
"""
return self.bot.forwardMessage(
@@ -452,44 +492,51 @@ class Message(TelegramObject):
def edit_text(self, *args, **kwargs):
"""
Shortcut for ``bot.editMessageText(chat_id=message.chat_id,
message_id=message.message_id,
*args, **kwargs)``
Shortcut for
>>> bot.editMessageText(chat_id=message.chat_id,
... message_id=message.message_id,
... *args, **kwargs)
Note:
You can only edit messages that the bot sent itself,
therefore this method can only be used on the
return value of the bot.send_* family of methods.
return value of the ``bot.send_*`` family of methods.
"""
return self.bot.edit_message_text(
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
def edit_caption(self, *args, **kwargs):
"""
Shortcut for ``bot.editMessageCaption(chat_id=message.chat_id,
message_id=message.message_id,
*args, **kwargs)``
Shortcut for
>>> bot.editMessageCaption(chat_id=message.chat_id,
... message_id=message.message_id,
... *args, **kwargs)
Note:
You can only edit messages that the bot sent itself,
therefore this method can only be used on the
return value of the bot.send_* family of methods.
return value of the ``bot.send_*`` family of methods.
"""
return self.bot.edit_message_caption(
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
def edit_reply_markup(self, *args, **kwargs):
"""
Shortcut for ``bot.editReplyMarkup(chat_id=message.chat_id,
message_id=message.message_id,
*args, **kwargs)``
Shortcut for
>>> bot.editReplyMarkup(chat_id=message.chat_id,
... message_id=message.message_id,
... *args, **kwargs)
Note:
You can only edit messages that the bot sent itself,
therefore this method can only be used on the
return value of the bot.send_* family of methods.
return value of the ``bot.send_*`` family of methods.
"""
return self.bot.edit_message_caption(
return self.bot.edit_message_reply_markup(
chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs)
def parse_entity(self, entity):
@@ -502,8 +549,8 @@ class Message(TelegramObject):
(That is, you can't just slice ``Message.text`` with the offset and length.)
Args:
entity (MessageEntity): The entity to extract the text from. It must be an entity that
belongs to this message.
entity (telegram.MessageEntity): The entity to extract the text from. It must be an
entity that belongs to this message.
Returns:
str: The text of the given entity
@@ -529,8 +576,8 @@ class Message(TelegramObject):
See ``get_entity_text`` for more info.
Args:
types (Optional[list]): List of ``MessageEntity`` types as strings. If the ``type``
attribute of an entity is contained in this list, it will be returned.
types (Optional[list]): List of ``telegram.MessageEntity`` types as strings. If the
``type`` attribute of an entity is contained in this list, it will be returned.
Defaults to a list of all types. All types can be found as constants in
:class:`telegram.MessageEntity`.
@@ -16,30 +16,31 @@
#
# 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 an object that represents a Telegram
ReplyKeyboardHide."""
"""This module contains an object that represents a Telegram ReplyKeyboardRemove."""
from telegram import ReplyMarkup
from telegram.utils.deprecate import warn_deprecate_obj
class ReplyKeyboardHide(ReplyMarkup):
"""This object represents a Telegram ReplyKeyboardHide.
class ReplyKeyboardRemove(ReplyMarkup):
"""This object represents a Telegram ReplyKeyboardRemove.
Attributes:
hide_keyboard (bool):
remove_keyboard (bool): Always True.
selective (bool):
Args:
hide_keyboard (bool):
selective (Optional[bool]): Use this parameter if you want to remove the keyboard for
specific users only. Targets:
1) users that are @mentioned in the text of the Message object;
2) if the bot's message is a reply (has reply_to_message_id), sender of the
original message.
**kwargs: Arbitrary keyword arguments.
Keyword Args:
selective (Optional[bool]):
"""
def __init__(self, hide_keyboard=True, selective=False, **kwargs):
def __init__(self, selective=False, **kwargs):
# Required
self.hide_keyboard = bool(hide_keyboard)
self.remove_keyboard = True
# Optionals
self.selective = bool(selective)
@@ -51,9 +52,19 @@ class ReplyKeyboardHide(ReplyMarkup):
bot(telegram.Bot):
Returns:
telegram.ReplyKeyboardHide:
telegram.ReplyKeyboardRemove
"""
if not data:
return None
return ReplyKeyboardHide(**data)
return ReplyKeyboardRemove(**data)
class ReplyKeyboardHide(object):
def __new__(cls, hide_keyboard=True, selective=False, **kwargs):
warn_deprecate_obj(ReplyKeyboardHide.__name__, ReplyKeyboardRemove.__name__)
obj = ReplyKeyboardRemove.__new__(ReplyKeyboardRemove, selective)
obj.__init__(selective)
return obj
+23 -9
View File
@@ -25,23 +25,31 @@ class Update(TelegramObject):
"""This object represents a Telegram Update.
Attributes:
update_id (int):
message (:class:`telegram.Message`):
edited_message (:class:`telegram.Message`):
inline_query (:class:`telegram.InlineQuery`):
chosen_inline_result (:class:`telegram.ChosenInlineResult`):
callback_query (:class:`telegram.CallbackQuery`):
update_id (int): The update's unique identifier.
message (:class:`telegram.Message`): New incoming message of any kind - text, photo,
sticker, etc.
edited_message (:class:`telegram.Message`): New version of a message that is known to the
bot and was edited
inline_query (:class:`telegram.InlineQuery`): New incoming inline query.
chosen_inline_result (:class:`telegram.ChosenInlineResult`): The result of an inline query
that was chosen by a user and sent to their chat partner.
callback_query (:class:`telegram.CallbackQuery`): New incoming callback query.
channel_post (Optional[:class:`telegram.Message`]): New incoming channel post of any kind -
text, photo, sticker, etc.
edited_channel_post (Optional[:class:`telegram.Message`]): New version of a channel post
that is known to the bot and was edited.
Args:
update_id (int):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
message (Optional[:class:`telegram.Message`]):
edited_message (Optional[:class:`telegram.Message`]):
inline_query (Optional[:class:`telegram.InlineQuery`]):
chosen_inline_result (Optional[:class:`telegram.ChosenInlineResult`])
callback_query (Optional[:class:`telegram.CallbackQuery`]):
channel_post (Optional[:class:`telegram.Message`]):
edited_channel_post (Optional[:class:`telegram.Message`]):
**kwargs: Arbitrary keyword arguments.
"""
def __init__(self,
@@ -51,6 +59,8 @@ class Update(TelegramObject):
inline_query=None,
chosen_inline_result=None,
callback_query=None,
channel_post=None,
edited_channel_post=None,
**kwargs):
# Required
self.update_id = int(update_id)
@@ -60,6 +70,8 @@ class Update(TelegramObject):
self.inline_query = inline_query
self.chosen_inline_result = chosen_inline_result
self.callback_query = callback_query
self.channel_post = channel_post
self.edited_channel_post = edited_channel_post
@staticmethod
def de_json(data, bot):
@@ -80,5 +92,7 @@ class Update(TelegramObject):
data['chosen_inline_result'] = ChosenInlineResult.de_json(
data.get('chosen_inline_result'), bot)
data['callback_query'] = CallbackQuery.de_json(data.get('callback_query'), bot)
data['channel_post'] = Message.de_json(data.get('channel_post'), bot)
data['edited_channel_post'] = Message.de_json(data.get('edited_channel_post'), bot)
return Update(**data)
+5 -1
View File
@@ -21,11 +21,15 @@
import warnings
def warn_deprecate_obj(old, new):
warnings.warn('{0} is being deprecated, please use {1} from now on'.format(old, new))
def deprecate(func, old, new):
"""Warn users invoking old to switch to the new function."""
def f(*args, **kwargs):
warnings.warn("{0} is being deprecated, please use {1} from now on".format(old, new))
warn_deprecate_obj(old, new)
return func(*args, **kwargs)
return f
+4 -2
View File
@@ -31,8 +31,8 @@ import urllib3
from urllib3.connection import HTTPConnection
from telegram import (InputFile, TelegramError)
from telegram.error import Unauthorized, NetworkError, TimedOut, BadRequest, ChatMigrated, \
RetryAfter
from telegram.error import Unauthorized, InvalidToken, NetworkError, TimedOut, BadRequest, \
ChatMigrated, RetryAfter
logging.getLogger('urllib3').setLevel(logging.WARNING)
@@ -150,6 +150,8 @@ class Request(object):
raise Unauthorized()
elif resp.status == 400:
raise BadRequest(repr(message))
elif resp.status == 404:
raise InvalidToken()
elif resp.status == 502:
raise NetworkError('Bad Gateway')
else:
+1 -1
View File
@@ -17,4 +17,4 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
__version__ = '5.2.0'
__version__ = '5.3.0'
+84 -6
View File
@@ -34,6 +34,9 @@ import telegram
from telegram.error import BadRequest
from tests.base import BaseTest, timeout
BASE_TIME = time.time()
HIGHSCORE_DELTA = 1450000000
class BotTest(BaseTest, unittest.TestCase):
"""This object represents Tests for Telegram Bot."""
@@ -227,7 +230,7 @@ class BotTest(BaseTest, unittest.TestCase):
bot.getMe()
def testInvalidSrvResp(self):
with self.assertRaisesRegexp(telegram.TelegramError, 'Invalid server response'):
with self.assertRaisesRegexp(telegram.error.InvalidToken, 'Invalid token'):
# bypass the valid token check
newbot_cls = type(
'NoTokenValidateBot', (telegram.Bot,), dict(_validate_token=lambda x, y: None))
@@ -286,6 +289,16 @@ class BotTest(BaseTest, unittest.TestCase):
self.assertEqual(chat_member.status, "administrator")
self._testUserEqualsBot(bot)
@flaky(3, 1)
@timeout(10)
def test_forward_channel_messgae(self):
text = 'test forward message'
msg = self._bot.sendMessage(self._channel_id, text)
self.assertEqual(text, msg.text)
fwdmsg = msg.forward(self._chat_id)
self.assertEqual(text, fwdmsg.text)
self.assertEqual(fwdmsg.forward_from_message_id, msg.message_id)
@flaky(3, 1)
@timeout(10)
def test_get_webhook_info(self):
@@ -297,17 +310,16 @@ class BotTest(BaseTest, unittest.TestCase):
@flaky(3, 1)
@timeout(10)
def test_set_game_score(self):
# We need a game to set the score for
def test_set_game_score1(self):
# NOTE: numbering of methods assures proper order between test_set_game_scoreX methods
game_short_name = 'python_telegram_bot_test_game'
game = self._bot.sendGame(game_short_name=game_short_name, chat_id=self._chat_id)
message = self._bot.set_game_score(
user_id=self._chat_id,
score=int(time.time() - 1450000000),
score=int(BASE_TIME) - HIGHSCORE_DELTA,
chat_id=game.chat_id,
message_id=game.message_id,
edit_message=True)
message_id=game.message_id)
self.assertTrue(self.is_json(game.to_json()))
self.assertEqual(message.game.description, game.game.description)
@@ -315,6 +327,72 @@ class BotTest(BaseTest, unittest.TestCase):
self.assertEqual(message.game.photo[0].file_size, game.game.photo[0].file_size)
self.assertNotEqual(message.game.text, game.game.text)
@flaky(3, 1)
@timeout(10)
def test_set_game_score2(self):
# NOTE: numbering of methods assures proper order between test_set_game_scoreX methods
game_short_name = 'python_telegram_bot_test_game'
game = self._bot.sendGame(game_short_name=game_short_name, chat_id=self._chat_id)
score = int(BASE_TIME) - HIGHSCORE_DELTA + 1
message = self._bot.set_game_score(
user_id=self._chat_id,
score=score,
chat_id=game.chat_id,
message_id=game.message_id,
disable_edit_message=True)
self.assertTrue(self.is_json(game.to_json()))
self.assertEqual(message.game.description, game.game.description)
self.assertEqual(message.game.animation.file_id, game.game.animation.file_id)
self.assertEqual(message.game.photo[0].file_size, game.game.photo[0].file_size)
self.assertEqual(message.game.text, game.game.text)
@flaky(3, 1)
@timeout(10)
def test_set_game_score3(self):
# NOTE: numbering of methods assures proper order between test_set_game_scoreX methods
game_short_name = 'python_telegram_bot_test_game'
game = self._bot.sendGame(game_short_name=game_short_name, chat_id=self._chat_id)
score = int(BASE_TIME) - HIGHSCORE_DELTA - 1
with self.assertRaises(BadRequest) as cm:
self._bot.set_game_score(
user_id=self._chat_id,
score=score,
chat_id=game.chat_id,
message_id=game.message_id)
self.assertTrue('BOT_SCORE_NOT_MODIFIED' in cm.exception.message)
@flaky(3, 1)
@timeout(10)
def test_set_game_score4(self):
# NOTE: numbering of methods assures proper order between test_set_game_scoreX methods
game_short_name = 'python_telegram_bot_test_game'
game = self._bot.sendGame(game_short_name=game_short_name, chat_id=self._chat_id)
score = int(BASE_TIME) - HIGHSCORE_DELTA - 2
message = self._bot.set_game_score(
user_id=self._chat_id,
score=score,
chat_id=game.chat_id,
message_id=game.message_id,
force=True)
self.assertTrue(self.is_json(game.to_json()))
self.assertEqual(message.game.description, game.game.description)
self.assertEqual(message.game.animation.file_id, game.game.animation.file_id)
self.assertEqual(message.game.photo[0].file_size, game.game.photo[0].file_size)
# For some reason the returned message does not contain the updated score. need to fetch
# the game again...
game2 = self._bot.sendGame(game_short_name=game_short_name, chat_id=self._chat_id)
self.assertIn(str(score), game2.game.text)
@flaky(3, 1)
@timeout(10)
def test_set_game_score_too_low_score(self):
+11 -5
View File
@@ -47,20 +47,26 @@ class ConstantsTest(BaseTest, unittest.TestCase):
@flaky(3, 1)
@timeout(10)
def testMaxCaptionLength(self):
self._bot.sendPhoto(
good_caption = 'a' * telegram.constants.MAX_CAPTION_LENGTH
good_msg = self._bot.sendPhoto(
photo=open('tests/data/telegram.png', 'rb'),
caption='a' * telegram.constants.MAX_CAPTION_LENGTH,
caption=good_caption,
chat_id=self._chat_id)
self.assertEqual(good_msg.caption, good_caption)
bad_caption = good_caption + 'Z'
try:
self._bot.sendPhoto(
bad_msg = self._bot.sendPhoto(
photo=open('tests/data/telegram.png', 'rb'),
caption='a' * (telegram.constants.MAX_CAPTION_LENGTH + 1),
chat_id=self._chat_id)
except BadRequest as e:
# This used to be the way long caption was handled before Oct? Nov? 2016
err = str(e)
self.assertTrue("TOO_LONG" in err) # BadRequest: 'MEDIA_CAPTION_TOO_LONG'
self.assertTrue("TOO_LONG" in err) # BadRequest: 'MEDIA_CAPTION_TOO_LONG'
else:
self.assertNotEqual(bad_msg.caption, bad_caption)
self.assertEqual(len(bad_msg.caption), telegram.constants.MAX_CAPTION_LENGTH)
if __name__ == '__main__':
+7
View File
@@ -51,6 +51,13 @@ class FiltersTest(BaseTest, unittest.TestCase):
self.message.text = '/test'
self.assertTrue(Filters.command(self.message))
def test_filters_reply(self):
another_message = Message(1, User(1, "TestOther"), datetime.now(), Chat(0, 'private'))
self.message.text = 'test'
self.assertFalse(Filters.reply(self.message))
self.message.reply_to_message = another_message
self.assertTrue(Filters.reply(self.message))
def test_filters_audio(self):
self.message.audio = 'test'
self.assertTrue(Filters.audio(self.message))
+29
View File
@@ -23,6 +23,9 @@ This module contains an object that represents Tests for JobQueue
import logging
import sys
import unittest
import datetime
import time
from math import ceil
from time import sleep
from tests.test_updater import MockBot
@@ -53,11 +56,15 @@ class JobQueueTest(BaseTest, unittest.TestCase):
self.jq = JobQueue(MockBot('jobqueue_test'))
self.jq.start()
self.result = 0
self.job_time = 0
def tearDown(self):
if self.jq is not None:
self.jq.stop()
def getSeconds(self):
return int(ceil(time.time()))
def job1(self, bot, job):
self.result += 1
@@ -71,6 +78,9 @@ class JobQueueTest(BaseTest, unittest.TestCase):
def job4(self, bot, job):
self.result += job.context
def job5(self, bot, job):
self.job_time = self.getSeconds()
def test_basic(self):
self.jq.put(Job(self.job1, 0.1))
sleep(1.5)
@@ -169,6 +179,25 @@ class JobQueueTest(BaseTest, unittest.TestCase):
finally:
u.stop()
def test_time_unit_int(self):
# Testing seconds in int
seconds_interval = 5
expected_time = self.getSeconds() + seconds_interval
self.jq.put(Job(self.job5, seconds_interval, repeat=False))
sleep(6)
self.assertEqual(self.job_time, expected_time)
def test_time_unit_dt_time(self):
# Testing seconds, minutes and hours as datetime.timedelta object
# This is sufficient to test that it actually works.
interval = datetime.timedelta(seconds=5)
expected_time = self.getSeconds() + interval.total_seconds()
self.jq.put(Job(self.job5, interval, repeat=False))
sleep(6)
self.assertEqual(self.job_time, expected_time)
if __name__ == '__main__':
unittest.main()
@@ -17,7 +17,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents Tests for Telegram ReplyKeyboardHide"""
"""This module contains an object that represents Tests for Telegram ReplyKeyboardRemove"""
import sys
import unittest
@@ -28,48 +28,48 @@ import telegram
from tests.base import BaseTest
class ReplyKeyboardHideTest(BaseTest, unittest.TestCase):
"""This object represents Tests for Telegram ReplyKeyboardHide."""
class ReplyKeyboardRemoveTest(BaseTest, unittest.TestCase):
"""This object represents Tests for Telegram ReplyKeyboardRemove."""
def setUp(self):
self.hide_keyboard = True
self.remove_keyboard = True
self.selective = True
self.json_dict = {
'hide_keyboard': self.hide_keyboard,
'remove_keyboard': self.remove_keyboard,
'selective': self.selective,
}
def test_send_message_with_reply_keyboard_hide(self):
def test_send_message_with_reply_keyboard_remove(self):
message = self._bot.sendMessage(
self._chat_id,
'Моё судно на воздушной подушке полно угрей',
reply_markup=telegram.ReplyKeyboardHide.de_json(self.json_dict, self._bot))
reply_markup=telegram.ReplyKeyboardRemove.de_json(self.json_dict, self._bot))
self.assertTrue(self.is_json(message.to_json()))
self.assertEqual(message.text, u'Моё судно на воздушной подушке полно угрей')
def test_reply_keyboard_hide_de_json(self):
reply_keyboard_hide = telegram.ReplyKeyboardHide.de_json(self.json_dict, self._bot)
def test_reply_keyboard_remove_de_json(self):
reply_keyboard_remove = telegram.ReplyKeyboardRemove.de_json(self.json_dict, self._bot)
self.assertEqual(reply_keyboard_hide.hide_keyboard, self.hide_keyboard)
self.assertEqual(reply_keyboard_hide.selective, self.selective)
self.assertEqual(reply_keyboard_remove.remove_keyboard, self.remove_keyboard)
self.assertEqual(reply_keyboard_remove.selective, self.selective)
def test_reply_keyboard_hide_de_json_empty(self):
reply_keyboard_hide = telegram.ReplyKeyboardHide.de_json(None, self._bot)
def test_reply_keyboard_remove_de_json_empty(self):
reply_keyboard_remove = telegram.ReplyKeyboardRemove.de_json(None, self._bot)
self.assertFalse(reply_keyboard_hide)
self.assertFalse(reply_keyboard_remove)
def test_reply_keyboard_hide_to_json(self):
reply_keyboard_hide = telegram.ReplyKeyboardHide.de_json(self.json_dict, self._bot)
def test_reply_keyboard_remove_to_json(self):
reply_keyboard_remove = telegram.ReplyKeyboardRemove.de_json(self.json_dict, self._bot)
self.assertTrue(self.is_json(reply_keyboard_hide.to_json()))
self.assertTrue(self.is_json(reply_keyboard_remove.to_json()))
def test_reply_keyboard_hide_to_dict(self):
reply_keyboard_hide = telegram.ReplyKeyboardHide.de_json(self.json_dict, self._bot)
def test_reply_keyboard_remove_to_dict(self):
reply_keyboard_remove = telegram.ReplyKeyboardRemove.de_json(self.json_dict, self._bot)
self.assertEqual(reply_keyboard_hide['hide_keyboard'], self.hide_keyboard)
self.assertEqual(reply_keyboard_hide['selective'], self.selective)
self.assertEqual(reply_keyboard_remove['remove_keyboard'], self.remove_keyboard)
self.assertEqual(reply_keyboard_remove['selective'], self.selective)
if __name__ == '__main__':