mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-23 01:35:29 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d4e0500bf | |||
| 042d4bb2a4 | |||
| 1e22d570a3 | |||
| 2719c54899 | |||
| a5c8e98ee7 | |||
| 40113bb3ad | |||
| e8fac19de3 | |||
| 820ae3b7d6 | |||
| 4b3315db6f | |||
| 3ed05991ad | |||
| 38637ecf62 | |||
| bb5357a815 |
@@ -1,7 +1,6 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
|
||||
@@ -55,6 +55,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `Rahiel Kasim <https://github.com/rahiel>`_
|
||||
- `Sascha <https://github.com/saschalalala>`_
|
||||
- `Shelomentsev D <https://github.com/shelomentsevd>`_
|
||||
- `Simon Schürrle <https://github.com/SitiSchu>`_
|
||||
- `sooyhwang <https://github.com/sooyhwang>`_
|
||||
- `thodnev <https://github.com/thodnev>`_
|
||||
- `Valentijn <https://github.com/Faalentijn>`_
|
||||
|
||||
+26
@@ -1,6 +1,32 @@
|
||||
=======
|
||||
Changes
|
||||
=======
|
||||
**2017-12-08**
|
||||
*Released 9.0.0*
|
||||
|
||||
Breaking changes (possibly)
|
||||
|
||||
- Drop support for python 3.3 (PR `#930`_)
|
||||
|
||||
|
||||
New Features
|
||||
|
||||
- Support Bot API 3.5 (PR `#920`_)
|
||||
|
||||
|
||||
Changes
|
||||
|
||||
- Fix race condition in dispatcher start/stop (`#887`_)
|
||||
- Log error trace if there is no error handler registered (`#694`_)
|
||||
- Update examples with consistent string formatting (`#870`_)
|
||||
- Various changes and improvements to the docs.
|
||||
|
||||
.. _`#920`: https://github.com/python-telegram-bot/python-telegram-bot/pull/920
|
||||
.. _`#930`: https://github.com/python-telegram-bot/python-telegram-bot/pull/930
|
||||
.. _`#887`: https://github.com/python-telegram-bot/python-telegram-bot/pull/887
|
||||
.. _`#694`: https://github.com/python-telegram-bot/python-telegram-bot/pull/694
|
||||
.. _`#870`: https://github.com/python-telegram-bot/python-telegram-bot/pull/870
|
||||
|
||||
**2017-10-15**
|
||||
*Released 8.1.1*
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at devs@python-telegram-bot.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
@@ -7,7 +7,6 @@ environment:
|
||||
# isn't covered by this document) at the time of writing.
|
||||
|
||||
- PYTHON: "C:\\Python27"
|
||||
- PYTHON: "C:\\Python33"
|
||||
- PYTHON: "C:\\Python34"
|
||||
- PYTHON: "C:\\Python35"
|
||||
- PYTHON: "C:\\Python36"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
comment:
|
||||
layout: "diff, files"
|
||||
behavior: default
|
||||
require_changes: false
|
||||
+2
-2
@@ -58,9 +58,9 @@ author = u'Leandro Toledo'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '8.1' # telegram.__version__[:3]
|
||||
version = '9.0' # telegram.__version__[:3]
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '8.1.1' # telegram.__version__
|
||||
release = '9.0.0' # telegram.__version__
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -12,6 +12,10 @@ objects in the package reflect the types as defined by the `telegram bot api <ht
|
||||
.. toctree::
|
||||
telegram
|
||||
|
||||
Changelog
|
||||
---------
|
||||
|
||||
.. include:: ..\\..\\CHANGES.rst
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.InputMedia
|
||||
===================
|
||||
|
||||
.. autoclass:: telegram.InputMedia
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.InputMediaPhoto
|
||||
========================
|
||||
|
||||
.. autoclass:: telegram.InputMediaPhoto
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,6 @@
|
||||
telegram.InputMediaVideo
|
||||
========================
|
||||
|
||||
.. autoclass:: telegram.InputMediaVideo
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -21,6 +21,9 @@ telegram package
|
||||
telegram.inlinekeyboardbutton
|
||||
telegram.inlinekeyboardmarkup
|
||||
telegram.inputfile
|
||||
telegram.inputmedia
|
||||
telegram.inputmediaphoto
|
||||
telegram.inputmediavideo
|
||||
telegram.keyboardbutton
|
||||
telegram.location
|
||||
telegram.message
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
# Examples
|
||||
|
||||
The examples in this folder are small bots meant to show you how a bot that is written with `python-telegram-bot` looks like. Some bots focus on one specific aspect of the Telegram Bot API while others focus on one of the mechanics of this library. Except for the `echobot.py` example, they all use the high-level framework this library provides with the `telegram.ext` submodule.
|
||||
The examples in this folder are small bots meant to show you how a bot that is written with `python-telegram-bot` looks like. Some bots focus on one specific aspect of the Telegram Bot API while others focus on one of the mechanics of this library. Except for the [`echobot.py`](#pure-api) example, they all use the high-level framework this library provides with the [`telegram.ext`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.html) submodule.
|
||||
|
||||
All examples are licensed under the [CC0 License](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/LICENSE.txt) and are therefore fully dedicated to the public domain. You can use them as the base for your own bots without worrying about copyrights.
|
||||
|
||||
@@ -22,5 +22,8 @@ This example sheds some light on inline keyboards, callback queries and message
|
||||
### [`inlinebot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/inlinebot.py)
|
||||
A basic example of an [inline bot](https://core.telegram.org/bots/inline). Don't forget to enable inline mode with [@BotFather](https://telegram.me/BotFather).
|
||||
|
||||
### [`paymentbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/examples/inlinebot.py)
|
||||
A basic example of a bot that can accept payments. Don't forget to enable and configure payments with [@BotFather](https://telegram.me/BotFather).
|
||||
|
||||
## Pure API
|
||||
The [`echobot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/echobot.py) example uses only the pure, "bare-metal" API wrapper.
|
||||
|
||||
@@ -46,7 +46,7 @@ def start(bot, update):
|
||||
|
||||
def gender(bot, update):
|
||||
user = update.message.from_user
|
||||
logger.info("Gender of %s: %s" % (user.first_name, update.message.text))
|
||||
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.',
|
||||
reply_markup=ReplyKeyboardRemove())
|
||||
@@ -58,7 +58,7 @@ def photo(bot, update):
|
||||
user = update.message.from_user
|
||||
photo_file = bot.get_file(update.message.photo[-1].file_id)
|
||||
photo_file.download('user_photo.jpg')
|
||||
logger.info("Photo of %s: %s" % (user.first_name, 'user_photo.jpg'))
|
||||
logger.info("Photo of %s: %s", user.first_name, 'user_photo.jpg')
|
||||
update.message.reply_text('Gorgeous! Now, send me your location please, '
|
||||
'or send /skip if you don\'t want to.')
|
||||
|
||||
@@ -67,7 +67,7 @@ def photo(bot, update):
|
||||
|
||||
def skip_photo(bot, update):
|
||||
user = update.message.from_user
|
||||
logger.info("User %s did not send a photo." % user.first_name)
|
||||
logger.info("User %s did not send a photo.", user.first_name)
|
||||
update.message.reply_text('I bet you look great! Now, send me your location please, '
|
||||
'or send /skip.')
|
||||
|
||||
@@ -77,8 +77,8 @@ def skip_photo(bot, update):
|
||||
def location(bot, update):
|
||||
user = update.message.from_user
|
||||
user_location = update.message.location
|
||||
logger.info("Location of %s: %f / %f"
|
||||
% (user.first_name, user_location.latitude, user_location.longitude))
|
||||
logger.info("Location of %s: %f / %f", user.first_name, user_location.latitude,
|
||||
user_location.longitude)
|
||||
update.message.reply_text('Maybe I can visit you sometime! '
|
||||
'At last, tell me something about yourself.')
|
||||
|
||||
@@ -87,7 +87,7 @@ def location(bot, update):
|
||||
|
||||
def skip_location(bot, update):
|
||||
user = update.message.from_user
|
||||
logger.info("User %s did not send a location." % user.first_name)
|
||||
logger.info("User %s did not send a location.", user.first_name)
|
||||
update.message.reply_text('You seem a bit paranoid! '
|
||||
'At last, tell me something about yourself.')
|
||||
|
||||
@@ -96,7 +96,7 @@ def skip_location(bot, update):
|
||||
|
||||
def bio(bot, update):
|
||||
user = update.message.from_user
|
||||
logger.info("Bio of %s: %s" % (user.first_name, update.message.text))
|
||||
logger.info("Bio of %s: %s", user.first_name, update.message.text)
|
||||
update.message.reply_text('Thank you! I hope we can talk again some day.')
|
||||
|
||||
return ConversationHandler.END
|
||||
@@ -104,7 +104,7 @@ def bio(bot, update):
|
||||
|
||||
def cancel(bot, update):
|
||||
user = update.message.from_user
|
||||
logger.info("User %s canceled the conversation." % user.first_name)
|
||||
logger.info("User %s canceled the conversation.", user.first_name)
|
||||
update.message.reply_text('Bye! I hope we can talk again some day.',
|
||||
reply_markup=ReplyKeyboardRemove())
|
||||
|
||||
@@ -112,7 +112,8 @@ def cancel(bot, update):
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logger.warn('Update "%s" caused error "%s"' % (update, error))
|
||||
"""Log Errors caused by Updates."""
|
||||
logger.warning('Update "%s" caused error "%s"', update, error)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -41,7 +41,7 @@ def facts_to_str(user_data):
|
||||
facts = list()
|
||||
|
||||
for key, value in user_data.items():
|
||||
facts.append('%s - %s' % (key, value))
|
||||
facts.append('{} - {}'.format(key, value))
|
||||
|
||||
return "\n".join(facts).join(['\n', '\n'])
|
||||
|
||||
@@ -58,7 +58,8 @@ def start(bot, update):
|
||||
def regular_choice(bot, update, user_data):
|
||||
text = update.message.text
|
||||
user_data['choice'] = text
|
||||
update.message.reply_text('Your %s? Yes, I would love to hear about that!' % text.lower())
|
||||
update.message.reply_text(
|
||||
'Your {}? Yes, I would love to hear about that!'.format(text.lower()))
|
||||
|
||||
return TYPING_REPLY
|
||||
|
||||
@@ -77,10 +78,9 @@ def received_information(bot, update, user_data):
|
||||
del user_data['choice']
|
||||
|
||||
update.message.reply_text("Neat! Just so you know, this is what you already told me:"
|
||||
"%s"
|
||||
"You can tell me more, or change your opinion on something."
|
||||
% facts_to_str(user_data),
|
||||
reply_markup=markup)
|
||||
"{}"
|
||||
"You can tell me more, or change your opinion on something.".format(
|
||||
facts_to_str(user_data)), reply_markup=markup)
|
||||
|
||||
return CHOOSING
|
||||
|
||||
@@ -90,15 +90,16 @@ def done(bot, update, user_data):
|
||||
del user_data['choice']
|
||||
|
||||
update.message.reply_text("I learned these facts about you:"
|
||||
"%s"
|
||||
"Until next time!" % facts_to_str(user_data))
|
||||
"{}"
|
||||
"Until next time!".format(facts_to_str(user_data)))
|
||||
|
||||
user_data.clear()
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logger.warn('Update "%s" caused error "%s"' % (update, error))
|
||||
"""Log Errors caused by Updates."""
|
||||
logger.warning('Update "%s" caused error "%s"', update, error)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
+9
-4
@@ -1,9 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Simple Bot to reply to Telegram messages. This is built on the API wrapper, see
|
||||
# echobot2.py to see the same example built on the telegram.ext bot framework.
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
"""Simple Bot to reply to Telegram messages.
|
||||
|
||||
This is built on the API wrapper, see echobot2.py to see the same example built
|
||||
on the telegram.ext bot framework.
|
||||
This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
import logging
|
||||
import telegram
|
||||
from telegram.error import NetworkError, Unauthorized
|
||||
@@ -12,7 +14,9 @@ from time import sleep
|
||||
|
||||
update_id = None
|
||||
|
||||
|
||||
def main():
|
||||
"""Run the bot."""
|
||||
global update_id
|
||||
# Telegram Bot Authorization Token
|
||||
bot = telegram.Bot('TOKEN')
|
||||
@@ -37,6 +41,7 @@ def main():
|
||||
|
||||
|
||||
def echo(bot):
|
||||
"""Echo the message the user sent."""
|
||||
global update_id
|
||||
# Request updates after the last update_id
|
||||
for update in bot.get_updates(offset=update_id, timeout=10):
|
||||
|
||||
+11
-5
@@ -1,9 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Simple Bot to reply to Telegram messages
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
|
||||
"""Simple Bot to reply to Telegram messages.
|
||||
|
||||
This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
This Bot uses the Updater class to handle the bot.
|
||||
|
||||
First, a few handler functions are defined. Then, those functions are passed to
|
||||
@@ -29,22 +30,27 @@ logger = logging.getLogger(__name__)
|
||||
# Define a few command handlers. These usually take the two arguments bot and
|
||||
# update. Error handlers also receive the raised TelegramError object in error.
|
||||
def start(bot, update):
|
||||
"""Send a message when the command /start is issued."""
|
||||
update.message.reply_text('Hi!')
|
||||
|
||||
|
||||
def help(bot, update):
|
||||
"""Send a message when the command /help is issued."""
|
||||
update.message.reply_text('Help!')
|
||||
|
||||
|
||||
def echo(bot, update):
|
||||
"""Echo the user message."""
|
||||
update.message.reply_text(update.message.text)
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logger.warn('Update "%s" caused error "%s"' % (update, error))
|
||||
"""Log Errors caused by Updates."""
|
||||
logger.warning('Update "%s" caused error "%s"', update, error)
|
||||
|
||||
|
||||
def main():
|
||||
"""Start the bot."""
|
||||
# Create the EventHandler and pass it your bot's token.
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
|
||||
+30
-29
@@ -1,9 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Simple Bot to reply to Telegram messages
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
|
||||
"""Simple Bot to reply to Telegram messages.
|
||||
|
||||
This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
This Bot uses the Updater class to handle the bot.
|
||||
|
||||
First, a few handler functions are defined. Then, those functions are passed to
|
||||
@@ -19,6 +20,8 @@ from uuid import uuid4
|
||||
|
||||
import re
|
||||
|
||||
from telegram.utils.helpers import escape_markdown
|
||||
|
||||
from telegram import InlineQueryResultArticle, ParseMode, \
|
||||
InputTextMessageContent
|
||||
from telegram.ext import Updater, InlineQueryHandler, CommandHandler
|
||||
@@ -34,45 +37,43 @@ logger = logging.getLogger(__name__)
|
||||
# Define a few command handlers. These usually take the two arguments bot and
|
||||
# update. Error handlers also receive the raised TelegramError object in error.
|
||||
def start(bot, update):
|
||||
"""Send a message when the command /start is issued."""
|
||||
update.message.reply_text('Hi!')
|
||||
|
||||
|
||||
def help(bot, update):
|
||||
"""Send a message when the command /help is issued."""
|
||||
update.message.reply_text('Help!')
|
||||
|
||||
|
||||
def escape_markdown(text):
|
||||
"""Helper function to escape telegram markup symbols"""
|
||||
escape_chars = '\*_`\['
|
||||
return re.sub(r'([%s])' % escape_chars, r'\\\1', text)
|
||||
|
||||
|
||||
def inlinequery(bot, update):
|
||||
"""Handle the inline query."""
|
||||
query = update.inline_query.query
|
||||
results = list()
|
||||
|
||||
results.append(InlineQueryResultArticle(id=uuid4(),
|
||||
title="Caps",
|
||||
input_message_content=InputTextMessageContent(
|
||||
query.upper())))
|
||||
|
||||
results.append(InlineQueryResultArticle(id=uuid4(),
|
||||
title="Bold",
|
||||
input_message_content=InputTextMessageContent(
|
||||
"*%s*" % escape_markdown(query),
|
||||
parse_mode=ParseMode.MARKDOWN)))
|
||||
|
||||
results.append(InlineQueryResultArticle(id=uuid4(),
|
||||
title="Italic",
|
||||
input_message_content=InputTextMessageContent(
|
||||
"_%s_" % escape_markdown(query),
|
||||
parse_mode=ParseMode.MARKDOWN)))
|
||||
results = [
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(),
|
||||
title="Caps",
|
||||
input_message_content=InputTextMessageContent(
|
||||
query.upper())),
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(),
|
||||
title="Bold",
|
||||
input_message_content=InputTextMessageContent(
|
||||
"*{}*".format(escape_markdown(query)),
|
||||
parse_mode=ParseMode.MARKDOWN)),
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(),
|
||||
title="Italic",
|
||||
input_message_content=InputTextMessageContent(
|
||||
"_{}_".format(escape_markdown(query)),
|
||||
parse_mode=ParseMode.MARKDOWN))]
|
||||
|
||||
update.inline_query.answer(results)
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logger.warning('Update "%s" caused error "%s"' % (update, error))
|
||||
"""Log Errors caused by Updates."""
|
||||
logger.warning('Update "%s" caused error "%s"', update, error)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
+23
-16
@@ -1,15 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Basic example for a bot that uses inline keyboards.
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
"""Basic example for a bot that uses inline keyboards.
|
||||
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
import logging
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
|
||||
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def start(bot, update):
|
||||
@@ -26,7 +27,7 @@ def start(bot, update):
|
||||
def button(bot, update):
|
||||
query = update.callback_query
|
||||
|
||||
bot.edit_message_text(text="Selected option: %s" % query.data,
|
||||
bot.edit_message_text(text="Selected option: {}".format(query.data),
|
||||
chat_id=query.message.chat_id,
|
||||
message_id=query.message.message_id)
|
||||
|
||||
@@ -36,20 +37,26 @@ def help(bot, update):
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logging.warning('Update "%s" caused error "%s"' % (update, error))
|
||||
"""Log Errors caused by Updates."""
|
||||
logger.warning('Update "%s" caused error "%s"', update, error)
|
||||
|
||||
|
||||
# Create the Updater and pass it your bot's token.
|
||||
updater = Updater("TOKEN")
|
||||
def main():
|
||||
# Create the Updater and pass it your bot's token.
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
updater.dispatcher.add_handler(CommandHandler('start', start))
|
||||
updater.dispatcher.add_handler(CallbackQueryHandler(button))
|
||||
updater.dispatcher.add_handler(CommandHandler('help', help))
|
||||
updater.dispatcher.add_error_handler(error)
|
||||
updater.dispatcher.add_handler(CommandHandler('start', start))
|
||||
updater.dispatcher.add_handler(CallbackQueryHandler(button))
|
||||
updater.dispatcher.add_handler(CommandHandler('help', help))
|
||||
updater.dispatcher.add_error_handler(error)
|
||||
|
||||
# Start the Bot
|
||||
updater.start_polling()
|
||||
# Start the Bot
|
||||
updater.start_polling()
|
||||
|
||||
# Run the bot until the user presses Ctrl-C or the process receives SIGINT,
|
||||
# SIGTERM or SIGABRT
|
||||
updater.idle()
|
||||
# Run the bot until the user presses Ctrl-C or the process receives SIGINT,
|
||||
# SIGTERM or SIGABRT
|
||||
updater.idle()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
+10
-6
@@ -1,8 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Basic example for a bot that can receive payment from user.
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
"""Basic example for a bot that can receive payment from user.
|
||||
|
||||
This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
|
||||
from telegram import (LabeledPrice, ShippingOption)
|
||||
from telegram.ext import (Updater, CommandHandler, MessageHandler,
|
||||
@@ -10,13 +12,15 @@ from telegram.ext import (Updater, CommandHandler, MessageHandler,
|
||||
import logging
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logger.warn('Update "%s" caused error "%s"' % (update, error))
|
||||
"""Log Errors caused by Updates."""
|
||||
logger.warning('Update "%s" caused error "%s"', update, error)
|
||||
|
||||
|
||||
def start_callback(bot, update):
|
||||
@@ -31,7 +35,7 @@ def start_with_shipping_callback(bot, update):
|
||||
description = "Payment Example using python-telegram-bot"
|
||||
# select a payload just for you to recognize its the donation from your bot
|
||||
payload = "Custom-Payload"
|
||||
# get your provider_token at @botfather, see https://core.telegram.org/bots/payments#getting-a-token
|
||||
# In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
|
||||
provider_token = "PROVIDER_TOKEN"
|
||||
start_parameter = "test-payment"
|
||||
currency = "USD"
|
||||
@@ -55,7 +59,7 @@ def start_without_shipping_callback(bot, update):
|
||||
description = "Payment Example using python-telegram-bot"
|
||||
# select a payload just for you to recognize its the donation from your bot
|
||||
payload = "Custom-Payload"
|
||||
# get your provider_token at @botfather, see https://core.telegram.org/bots/payments#getting-a-token
|
||||
# In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
|
||||
provider_token = "PROVIDER_TOKEN"
|
||||
start_parameter = "test-payment"
|
||||
currency = "USD"
|
||||
|
||||
+14
-11
@@ -1,9 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Simple Bot to send timed Telegram messages
|
||||
|
||||
|
||||
"""Simple Bot to send timed Telegram messages.
|
||||
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
"""
|
||||
|
||||
This Bot uses the Updater class to handle the bot and the JobQueue to send
|
||||
timed messages.
|
||||
|
||||
@@ -17,7 +19,7 @@ Press Ctrl-C on the command line or send a signal to the process to stop the
|
||||
bot.
|
||||
"""
|
||||
|
||||
from telegram.ext import Updater, CommandHandler, Job
|
||||
from telegram.ext import Updater, CommandHandler
|
||||
import logging
|
||||
|
||||
# Enable logging
|
||||
@@ -34,12 +36,12 @@ def start(bot, update):
|
||||
|
||||
|
||||
def alarm(bot, job):
|
||||
"""Function to send the alarm message"""
|
||||
"""Send the alarm message."""
|
||||
bot.send_message(job.context, text='Beep!')
|
||||
|
||||
|
||||
def set(bot, update, args, job_queue, chat_data):
|
||||
"""Adds a job to the queue"""
|
||||
def set_timer(bot, update, args, job_queue, chat_data):
|
||||
"""Add a job to the queue."""
|
||||
chat_id = update.message.chat_id
|
||||
try:
|
||||
# args[0] should contain the time for the timer in seconds
|
||||
@@ -59,8 +61,7 @@ def set(bot, update, args, job_queue, chat_data):
|
||||
|
||||
|
||||
def unset(bot, update, chat_data):
|
||||
"""Removes the job if the user changed their mind"""
|
||||
|
||||
"""Remove the job if the user changed their mind."""
|
||||
if 'job' not in chat_data:
|
||||
update.message.reply_text('You have no active timer')
|
||||
return
|
||||
@@ -73,10 +74,12 @@ def unset(bot, update, chat_data):
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logger.warning('Update "%s" caused error "%s"' % (update, error))
|
||||
"""Log Errors caused by Updates."""
|
||||
logger.warning('Update "%s" caused error "%s"', update, error)
|
||||
|
||||
|
||||
def main():
|
||||
"""Run bot."""
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
@@ -85,7 +88,7 @@ def main():
|
||||
# on different commands - answer in Telegram
|
||||
dp.add_handler(CommandHandler("start", start))
|
||||
dp.add_handler(CommandHandler("help", start))
|
||||
dp.add_handler(CommandHandler("set", set,
|
||||
dp.add_handler(CommandHandler("set", set_timer,
|
||||
pass_args=True,
|
||||
pass_job_queue=True,
|
||||
pass_chat_data=True))
|
||||
|
||||
@@ -53,7 +53,6 @@ with codecs.open('README.rst', 'r', 'utf-8') as fd:
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6'
|
||||
|
||||
@@ -96,6 +96,9 @@ from .constants import (MAX_MESSAGE_LENGTH, MAX_CAPTION_LENGTH, SUPPORTED_WEBHOO
|
||||
MAX_FILESIZE_DOWNLOAD, MAX_FILESIZE_UPLOAD,
|
||||
MAX_MESSAGES_PER_SECOND_PER_CHAT, MAX_MESSAGES_PER_SECOND,
|
||||
MAX_MESSAGES_PER_MINUTE_PER_GROUP)
|
||||
from .files.inputmedia import InputMedia
|
||||
from .files.inputmediavideo import InputMediaVideo
|
||||
from .files.inputmediaphoto import InputMediaPhoto
|
||||
from .version import __version__ # flake8: noqa
|
||||
|
||||
__author__ = 'devs@python-telegram-bot.org'
|
||||
@@ -121,5 +124,6 @@ __all__ = [
|
||||
'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation',
|
||||
'Game', 'GameHighScore', 'VideoNote', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption',
|
||||
'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery', 'ChatPhoto',
|
||||
'StickerSet', 'MaskPosition', 'CallbackGame'
|
||||
'StickerSet', 'MaskPosition', 'CallbackGame', 'InputMedia', 'InputMediaPhoto',
|
||||
'InputMediaVideo'
|
||||
]
|
||||
|
||||
+66
-8
@@ -21,10 +21,13 @@
|
||||
"""This module contains an object that represents a Telegram Bot."""
|
||||
|
||||
import functools
|
||||
import json
|
||||
import logging
|
||||
import warnings
|
||||
from datetime import datetime
|
||||
|
||||
from future.utils import string_types
|
||||
|
||||
from telegram import (User, Message, Update, Chat, ChatMember, UserProfilePhotos, File,
|
||||
ReplyMarkup, TelegramObject, WebhookInfo, GameHighScore, StickerSet,
|
||||
PhotoSize, Audio, Document, Sticker, Video, Voice, VideoNote, Location,
|
||||
@@ -335,12 +338,12 @@ class Bot(TelegramObject):
|
||||
disable_notification=False,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
timeout=20.,
|
||||
timeout=20,
|
||||
**kwargs):
|
||||
"""Use this method to send photos.
|
||||
|
||||
Note:
|
||||
The video argument can be either a file_id, an URL or a file from disk
|
||||
The photo argument can be either a file_id, an URL or a file from disk
|
||||
``open(filename, 'rb')``
|
||||
|
||||
Args:
|
||||
@@ -394,7 +397,7 @@ class Bot(TelegramObject):
|
||||
disable_notification=False,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
timeout=20.,
|
||||
timeout=20,
|
||||
**kwargs):
|
||||
"""
|
||||
Use this method to send audio files, if you want Telegram clients to display them in the
|
||||
@@ -465,7 +468,7 @@ class Bot(TelegramObject):
|
||||
disable_notification=False,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
timeout=20.,
|
||||
timeout=20,
|
||||
**kwargs):
|
||||
"""Use this method to send general files.
|
||||
|
||||
@@ -576,7 +579,7 @@ class Bot(TelegramObject):
|
||||
disable_notification=False,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
timeout=20.,
|
||||
timeout=20,
|
||||
width=None,
|
||||
height=None,
|
||||
**kwargs):
|
||||
@@ -646,7 +649,7 @@ class Bot(TelegramObject):
|
||||
disable_notification=False,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
timeout=20.,
|
||||
timeout=20,
|
||||
**kwargs):
|
||||
"""
|
||||
Use this method to send audio files, if you want Telegram clients to display the file
|
||||
@@ -708,7 +711,7 @@ class Bot(TelegramObject):
|
||||
disable_notification=False,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
timeout=20.,
|
||||
timeout=20,
|
||||
**kwargs):
|
||||
"""Use this method to send video messages.
|
||||
|
||||
@@ -757,6 +760,51 @@ class Bot(TelegramObject):
|
||||
|
||||
return url, data
|
||||
|
||||
@log
|
||||
def send_media_group(self,
|
||||
chat_id,
|
||||
media,
|
||||
disable_notification=None,
|
||||
reply_to_message_id=None,
|
||||
timeout=20,
|
||||
**kwargs):
|
||||
"""Use this method to send a group of photos or videos as an album.
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||
of the target channel (in the format @channelusername).
|
||||
media (List[:class:`telegram.InputMedia`]): An array describing photos and videos to be
|
||||
sent, must include 2–10 items.
|
||||
disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
|
||||
receive a notification with no sound.
|
||||
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
|
||||
original message.
|
||||
timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds).
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Returns:
|
||||
List[:class:`telegram.Message`]: An array of the sent Messages.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
"""
|
||||
# TODO: Make InputMediaPhoto, InputMediaVideo and send_media_group work with new files
|
||||
|
||||
url = '{0}/sendMediaGroup'.format(self.base_url)
|
||||
|
||||
media = [med.to_dict() for med in media]
|
||||
|
||||
data = {'chat_id': chat_id, 'media': media}
|
||||
|
||||
if reply_to_message_id:
|
||||
data['reply_to_message_id'] = reply_to_message_id
|
||||
if disable_notification:
|
||||
data['disable_notification'] = disable_notification
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return [Message.de_json(res, self) for res in result]
|
||||
|
||||
@log
|
||||
@message
|
||||
def send_location(self,
|
||||
@@ -2153,6 +2201,7 @@ class Bot(TelegramObject):
|
||||
disable_notification=False,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None,
|
||||
provider_data=None,
|
||||
timeout=None,
|
||||
**kwargs):
|
||||
"""Use this method to send invoices.
|
||||
@@ -2169,6 +2218,10 @@ class Bot(TelegramObject):
|
||||
currency (:obj:`str`): Three-letter ISO 4217 currency code.
|
||||
prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a list of components
|
||||
(e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.).
|
||||
provider_data (:obj:`str` | :obj:`object`, optional): JSON-encoded data about the
|
||||
invoice, which will be shared with the payment provider. A detailed description of
|
||||
required fields should be provided by the payment provider. When an object is
|
||||
passed, it will be encoded as JSON.
|
||||
photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a
|
||||
photo of the goods or a marketing image for a service. People like it better when
|
||||
they see what they are paying for.
|
||||
@@ -2216,7 +2269,11 @@ class Bot(TelegramObject):
|
||||
'currency': currency,
|
||||
'prices': [p.to_dict() for p in prices]
|
||||
}
|
||||
|
||||
if provider_data is not None:
|
||||
if isinstance(provider_data, string_types):
|
||||
data['provider_data'] = provider_data
|
||||
else:
|
||||
data['provider_data'] = json.dumps(provider_data)
|
||||
if photo_url is not None:
|
||||
data['photo_url'] = photo_url
|
||||
if photo_size is not None:
|
||||
@@ -2965,6 +3022,7 @@ class Bot(TelegramObject):
|
||||
sendVideo = send_video
|
||||
sendVoice = send_voice
|
||||
sendVideoNote = send_video_note
|
||||
sendMediaGroup = send_media_group
|
||||
sendLocation = send_location
|
||||
editMessageLiveLocation = edit_message_live_location
|
||||
stopMessageLiveLocation = stop_message_live_location
|
||||
|
||||
@@ -183,14 +183,20 @@ class Dispatcher(object):
|
||||
self.__async_queue.put(promise)
|
||||
return promise
|
||||
|
||||
def start(self):
|
||||
def start(self, ready=None):
|
||||
"""Thread target of thread 'dispatcher'.
|
||||
|
||||
Runs in background and processes the update queue.
|
||||
|
||||
Args:
|
||||
ready (:obj:`threading.Event`, optional): If specified, the event will be set once the
|
||||
dispatcher is ready.
|
||||
|
||||
"""
|
||||
if self.running:
|
||||
self.logger.warning('already running')
|
||||
if ready is not None:
|
||||
ready.set()
|
||||
return
|
||||
|
||||
if self.__exception_event.is_set():
|
||||
@@ -202,6 +208,9 @@ class Dispatcher(object):
|
||||
self.running = True
|
||||
self.logger.debug('Dispatcher started')
|
||||
|
||||
if ready is not None:
|
||||
ready.set()
|
||||
|
||||
while 1:
|
||||
try:
|
||||
# Pop update from update queue.
|
||||
@@ -370,5 +379,10 @@ class Dispatcher(object):
|
||||
error (:class:`telegram.TelegramError`): The Telegram error that was raised.
|
||||
|
||||
"""
|
||||
for callback in self.error_handlers:
|
||||
callback(self.bot, update, error)
|
||||
if self.error_handlers:
|
||||
for callback in self.error_handlers:
|
||||
callback(self.bot, update, error)
|
||||
|
||||
else:
|
||||
self.logger.exception(
|
||||
'No error handlers are registered, logging exception...', exc_info=error)
|
||||
|
||||
@@ -265,7 +265,7 @@ class Filters(object):
|
||||
"""Subset for messages containing a status update.
|
||||
|
||||
Examples:
|
||||
Use these filters like: ``Filters.status_update.new_chat_member`` etc. Or use just
|
||||
Use these filters like: ``Filters.status_update.new_chat_members`` etc. Or use just
|
||||
``Filters.status_update`` for all status update messages.
|
||||
|
||||
"""
|
||||
|
||||
@@ -199,10 +199,13 @@ class Updater(object):
|
||||
|
||||
# Create & start threads
|
||||
self.job_queue.start()
|
||||
self._init_thread(self.dispatcher.start, "dispatcher")
|
||||
dispatcher_ready = Event()
|
||||
self._init_thread(self.dispatcher.start, "dispatcher", ready=dispatcher_ready)
|
||||
self._init_thread(self._start_polling, "updater", poll_interval, timeout,
|
||||
read_latency, bootstrap_retries, clean, allowed_updates)
|
||||
|
||||
dispatcher_ready.wait()
|
||||
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2017
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# 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/].
|
||||
"""Base class for Telegram InputMedia Objects."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class InputMedia(TelegramObject):
|
||||
"""Base class for Telegram InputMedia Objects.
|
||||
|
||||
See :class:`telegram.InputMediaPhoto` and :class:`telegram.InputMediaVideo` for
|
||||
detailed use.
|
||||
|
||||
"""
|
||||
pass
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2017
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# 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 an object that represents a Telegram InputMediaPhoto."""
|
||||
from telegram import InputMedia, PhotoSize
|
||||
|
||||
|
||||
class InputMediaPhoto(InputMedia):
|
||||
"""Represents a photo to be sent.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): ``photo``.
|
||||
media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the
|
||||
Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the
|
||||
Internet. Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
|
||||
caption (:obj:`str`): Optional. Caption of the photo to be sent, 0-200 characters.
|
||||
|
||||
Args:
|
||||
media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the
|
||||
Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the
|
||||
Internet. Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
|
||||
caption (:obj:`str`, optional ): Caption of the photo to be sent, 0-200 characters.
|
||||
|
||||
Note:
|
||||
At the moment using a new file is not yet supported.
|
||||
"""
|
||||
|
||||
# TODO: Make InputMediaPhoto, InputMediaVideo and send_media_group work with new files
|
||||
|
||||
def __init__(self, media, caption=None):
|
||||
self.type = 'photo'
|
||||
|
||||
if isinstance(media, PhotoSize):
|
||||
self.media = media.file_id
|
||||
elif hasattr(media, 'read'):
|
||||
raise ValueError(
|
||||
'Sending files is not supported (yet). Use file_id, url or PhotoSize')
|
||||
else:
|
||||
self.media = media
|
||||
|
||||
if caption:
|
||||
self.caption = caption
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2017
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# 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 an object that represents a Telegram InputMediaPhoto."""
|
||||
from telegram import InputMedia, Video
|
||||
|
||||
|
||||
class InputMediaVideo(InputMedia):
|
||||
"""Represents a video to be sent.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): ``video``.
|
||||
media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the Telegram
|
||||
servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet.
|
||||
Lastly you can pass an existing :class:`telegram.Video` object to send.
|
||||
caption (:obj:`str`): Optional. Caption of the video to be sent, 0-200 characters.
|
||||
width (:obj:`int`): Optional. Video width.
|
||||
height (:obj:`int`): Optional. Video height.
|
||||
duration (:obj:`int`): Optional. Video duration.
|
||||
|
||||
Args:
|
||||
media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the Telegram
|
||||
servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet.
|
||||
Lastly you can pass an existing :class:`telegram.Video` object to send.
|
||||
caption (:obj:`str`, optional): Caption of the video to be sent, 0-200 characters.
|
||||
width (:obj:`int`, optional): Video width.
|
||||
height (:obj:`int`, optional): Video height.
|
||||
duration (:obj:`int`, optional): Video duration.
|
||||
|
||||
Note:
|
||||
When using a :class:`telegram.Video` for the :attr:`media` attribute. It will take the
|
||||
width, height and duration from that video, unless otherwise specified with the optional
|
||||
arguments.
|
||||
At the moment using a new file is not yet supported.
|
||||
"""
|
||||
|
||||
# TODO: Make InputMediaPhoto, InputMediaVideo and send_media_group work with new files
|
||||
|
||||
def __init__(self, media, caption=None, width=None, height=None, duration=None):
|
||||
self.type = 'video'
|
||||
|
||||
if isinstance(media, Video):
|
||||
self.media = media.file_id
|
||||
self.width = media.width
|
||||
self.height = media.height
|
||||
self.duration = media.duration
|
||||
elif hasattr(media, 'read'):
|
||||
raise ValueError('Sending files is not supported (yet). Use file_id, url or Video')
|
||||
else:
|
||||
self.media = media
|
||||
|
||||
if caption:
|
||||
self.caption = caption
|
||||
if width:
|
||||
self.width = width
|
||||
if height:
|
||||
self.height = height
|
||||
if duration:
|
||||
self.duration = duration
|
||||
@@ -48,6 +48,8 @@ class Message(TelegramObject):
|
||||
forward_date (:class:`datetime.datetime`): Optional. Date the original message was sent.
|
||||
reply_to_message (:class:`telegram.Message`): Optional. The original message.
|
||||
edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited.
|
||||
media_group_id (:obj:`str`): Optional. The unique identifier of a media message group this
|
||||
message belongs to.
|
||||
text (:obj:`str`): Optional. The actual UTF-8 text of the message.
|
||||
entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like
|
||||
usernames, URLs, bot commands, etc. that appear in the text. See
|
||||
@@ -117,6 +119,8 @@ class Message(TelegramObject):
|
||||
``reply_to_message`` fields even if it itself is a reply.
|
||||
edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix
|
||||
time. Converted to :class:`datetime.datetime`.
|
||||
media_group_id (:obj:`str`, optional): The unique identifier of a media message group this
|
||||
message belongs to.
|
||||
text (str, optional): For text messages, the actual UTF-8 text of the message, 0-4096
|
||||
characters. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`.
|
||||
entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special
|
||||
@@ -232,6 +236,7 @@ class Message(TelegramObject):
|
||||
successful_payment=None,
|
||||
forward_signature=None,
|
||||
author_signature=None,
|
||||
media_group_id=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
@@ -277,6 +282,7 @@ class Message(TelegramObject):
|
||||
self.successful_payment = successful_payment
|
||||
self.forward_signature = forward_signature
|
||||
self.author_signature = author_signature
|
||||
self.media_group_id = media_group_id
|
||||
|
||||
self.bot = bot
|
||||
|
||||
|
||||
+1
-1
@@ -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__ = '8.1.1'
|
||||
__version__ = '9.0.0'
|
||||
|
||||
+2
-2
@@ -104,8 +104,8 @@ class TestBot(object):
|
||||
# Considering that the first message is old enough
|
||||
bot.delete_message(chat_id=chat_id, message_id=1)
|
||||
|
||||
# send_photo, send_audio, send_document, send_sticker, send_video, send_voice
|
||||
# and send_video_note are tested in their respective test modules. No need to duplicate here.
|
||||
# send_photo, send_audio, send_document, send_sticker, send_video, send_voice, send_video_note
|
||||
# and send_media_group are tested in their respective test modules. No need to duplicate here.
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2017
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import pytest
|
||||
from flaky import flaky
|
||||
|
||||
from telegram import InputMediaVideo, InputMediaPhoto, Message
|
||||
from .test_video import video, video_file
|
||||
from .test_photo import _photo, photo_file, photo, thumb
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def input_media_video():
|
||||
return InputMediaVideo(media=TestInputMediaVideo.media,
|
||||
caption=TestInputMediaVideo.caption,
|
||||
width=TestInputMediaVideo.width,
|
||||
height=TestInputMediaVideo.height,
|
||||
duration=TestInputMediaVideo.duration)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def input_media_photo():
|
||||
return InputMediaPhoto(media=TestInputMediaPhoto.media,
|
||||
caption=TestInputMediaPhoto.caption)
|
||||
|
||||
|
||||
class TestInputMediaVideo(object):
|
||||
type = "video"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
width = 3
|
||||
height = 4
|
||||
duration = 5
|
||||
|
||||
def test_expected_values(self, input_media_video):
|
||||
assert input_media_video.type == self.type
|
||||
assert input_media_video.media == self.media
|
||||
assert input_media_video.caption == self.caption
|
||||
assert input_media_video.width == self.width
|
||||
assert input_media_video.height == self.height
|
||||
assert input_media_video.duration == self.duration
|
||||
|
||||
def test_to_dict(self, input_media_video):
|
||||
input_media_video_dict = input_media_video.to_dict()
|
||||
assert input_media_video_dict['type'] == input_media_video.type
|
||||
assert input_media_video_dict['media'] == input_media_video.media
|
||||
assert input_media_video_dict['caption'] == input_media_video.caption
|
||||
assert input_media_video_dict['width'] == input_media_video.width
|
||||
assert input_media_video_dict['height'] == input_media_video.height
|
||||
assert input_media_video_dict['duration'] == input_media_video.duration
|
||||
|
||||
def test_with_video(self, video):
|
||||
# fixture found in test_video
|
||||
input_media_video = InputMediaVideo(video, caption="test 3")
|
||||
assert input_media_video.type == self.type
|
||||
assert input_media_video.media == video.file_id
|
||||
assert input_media_video.width == video.width
|
||||
assert input_media_video.height == video.height
|
||||
assert input_media_video.duration == video.duration
|
||||
assert input_media_video.caption == "test 3"
|
||||
|
||||
def test_error_with_file(self, video_file):
|
||||
# fixture found in test_video
|
||||
with pytest.raises(ValueError, match="file_id, url or Video"):
|
||||
InputMediaVideo(video_file)
|
||||
|
||||
|
||||
class TestInputMediaPhoto(object):
|
||||
type = "photo"
|
||||
media = "NOTAREALFILEID"
|
||||
caption = "My Caption"
|
||||
|
||||
def test_expected_values(self, input_media_photo):
|
||||
assert input_media_photo.type == self.type
|
||||
assert input_media_photo.media == self.media
|
||||
assert input_media_photo.caption == self.caption
|
||||
|
||||
def test_to_dict(self, input_media_photo):
|
||||
input_media_photo_dict = input_media_photo.to_dict()
|
||||
assert input_media_photo_dict['type'] == input_media_photo.type
|
||||
assert input_media_photo_dict['media'] == input_media_photo.media
|
||||
assert input_media_photo_dict['caption'] == input_media_photo.caption
|
||||
|
||||
def test_with_photo(self, photo):
|
||||
# fixture found in test_photo
|
||||
imp = InputMediaPhoto(photo, caption="test 2")
|
||||
assert imp.type == self.type
|
||||
assert imp.media == photo.file_id
|
||||
assert imp.caption == "test 2"
|
||||
|
||||
def test_error_with_file(self, photo_file):
|
||||
# fixture found in test_photo
|
||||
with pytest.raises(ValueError, match="file_id, url or PhotoSize"):
|
||||
InputMediaPhoto(photo_file)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def media_group(photo, thumb):
|
||||
return [InputMediaPhoto(photo), InputMediaPhoto(thumb)]
|
||||
|
||||
|
||||
class TestSendMediaGroup(object):
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_send_media_group_photo(self, bot, chat_id, media_group):
|
||||
messages = bot.send_media_group(chat_id, media_group)
|
||||
assert isinstance(messages, list)
|
||||
assert len(messages) == 2
|
||||
assert all([isinstance(mes, Message) for mes in messages])
|
||||
assert all([mes.media_group_id == messages[0].media_group_id for mes in messages])
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_send_media_group_all_args(self, bot, chat_id, media_group):
|
||||
m1 = bot.send_message(chat_id, text="test")
|
||||
messages = bot.send_media_group(chat_id, media_group, disable_notification=True,
|
||||
reply_to_message_id=m1.message_id)
|
||||
assert isinstance(messages, list)
|
||||
assert len(messages) == 2
|
||||
assert all([isinstance(mes, Message) for mes in messages])
|
||||
assert all([mes.media_group_id == messages[0].media_group_id for mes in messages])
|
||||
|
||||
@pytest.mark.skip(reason="Needs a rework to send new files")
|
||||
def test_send_media_group_new_files(self):
|
||||
pass
|
||||
@@ -32,6 +32,7 @@ def invoice():
|
||||
class TestInvoice(object):
|
||||
payload = 'payload'
|
||||
prices = [LabeledPrice('Fish', 100), LabeledPrice('Fish Tax', 1000)]
|
||||
provider_data = """{"test":"test"}"""
|
||||
title = 'title'
|
||||
description = 'description'
|
||||
start_parameter = 'start_parameter'
|
||||
@@ -88,6 +89,7 @@ class TestInvoice(object):
|
||||
self.start_parameter,
|
||||
self.currency,
|
||||
self.prices,
|
||||
provider_data=self.provider_data,
|
||||
photo_url='https://raw.githubusercontent.com/'
|
||||
'python-telegram-bot/logos/master/'
|
||||
'logo/png/ptb-logo_240.png',
|
||||
@@ -105,3 +107,24 @@ class TestInvoice(object):
|
||||
assert message.invoice.description == self.description
|
||||
assert message.invoice.title == self.title
|
||||
assert message.invoice.total_amount == self.total_amount
|
||||
|
||||
def test_send_object_as_provider_data(self, monkeypatch, bot, chat_id, provider_token):
|
||||
def test(_, url, data, **kwargs):
|
||||
return data['provider_data'] == '{"test_data": 123456789}'
|
||||
|
||||
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||
|
||||
assert bot.send_invoice(chat_id, self.title, self.description, self.payload,
|
||||
provider_token, self.start_parameter, self.currency,
|
||||
self.prices, provider_data={'test_data': 123456789})
|
||||
|
||||
def test_send_nonesense_as_provider_data(self, monkeypatch, bot, chat_id, provider_token):
|
||||
def test(_, url, data, **kwargs):
|
||||
return True
|
||||
|
||||
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
assert bot.send_invoice(chat_id, self.title, self.description, self.payload,
|
||||
provider_token, self.start_parameter, self.currency,
|
||||
self.prices, provider_data={'a', 'b', 'c'})
|
||||
|
||||
@@ -79,7 +79,10 @@ def message(bot):
|
||||
'charge_id', 'provider_id',
|
||||
order_info={})},
|
||||
{'forward_signature': 'some_forward_sign'},
|
||||
{'author_signature': 'some_author_sign'}
|
||||
{'author_signature': 'some_author_sign'},
|
||||
{'photo': [PhotoSize('photo_id', 50, 50)],
|
||||
'caption': 'photo_file',
|
||||
'media_group_id': 1234443322222}
|
||||
],
|
||||
ids=['forwarded_user', 'forwarded_channel', 'reply', 'edited', 'text',
|
||||
'caption_entities', 'audio', 'document', 'game', 'photo', 'sticker', 'video',
|
||||
@@ -87,7 +90,7 @@ def message(bot):
|
||||
'left_member', 'new_title', 'new_photo', 'delete_photo', 'group_created',
|
||||
'supergroup_created', 'channel_created', 'migrated_to', 'migrated_from',
|
||||
'pinned', 'invoice', 'successful_payment', 'forward_signature',
|
||||
'author_signature'])
|
||||
'author_signature', 'photo_from_media_group'])
|
||||
def message_params(bot, request):
|
||||
return Message(message_id=TestMessage.id,
|
||||
from_user=TestMessage.from_user,
|
||||
|
||||
@@ -105,7 +105,8 @@ def check_object(h4):
|
||||
field = parameter[0]
|
||||
if field == 'from':
|
||||
field = 'from_user'
|
||||
elif name.startswith('InlineQueryResult') and field == 'type':
|
||||
elif ((name.startswith('InlineQueryResult') or
|
||||
name.startswith('InputMedia')) and field == 'type'):
|
||||
continue
|
||||
elif field == 'remove_keyboard':
|
||||
continue
|
||||
|
||||
+3
-3
@@ -174,9 +174,9 @@ class TestPhoto(object):
|
||||
assert isinstance(photo.file_id, str)
|
||||
assert photo.file_id != ''
|
||||
assert isinstance(photo, PhotoSize)
|
||||
assert photo.width == 1920
|
||||
assert photo.height == 1080
|
||||
assert photo.file_size == 30907
|
||||
assert photo.width == 1280
|
||||
assert photo.height == 720
|
||||
assert photo.file_size == 33372
|
||||
|
||||
def test_send_with_photosize(self, monkeypatch, bot, chat_id, photo):
|
||||
def test(_, url, data, **kwargs):
|
||||
|
||||
Reference in New Issue
Block a user