Compare commits

...

41 Commits

Author SHA1 Message Date
Pieter Schutz 72ecc696cb Bump to v12.4.2 2020-02-10 11:39:26 +01:00
Bibo-Joshi a447760411 Make sure PP can read files that dont have bot_data (#1760)
* Make sure PP can read files that dont have bot_data

* Improve workaround
2020-02-08 19:24:35 +02:00
Bibo-Joshi 6da529c46b Pass correct parse_mode to InlineResults if bot.defaults is None (#1763)
* Pass correct parse_mode to InlineResults if bot.defaults is None

* Add tests for inlinequeryresults with (default)parse_mode

* enhance tests
2020-02-08 18:52:22 +02:00
Noam Meltzer bd1b2fb6c1 Bump version to v12.4.1 2020-02-08 15:06:05 +02:00
Bibo-Joshi f9a8cd924c Make Filters.command only accept MessageEntity commands (#1744)
* Make Filters.command only accept MessageEntitie commands

* Add option to filters.command to allow cmds anywhere in the message

* Make codecov happy, also retroactive for #1631
2020-02-08 14:54:21 +02:00
Bibo-Joshi 7b3b278c7c Bump version to v12.4 2020-02-08 10:01:41 +02:00
Bibo-Joshi cf3635d408 make test_webhook_invalid_posts flaky (#1758) 2020-02-07 18:32:38 +02:00
Bibo-Joshi 84cfc6f7fa Rename Test suite … (#1750)
* Rename Test suite

* Actually change the badge in readme

* fix download without path arguments (#1591)

* fix download without path arguments

* fix download without path arguments

* solved downloading a file without file_path or custom_path

* if no file_path, download as file_id

* Add test case

* Elaborate doc string

Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>

* Add default values (#1490)

* added parse_mode parameter in Updater and in Bot class to set a default parse mode for bot

* DefaultValue

* Add default parse_mode everywhere

* Renome to default_parse_mode

* Test def parse_mode for send_*, edit_message_*

* Remove duplicate code in Input* classes

* Improve handling of def_p_m for Bot methods

* Remove unneeded deletion of kwargs

* Make @log preserve signature, add bots with defaults to tests

* Fix Codacy

* Fix Travis Error

* Add default_disable_notification

* Add default_disable_web_page_preview

* Add default_disable_timeout

* add default_disable_web_page_preview for InputTextMessageContent

* add default_quote

* Try fixing test_pin_and_unpin

* Just run 3.5 tests for paranoia

* add tests for Defaults

* Revert "Just run 3.5 tests for paranoia"

This reverts commit 1baa91a3a1.

* Tidy up parameters, move Defaults to ext

* Stage new files, because im an idiot

* remove debug prints

* change equality checks for DEFAULT_NONE

* Some last changes

* fix S&R error so that tests actually run

Co-authored-by: Ak4zh <agwl.akash@gmail.com>
Co-authored-by: Eldinnie <Eldinnie@users.noreply.github.com>

* Skip test relying on ordered dicts for 3.5 (#1752)

* Rename Test suite

* Actually change the badge in readme

Co-authored-by: Gabriel Simonetto <42247511+GabrielSimonetto@users.noreply.github.com>
Co-authored-by: Ak4zh <agwl.akash@gmail.com>
Co-authored-by: Eldinnie <Eldinnie@users.noreply.github.com>
2020-02-06 11:38:21 +01:00
Bibo-Joshi bf06fa2c18 Skip test relying on ordered dicts for 3.5 (#1752) 2020-02-06 11:28:27 +01:00
Bibo-Joshi 960c7a0c70 Add default values (#1490)
* added parse_mode parameter in Updater and in Bot class to set a default parse mode for bot

* DefaultValue

* Add default parse_mode everywhere

* Renome to default_parse_mode

* Test def parse_mode for send_*, edit_message_*

* Remove duplicate code in Input* classes

* Improve handling of def_p_m for Bot methods

* Remove unneeded deletion of kwargs

* Make @log preserve signature, add bots with defaults to tests

* Fix Codacy

* Fix Travis Error

* Add default_disable_notification

* Add default_disable_web_page_preview

* Add default_disable_timeout

* add default_disable_web_page_preview for InputTextMessageContent

* add default_quote

* Try fixing test_pin_and_unpin

* Just run 3.5 tests for paranoia

* add tests for Defaults

* Revert "Just run 3.5 tests for paranoia"

This reverts commit 1baa91a3a1.

* Tidy up parameters, move Defaults to ext

* Stage new files, because im an idiot

* remove debug prints

* change equality checks for DEFAULT_NONE

* Some last changes

* fix S&R error so that tests actually run

Co-authored-by: Ak4zh <agwl.akash@gmail.com>
Co-authored-by: Eldinnie <Eldinnie@users.noreply.github.com>
2020-02-06 11:22:56 +01:00
Gabriel Simonetto bacabbe767 fix download without path arguments (#1591)
* fix download without path arguments

* fix download without path arguments

* solved downloading a file without file_path or custom_path

* if no file_path, download as file_id

* Add test case

* Elaborate doc string

Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>
2020-02-06 11:21:21 +01:00
Eldinnie d8dcdeea75 fix test_pin_and_unpin_message (#1749)
Make it flaky and timeout
2020-02-02 23:39:08 +01:00
isinstance 818475bd93 Fix Server response could not be decoded using UTF-8 (#1623)
Co-authored-by: Noam Meltzer <tsnoam@gmail.com>
2020-02-03 00:12:27 +02:00
Bibo-Joshi f97ac90af7 skip test_json on TestDictPersistence on py3.5 (#1748) 2020-02-03 00:10:48 +02:00
billchenchina 90eeb40ae8 Add base_file_url support for telegram.ext.Updater (#1679)
Co-authored-by: Noam Meltzer <tsnoam@gmail.com>
2020-02-02 23:47:02 +02:00
Bibo-Joshi 6d9d11b8bd Handler persistence for nested ConversationHandlers (#1711)
* Handler persistence for nested ConversationHandlers

* Add tests for persistence w/ nested CHs
2020-02-02 22:31:56 +01:00
Bibo-Joshi f6b663f175 bot_data as global memory (V12 version of #1322) (#1325)
* Update AUTHORS.rst

* Update AUTHORS.rst

* Add bot_data to CallbackContext as global memory

* Minor fixes in docstrings

* Incorp. req. changes, Flake8 Fixes

* Persist before stop

* Fix CI errors

* Implement #1342 for bot_data

* Add check pickle_persistence_only_bot similar to #1462

* Fix test_persistence

* Try dispatching error before logging it

* Fix test

Co-authored-by: Eldinnie <Eldinnie@users.noreply.github.com>
2020-02-02 22:20:31 +01:00
Noam Meltzer 43bfebb150 Update copyright date to 2020 (#1746) 2020-02-02 23:08:54 +02:00
Jelle Besseling 743e2fce07 Add --with-upstream-urllib3 option to remove vendored version (#1725)
Co-authored-by: Noam Meltzer <tsnoam@gmail.com>
2020-02-02 22:56:25 +02:00
Shreyas Thirumalai 4c2a3d07ce Remove duplicate entries from docs. (#1739)
Fixes #1726
2020-02-02 20:35:52 +01:00
Poolitzer 423794f473 fixing message.link (#1741)
* fixing message.link

* improving if clause
2020-02-02 20:27:53 +01:00
Bibo-Joshi a397e6c3c6 Doc fixes (#1642)
* Add missing DispatcherHandlerStop to docs

* Forgot to stage new file ...

* update docstring for bot.edit_message_*

* make job callback docs context based

* Flake8

* Fix doc strings of message.reply_

* Update thumb size docs

* Add missing DispatcherHandlerStop to docs

* Forgot to stage new file ...

* update docstring for bot.edit_message_*

* make job callback docs context based

* Flake8

* Fix doc strings of message.reply_

* Update thumb size docs

* Update docs on InlineQuery.query length

* Minor doc updates

* change module to class in to_float_timestamp doc string
2020-02-02 20:20:54 +01:00
Bibo-Joshi 7cde6ca268 temporarily skip tests failing b/c missing api 4.5 (#1738) 2020-01-30 20:57:16 +02:00
Bibo-Joshi 408062dd43 Add note on how to run test_official to contrib guide (#1740) 2020-01-29 22:43:57 +02:00
Poolitzer d96d233dc5 dropping 2.7, 3.3, 3.4 support from setup.py and README.rst (#1734)
Fixes #1720
2020-01-26 23:47:52 +02:00
Bibo-Joshi 3eb2cef600 Make Filters.text accept leading slash (#1680)
Fixes #1678
2020-01-26 23:19:38 +02:00
Poolitzer 0b87f4b274 contibuting guide: warning about adding requirements (#1718) 2020-01-26 23:15:42 +02:00
Bibo-Joshi 0df526d390 jobqueue: Log datetimes correctly (minor change) (#1714) 2020-01-26 23:08:33 +02:00
Bibo-Joshi cb9af36937 Fix None check in JobQueue._put() (#1707)
fixes #1701
2020-01-26 23:07:17 +02:00
Poolitzer fbb7e0e645 No more unitests for py2.7 (#1731)
Still not removing any py2.7 specific code, but no reason to waste precious CPU and unitest time on py2.7.
2020-01-26 23:01:29 +02:00
Eana Hufwe d9d65cc2ac Add poll messages support to filters (#1673) 2020-01-26 22:57:48 +02:00
Bibo-Joshi 62f514f068 CallbackContext: Expose dispatcher as a property (#1684)
Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com>
2020-01-26 22:55:00 +02:00
David Auer 08bbeca8ec Fix typo in example text (#1703) 2020-01-26 22:35:34 +02:00
Mayur Newase 38b9f4b9bc Dispatcher.__init__: Remove double assignmed to self.job_queue (#1698)
Co-authored-by: mayur741 <mayur@wipadika.com>
2020-01-26 22:34:25 +02:00
Viktor Oreshkin 3d59b2f581 Docstring fix: thumb limits were changed with Bot API 4.2 (#1669) 2020-01-26 22:30:26 +02:00
rizlas e3c8466e41 Rename enocde_conversations_to_json() -> enocde_conversations_to_json() (#1661)
Fixes #1660
2020-01-26 22:24:00 +02:00
compSciKai 1d92f52c6a Minor documentation fix (#1647) 2020-01-26 22:19:59 +02:00
Bibo-Joshi 33280a7fe0 Add missing name for Filters.update classes (#1632) 2020-01-26 22:18:29 +02:00
Poolitzer 4b5ba15d31 both google python style links have been moved (#1624)
I choose https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html, based on https://web.archive.org/web/20160322212330/http://www.sphinx-doc.org/en/stable/ext/example_google.html
and http://google.github.io/styleguide/pyguide.html based on https://web.archive.org/web/20160304111857/https://google.github.io/styleguide/pyguide.html
2020-01-26 22:16:19 +02:00
Poolitzer d2466f1e6e CI: Fix running on master after push + official can fail (#1716)
allowing official to fail is only temporary until we'll add the latest bot api support
2020-01-26 22:07:24 +02:00
Bibo-Joshi 883c6b5901 Add dispatcher argument to Updater (#1484) 2020-01-26 21:59:47 +02:00
243 changed files with 2536 additions and 734 deletions
+12 -2
View File
@@ -43,6 +43,8 @@ If you have an idea for something to do, first check if it's already been filed
Another great way to start contributing is by writing tests. Tests are really important because they help prevent developers from accidentally breaking existing code, allowing them to build cool things faster. If you're interested in helping out, let the development team know by posting to the `developers' mailing list`_, and we'll help you get started.
That being said, we want to mention that we are very hesistant about adding new requirements to our projects. If you intend to do this, please state this in an issue and get a verification from one of the maintainers.
Instructions for making a code change
#####################################
@@ -111,6 +113,14 @@ Here's how to make a one-off code change.
$ pytest -v
To run ``test_official`` (particularly useful if you made API changes), run
.. code-block::
$ export TEST_OFFICIAL=True
prior to running the tests.
- To actually make the commit (this will trigger tests for yapf, lint and pep8 automatically):
.. code-block:: bash
@@ -238,6 +248,6 @@ break the API classes. For example:
.. _`developers' mailing list`: mailto:devs@python-telegram-bot.org
.. _`PEP 8 Style Guide`: https://www.python.org/dev/peps/pep-0008/
.. _`sphinx`: http://sphinx-doc.org
.. _`Google Python Style Guide`: https://google-styleguide.googlecode.com/svn/trunk/pyguide.html
.. _`Google Python Style Docstrings`: http://sphinx-doc.org/latest/ext/example_google.html
.. _`Google Python Style Guide`: http://google.github.io/styleguide/pyguide.html
.. _`Google Python Style Docstrings`: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
.. _AUTHORS.rst: ../AUTHORS.rst
+6 -2
View File
@@ -1,10 +1,13 @@
name: Testing your PR
name: GitHub Actions
on:
pull_request:
branches:
- master
schedule:
- cron: 7 3 * * *
push:
branches:
- master
jobs:
pytest:
@@ -12,7 +15,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: [2.7, 3.5, 3.6, 3.7]
python-version: [3.5, 3.6, 3.7]
os: [ubuntu-latest, windows-latest]
include:
- os: ubuntu-latest
@@ -87,6 +90,7 @@ jobs:
run: |
pytest -v tests/test_official.py
exit $?
continue-on-error: True
env:
TEST_OFFICIAL: "true"
shell: bash --noprofile --norc {0}
+3
View File
@@ -26,6 +26,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `d-qoi <https://github.com/d-qoi>`_
- `daimajia <https://github.com/daimajia>`_
- `Daniel Reed <https://github.com/nmlorg>`_
- `Eana Hufwe <https://github.com/blueset>`_
- `Ehsan Online <https://github.com/ehsanonline>`_
- `Eli Gao <https://github.com/eligao>`_
- `Emilio Molinari <https://github.com/xates>`_
@@ -67,6 +68,8 @@ The following wonderful people contributed directly or indirectly to this projec
- `Pieter Schutz <https://github.com/eldinnie>`_
- `Poolitzer <https://github.com/Poolitzer>`_
- `Rahiel Kasim <https://github.com/rahiel>`_
- `Riko Naka <https://github.com/rikonaka>`_
- `Rizlas <https://github.com/rizlas>`_
- `Sahil Sharma <https://github.com/sahilsharma811>`_
- `Sascha <https://github.com/saschalalala>`_
- `Shelomentsev D <https://github.com/shelomentsevd>`_
+93 -2
View File
@@ -2,6 +2,97 @@
Changelog
=========
Version 12.4.2
==============
*Released 2020-02-10*
**Bug Fixes**
- Pass correct parse_mode to InlineResults if bot.defaults is None (`#1763`_)
- Make sure PP can read files that dont have bot_data (`#1760`_)
.. _`#1763`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1763
.. _`#1760`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1760
Version 12.4.1
==============
*Released 2020-02-08*
This is a quick release for `#1744`_ which was accidently left out of v12.4.0 though mentioned in the
release notes.
Version 12.4.0
==============
*Released 2020-02-08*
**New features:**
- Set default values for arguments appearing repeatedly. We also have a `wiki page for the new defaults`_. (`#1490`_)
- Store data in ``CallbackContext.bot_data`` to access it in every callback. Also persists. (`#1325`_)
- ``Filters.poll`` allows only messages containing a poll (`#1673`_)
**Major changes:**
- ``Filters.text`` now accepts messages that start with a slash, because ``CommandHandler`` checks for ``MessageEntity.BOT_COMMAND`` since v12. This might lead to your MessageHandlers receiving more updates than before (`#1680`_).
- ``Filters.command`` new checks for ``MessageEntity.BOT_COMMAND`` instead of just a leading slash. Also by ``Filters.command(False)`` you can now filters for messages containing a command `anywhere` in the text (`#1744`_).
**Minor changes, CI improvements or bug fixes:**
- Add ``disptacher`` argument to ``Updater`` to allow passing a customized ``Dispatcher`` (`#1484`_)
- Add missing names for ``Filters`` (`#1632`_)
- Documentation fixes (`#1624`_, `#1647`_, `#1669`_, `#1703`_, `#1718`_, `#1734`_, `#1740`_, `#1642`_, `#1739`_, `#1746`_)
- CI improvements (`#1716`_, `#1731`_, `#1738`_, `#1748`_, `#1749`_, `#1750`_, `#1752`_)
- Fix spelling issue for ``encode_conversations_to_json`` (`#1661`_)
- Remove double assignement of ``Dispatcher.job_queue`` (`#1698`_)
- Expose dispatcher as property for ``CallbackContext`` (`#1684`_)
- Fix ``None`` check in ``JobQueue._put()`` (`#1707`_)
- Log datetimes correctly in ``JobQueue`` (`#1714`_)
- Fix false ``Message.link`` creation for private groups (`#1741`_)
- Add option ``--with-upstream-urllib3`` to `setup.py` to allow using non-vendored version (`#1725`_)
- Fix persistence for nested ``ConversationHandlers`` (`#1679`_)
- Improve handling of non-decodable server responses (`#1623`_)
- Fix download for files without ``file_path`` (`#1591`_)
- test_webhook_invalid_posts is now considered flaky and retried on failure (`#1758`_)
.. _`wiki page for the new defaults`: https://github.com/python-telegram-bot/python-telegram-bot/wiki/Adding-defaults-to-your-bot
.. _`#1744`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1744
.. _`#1752`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1752
.. _`#1750`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1750
.. _`#1591`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1591
.. _`#1490`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1490
.. _`#1749`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1749
.. _`#1623`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1623
.. _`#1748`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1748
.. _`#1679`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1679
.. _`#1711`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1711
.. _`#1325`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1325
.. _`#1746`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1746
.. _`#1725`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1725
.. _`#1739`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1739
.. _`#1741`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1741
.. _`#1642`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1642
.. _`#1738`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1738
.. _`#1740`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1740
.. _`#1734`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1734
.. _`#1680`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1680
.. _`#1718`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1718
.. _`#1714`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1714
.. _`#1707`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1707
.. _`#1731`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1731
.. _`#1673`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1673
.. _`#1684`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1684
.. _`#1703`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1703
.. _`#1698`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1698
.. _`#1669`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1669
.. _`#1661`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1661
.. _`#1647`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1647
.. _`#1632`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1632
.. _`#1624`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1624
.. _`#1716`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1716
.. _`#1484`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1484
.. _`#1758`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1484
Version 12.3.0
==============
*Released 2020-01-11*
@@ -15,7 +106,7 @@ Version 12.3.0
- Fix inconsistent handling of naive datetimes (`#1506`_).
**Minor changes, CI improvments or bug fixes:**
**Minor changes, CI improvements or bug fixes:**
- Documentation fixes (`#1558`_, `#1569`_, `#1579`_, `#1572`_, `#1566`_, `#1577`_, `#1656`_).
- Add mutex protection on `ConversationHandler` (`#1533`_).
@@ -27,7 +118,7 @@ Version 12.3.0
- Allow private groups for `Message.link` (`#1619`_).
- Fix wrong signature call for `ConversationHandler.TIMEOUT` handlers (`#1653`_).
.. _`#1631`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1558
.. _`#1631`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1631
.. _`#1506`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1506
.. _`#1558`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1558
.. _`#1569`: https://github.com/python-telegram-bot/python-telegram-bot/pull/1569
+5 -5
View File
@@ -29,7 +29,7 @@ We have a vibrant community of developers helping each other in our `Telegram gr
:target: https://www.gnu.org/licenses/lgpl-3.0.html
:alt: LGPLv3 License
.. image:: https://github.com/python-telegram-bot/python-telegram-bot/workflows/Testing%20your%20PR/badge.svg?event=schedule
.. image:: https://github.com/python-telegram-bot/python-telegram-bot/workflows/GitHub%20Actions/badge.svg?event=schedule
:target: https://github.com/python-telegram-bot/python-telegram-bot/
:alt: Github Actions workflow
@@ -83,7 +83,7 @@ Introduction
This library provides a pure Python interface for the
`Telegram Bot API <https://core.telegram.org/bots/api>`_.
It's compatible with Python versions 2.7, 3.3+ and `PyPy <http://pypy.org/>`_.
It's compatible with Python versions 3.5+ and `PyPy <http://pypy.org/>`_.
In addition to the pure API implementation, this library features a number of high-level classes to
make the development of bots easy and straightforward. These classes are contained in the
@@ -137,9 +137,9 @@ Other references:
Learning by example
-------------------
We believe that the best way to learn and understand this simple package is by example. So here
are some examples for you to review. Even if it's not your approach for learning, please take a
look at ``echobot2``, it is de facto the base for most of the bots out there. Best of all,
We believe that the best way to learn this package is by example. Here
are some examples for you to review. Even if it is not your approach for learning, please take a
look at ``echobot2``, it is the de facto base for most of the bots out there. Best of all,
the code for these examples are released to the public domain, so you can start by grabbing the
code and building on top of it.
+3 -3
View File
@@ -50,7 +50,7 @@ master_doc = 'index'
# General information about the project.
project = u'Python Telegram Bot'
copyright = u'2015-2018, Leandro Toledo'
copyright = u'2015-2020, Leandro Toledo'
author = u'Leandro Toledo'
# The version info for the project you're documenting, acts as replacement for
@@ -58,9 +58,9 @@ author = u'Leandro Toledo'
# built documents.
#
# The short X.Y version.
version = '12.3' # telegram.__version__[:3]
version = '12.4' # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = '12.3.0' # telegram.__version__
release = '12.4.2' # telegram.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+6
View File
@@ -0,0 +1,6 @@
telegram.ext.Defaults
=====================
.. autoclass:: telegram.ext.Defaults
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
telegram.ext.DispatcherHandlerStop
==================================
.. autoclass:: telegram.ext.DispatcherHandlerStop
:members:
:show-inheritance:
+2
View File
@@ -5,12 +5,14 @@ telegram.ext package
telegram.ext.updater
telegram.ext.dispatcher
telegram.ext.dispatcherhandlerstop
telegram.ext.filters
telegram.ext.job
telegram.ext.jobqueue
telegram.ext.messagequeue
telegram.ext.delayqueue
telegram.ext.callbackcontext
telegram.ext.defaults
Handlers
--------
+1 -1
View File
@@ -47,7 +47,7 @@ def start(update, context):
reply_text = "Hi! My name is Doctor Botter."
if context.user_data:
reply_text += " You already told me your {}. Why don't you tell me something more " \
"about yourself? Or change enything I " \
"about yourself? Or change anything I " \
"already know.".format(", ".join(context.user_data.keys()))
else:
reply_text += " I will hold a more complex conversation with you. Why don't you tell me " \
+1
View File
@@ -2,3 +2,4 @@ future>=0.16.0
certifi
tornado>=5.1
cryptography
decorator>=4.4.0
+11 -4
View File
@@ -3,6 +3,8 @@
import codecs
import os
import sys
from setuptools import setup, find_packages
@@ -18,6 +20,14 @@ def requirements():
packages = find_packages(exclude=['tests*'])
requirements = requirements()
# Allow for a package install to not use the vendored urllib3
UPSTREAM_URLLIB3_FLAG = '--with-upstream-urllib3'
if UPSTREAM_URLLIB3_FLAG in sys.argv:
sys.argv.remove(UPSTREAM_URLLIB3_FLAG)
requirements.append('urllib3 >= 1.19.1')
packages = [x for x in packages if not x.startswith('telegram.vendor.ptb_urllib3')]
with codecs.open('README.rst', 'r', 'utf-8') as fd:
fn = os.path.join('telegram', 'version.py')
@@ -35,7 +45,7 @@ with codecs.open('README.rst', 'r', 'utf-8') as fd:
description="We have made you a wrapper you can't refuse",
long_description=fd.read(),
packages=packages,
install_requires=requirements(),
install_requires=requirements,
extras_require={
'json': 'ujson',
'socks': 'PySocks'
@@ -50,10 +60,7 @@ with codecs.open('README.rst', 'r', 'utf-8') as fd:
'Topic :: Communications :: Chat',
'Topic :: Internet',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7'
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
# !/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+152 -55
View File
@@ -3,7 +3,7 @@
# pylint: disable=E0611,E0213,E1102,C0103,E1101,W0613,R0913,R0904
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -21,6 +21,8 @@
"""This module contains an object that represents a Telegram Bot."""
import functools
import inspect
from decorator import decorate
try:
import ujson as json
@@ -39,7 +41,7 @@ from telegram import (User, Message, Update, Chat, ChatMember, UserProfilePhotos
PhotoSize, Audio, Document, Sticker, Video, Animation, Voice, VideoNote,
Location, Venue, Contact, InputFile, Poll)
from telegram.error import InvalidToken, TelegramError
from telegram.utils.helpers import to_timestamp
from telegram.utils.helpers import to_timestamp, DEFAULT_NONE
from telegram.utils.request import Request
logging.getLogger(__name__).addHandler(logging.NullHandler())
@@ -57,18 +59,17 @@ def info(func):
return decorator
def log(func):
def log(func, *args, **kwargs):
logger = logging.getLogger(func.__module__)
@functools.wraps(func)
def decorator(self, *args, **kwargs):
logger.debug('Entering: %s', func.__name__)
result = func(self, *args, **kwargs)
result = func(*args, **kwargs)
logger.debug(result)
logger.debug('Exiting: %s', func.__name__)
return result
return decorator
return decorate(func, decorator)
class Bot(TelegramObject):
@@ -82,13 +83,55 @@ class Bot(TelegramObject):
:obj:`telegram.utils.request.Request`.
private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data.
private_key_password (:obj:`bytes`, optional): Password for above private key.
defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to
be used if not set explicitly in the bot methods.
"""
def __init__(self, token, base_url=None, base_file_url=None, request=None, private_key=None,
private_key_password=None):
def __new__(cls, *args, **kwargs):
# Get default values from kwargs
defaults = kwargs.get('defaults')
# Make an instance of the class
instance = super(Bot, cls).__new__(cls)
if not defaults:
return instance
# For each method ...
for method_name, method in inspect.getmembers(instance, predicate=inspect.ismethod):
# ... get kwargs
argspec = inspect.getargspec(method)
kwarg_names = argspec.args[-len(argspec.defaults or []):]
# ... check if Defaults has a attribute that matches the kwarg name
needs_default = [
kwarg_name for kwarg_name in kwarg_names if hasattr(defaults, kwarg_name)
]
# ... make a dict of kwarg name and the default value
default_kwargs = {
kwarg_name: getattr(defaults, kwarg_name) for kwarg_name in needs_default if (
getattr(defaults, kwarg_name) is not DEFAULT_NONE
)
}
# ... apply the defaults using a partial
if default_kwargs:
setattr(instance, method_name, functools.partial(method, **default_kwargs))
return instance
def __init__(self,
token,
base_url=None,
base_file_url=None,
request=None,
private_key=None,
private_key_password=None,
defaults=None):
self.token = self._validate_token(token)
# Gather default
self.defaults = defaults
if base_url is None:
base_url = 'https://api.telegram.org/bot'
@@ -120,11 +163,20 @@ class Bot(TelegramObject):
else:
data['reply_markup'] = reply_markup
if data.get('media') and (data['media'].parse_mode == DEFAULT_NONE):
if self.defaults:
data['media'].parse_mode = self.defaults.parse_mode
else:
data['media'].parse_mode = None
result = self._request.post(url, data, timeout=timeout)
if result is True:
return result
if self.defaults:
result['default_quote'] = self.defaults.quote
return Message.de_json(result, self)
@property
@@ -457,7 +509,7 @@ class Bot(TelegramObject):
to remove reply keyboard or to force a reply from the user.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds).
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
@@ -540,7 +592,7 @@ class Bot(TelegramObject):
to remove reply keyboard or to force a reply from the user.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds).
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
@@ -678,7 +730,7 @@ class Bot(TelegramObject):
to remove reply keyboard or to force a reply from the user.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds).
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
@@ -757,7 +809,7 @@ class Bot(TelegramObject):
instructions to remove reply keyboard or to force a reply from the user.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds).
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
@@ -822,7 +874,7 @@ class Bot(TelegramObject):
height (:obj:`int`, optional): Animation height.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
caption (:obj:`str`, optional): Animation caption (may also be used when resending
animations by file_id), 0-1024 characters.
@@ -978,6 +1030,13 @@ class Bot(TelegramObject):
data = {'chat_id': chat_id, 'media': media}
for m in data['media']:
if m.parse_mode == DEFAULT_NONE:
if self.defaults:
m.parse_mode = self.defaults.parse_mode
else:
m.parse_mode = None
if reply_to_message_id:
data['reply_to_message_id'] = reply_to_message_id
if disable_notification:
@@ -985,6 +1044,10 @@ class Bot(TelegramObject):
result = self._request.post(url, data, timeout=timeout)
if self.defaults:
for res in result:
res['default_quote'] = self.defaults.quote
return [Message.de_json(res, self) for res in result]
@log
@@ -1073,8 +1136,9 @@ class Bot(TelegramObject):
You can either supply a :obj:`latitude` and :obj:`longitude` or a :obj:`location`.
Args:
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
of the target channel (in the format @channelusername).
chat_id (:obj:`int` | :obj:`str`, optional): 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 (:obj:`int`, optional): Required if inline_message_id is not specified.
Identifier of the sent message.
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
@@ -1082,9 +1146,8 @@ class Bot(TelegramObject):
latitude (:obj:`float`, optional): Latitude of location.
longitude (:obj:`float`, optional): Longitude of location.
location (:class:`telegram.Location`, optional): The location to send.
reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized
object for an inline keyboard.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
@@ -1447,6 +1510,27 @@ class Bot(TelegramObject):
"""
url = '{0}/answerInlineQuery'.format(self.base_url)
for res in results:
if res._has_parse_mode and res.parse_mode == DEFAULT_NONE:
if self.defaults:
res.parse_mode = self.defaults.parse_mode
else:
res.parse_mode = None
if res._has_input_message_content and res.input_message_content:
if (res.input_message_content._has_parse_mode
and res.input_message_content.parse_mode == DEFAULT_NONE):
if self.defaults:
res.input_message_content.parse_mode = self.defaults.parse_mode
else:
res.input_message_content.parse_mode = None
if (res.input_message_content._has_disable_web_page_preview
and res.input_message_content.disable_web_page_preview == DEFAULT_NONE):
if self.defaults:
res.input_message_content.disable_web_page_preview = \
self.defaults.disable_web_page_preview
else:
res.input_message_content.disable_web_page_preview = None
results = [res.to_dict() for res in results]
data = {'inline_query_id': inline_query_id, 'results': results}
@@ -1704,21 +1788,21 @@ class Bot(TelegramObject):
bots).
Args:
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
of the target channel (in the format @channelusername).
chat_id (:obj:`int` | :obj:`str`, optional): 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 (:obj:`int`, optional): Required if inline_message_id is not specified.
Identifier of the sent message.
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
specified. Identifier of the inline message.
text (:obj:`str`): New text of the message.
parse_mode (:obj:`str`): Send Markdown or HTML, if you want Telegram apps to show bold,
italic, fixed-width text or inline URLs in your bot's message. See the constants in
:class:`telegram.ParseMode` for the available modes.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
show bold, italic, fixed-width text or inline URLs in your bot's message. See the
constants in :class:`telegram.ParseMode` for the available modes.
disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in
this message.
reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized
object for an inline keyboard.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
@@ -1764,8 +1848,9 @@ class Bot(TelegramObject):
(for inline bots).
Args:
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
of the target channel (in the format @channelusername).
chat_id (:obj:`int` | :obj:`str`, optional): 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 (:obj:`int`, optional): Required if inline_message_id is not specified.
Identifier of the sent message.
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
@@ -1774,9 +1859,8 @@ class Bot(TelegramObject):
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to
show bold, italic, fixed-width text or inline URLs in the media caption. See the
constants in :class:`telegram.ParseMode` for the available modes.
reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized
object for an inline keyboard.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
@@ -1829,17 +1913,17 @@ class Bot(TelegramObject):
returned.
Args:
chat_id (:obj:`int` | :obj:`str`, optional): Unique identifier for the target chat or
username of the target channel (in the format @channelusername).
chat_id (:obj:`int` | :obj:`str`, optional): 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 (:obj:`int`, optional): Required if inline_message_id is not specified.
Identifier of the sent message.
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
specified. Identifier of the inline message.
media (:class:`telegram.InputMedia`): An object for a new media content
of the message.
reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized
object for an inline keyboard.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
@@ -1877,15 +1961,15 @@ class Bot(TelegramObject):
(for inline bots).
Args:
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
of the target channel (in the format @channelusername).
chat_id (:obj:`int` | :obj:`str`, optional): 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 (:obj:`int`, optional): Required if inline_message_id is not specified.
Identifier of the sent message.
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
specified. Identifier of the inline message.
reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
to remove reply keyboard or to force a reply from the user.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized
object for an inline keyboard.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
@@ -1940,10 +2024,10 @@ class Bot(TelegramObject):
timeout (:obj:`int`, optional): Timeout in seconds for long polling. Defaults to 0,
i.e. usual short polling. Should be positive, short polling should be used for
testing purposes only.
allowed_updates (List[:obj:`str`]), optional): List the types of updates you want your
bot to receive. For example, specify ["message", "edited_channel_post",
"callback_query"] to only receive updates of these types. See
:class:`telegram.Update` for a complete list of available update types.
allowed_updates (List[:obj:`str`]), optional): A JSON-serialized list the types of
updates you want your bot to receive. For example, specify ["message",
"edited_channel_post", "callback_query"] to only receive updates of these types.
See :class:`telegram.Update` for a complete list of available update types.
Specify an empty list to receive all updates regardless of type (default). If not
specified, the previous setting will be used. Please note that this parameter
doesn't affect updates created before the call to the get_updates, so unwanted
@@ -1987,6 +2071,10 @@ class Bot(TelegramObject):
else:
self.logger.debug('No new updates found.')
if self.defaults:
for u in result:
u['default_quote'] = self.defaults.quote
return [Update.de_json(u, self) for u in result]
@log
@@ -2020,14 +2108,14 @@ class Bot(TelegramObject):
connections to the webhook for update delivery, 1-100. Defaults to 40. Use lower
values to limit the load on your bot's server, and higher values to increase your
bot's throughput.
allowed_updates (List[:obj:`str`], optional): List the types of updates you want your
bot to receive. For example, specify ["message", "edited_channel_post",
"callback_query"] to only receive updates of these types. See
:class:`telegram.Update` for a complete list of available update types. Specify an
empty list to receive all updates regardless of type (default). If not specified,
the previous setting will be used. Please note that this parameter doesn't affect
updates created before the call to the set_webhook, so unwanted updates may be
received for a short period of time.
allowed_updates (List[:obj:`str`], optional): A JSON-serialized list the types of
updates you want your bot to receive. For example, specify ["message",
"edited_channel_post", "callback_query"] to only receive updates of these types.
See :class:`telegram.Update` for a complete list of available update types.
Specify an empty list to receive all updates regardless of type (default). If not
specified, the previous setting will be used. Please note that this parameter
doesn't affect updates created before the call to the set_webhook, so unwanted
updates may be received for a short period of time.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
@@ -2041,12 +2129,17 @@ class Bot(TelegramObject):
work.
3. Ports currently supported for Webhooks: 443, 80, 88, 8443.
If you're having any trouble setting up webhooks, please check out this `guide to
Webhooks`_.
Returns:
:obj:`bool` On success, ``True`` is returned.
Raises:
:class:`telegram.TelegramError`
.. _`guide to Webhooks`: https://core.telegram.org/bots/webhooks
"""
url_ = '{0}/setWebhook'.format(self.base_url)
@@ -2162,6 +2255,9 @@ class Bot(TelegramObject):
result = self._request.post(url, data, timeout=timeout)
if self.defaults:
result['default_quote'] = self.defaults.quote
return Chat.de_json(result, self)
@log
@@ -2481,8 +2577,9 @@ class Bot(TelegramObject):
start_parameter (:obj:`str`): Unique deep-linking parameter that can be used to
generate this invoice when used as a start parameter.
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.).
prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a JSON-serialized 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
+5 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -101,7 +101,10 @@ class CallbackQuery(TelegramObject):
data = super(CallbackQuery, cls).de_json(data, bot)
data['from_user'] = User.de_json(data.get('from'), bot)
data['message'] = Message.de_json(data.get('message'), bot)
message = data.get('message')
if message:
message['default_quote'] = data.get('default_quote')
data['message'] = Message.de_json(message, bot)
return cls(bot=bot, **data)
+5 -2
View File
@@ -2,7 +2,7 @@
# pylint: disable=C0103,W0622
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -135,7 +135,10 @@ class Chat(TelegramObject):
data['photo'] = ChatPhoto.de_json(data.get('photo'), bot)
from telegram import Message
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)
pinned_message = data.get('pinned_message')
if pinned_message:
pinned_message['default_quote'] = data.get('default_quote')
data['pinned_message'] = Message.de_json(pinned_message, bot)
data['permissions'] = ChatPermissions.de_json(data.get('permissions'), bot)
return cls(bot=bot, **data)
+1 -1
View File
@@ -2,7 +2,7 @@
# pylint: disable=R0903
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -2,7 +2,7 @@
# pylint: disable=R0902,R0912,R0913
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,5 +1,5 @@
# python-telegram-bot - a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# by the python-telegram-bot contributors <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+3 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -41,6 +41,7 @@ from .precheckoutqueryhandler import PreCheckoutQueryHandler
from .shippingqueryhandler import ShippingQueryHandler
from .messagequeue import MessageQueue
from .messagequeue import DelayQueue
from .defaults import Defaults
__all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
'ChosenInlineResultHandler', 'CommandHandler', 'Handler', 'InlineQueryHandler',
@@ -48,4 +49,4 @@ __all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
'StringRegexHandler', 'TypeHandler', 'ConversationHandler',
'PreCheckoutQueryHandler', 'ShippingQueryHandler', 'MessageQueue', 'DelayQueue',
'DispatcherHandlerStop', 'run_async', 'CallbackContext', 'BasePersistence',
'PicklePersistence', 'DictPersistence', 'PrefixHandler')
'PicklePersistence', 'DictPersistence', 'PrefixHandler', 'Defaults')
+29 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -25,6 +25,8 @@ class BasePersistence(object):
All relevant methods must be overwritten. This means:
* If :attr:`store_bot_data` is ``True`` you must overwrite :meth:`get_bot_data` and
:meth:`update_bot_data`.
* If :attr:`store_chat_data` is ``True`` you must overwrite :meth:`get_chat_data` and
:meth:`update_chat_data`.
* If :attr:`store_user_data` is ``True`` you must overwrite :meth:`get_user_data` and
@@ -38,17 +40,22 @@ class BasePersistence(object):
persistence class.
store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this
persistence class.
store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this
persistence class.
Args:
store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this
persistence class. Default is ``True``.
store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this
persistence class. Default is ``True`` .
store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this
persistence class. Default is ``True`` .
"""
def __init__(self, store_user_data=True, store_chat_data=True):
def __init__(self, store_user_data=True, store_chat_data=True, store_bot_data=True):
self.store_user_data = store_user_data
self.store_chat_data = store_chat_data
self.store_bot_data = store_bot_data
def get_user_data(self):
""""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
@@ -70,6 +77,16 @@ class BasePersistence(object):
"""
raise NotImplementedError
def get_bot_data(self):
""""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
persistence object. It should return the bot_data if stored, or an empty
``dict``.
Returns:
:obj:`defaultdict`: The restored bot data.
"""
raise NotImplementedError
def get_conversations(self, name):
""""Will be called by :class:`telegram.ext.Dispatcher` when a
:class:`telegram.ext.ConversationHandler` is added if
@@ -111,7 +128,16 @@ class BasePersistence(object):
Args:
chat_id (:obj:`int`): The chat the data might have been changed for.
data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` [user_id].
data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` [chat_id].
"""
raise NotImplementedError
def update_bot_data(self, data):
"""Will be called by the :class:`telegram.ext.Dispatcher` after a handler has
handled an update.
Args:
data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data` .
"""
raise NotImplementedError
+27 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -43,8 +43,17 @@ class CallbackContext(object):
that you think you added will not be present.
Attributes:
bot_data (:obj:`dict`, optional): A dict that can be used to keep any data in. For each
update it will be the same ``dict``.
chat_data (:obj:`dict`, optional): A dict that can be used to keep any data in. For each
update from the same chat it will be the same ``dict``.
update from the same chat id it will be the same ``dict``.
Warning:
When a group chat migrates to a supergroup, its chat id will change and the
``chat_data`` needs to be transferred. For details see our `wiki page
<https://github.com/python-telegram-bot/python-telegram-bot/wiki/
Storing-user--and-chat-related-data#chat-migration>`_.
user_data (:obj:`dict`, optional): A dict that can be used to keep any data in. For each
update from the same user it will be the same ``dict``.
matches (List[:obj:`re match object`], optional): If the associated update originated from
@@ -73,6 +82,7 @@ class CallbackContext(object):
raise ValueError('CallbackContext should not be used with a non context aware '
'dispatcher!')
self._dispatcher = dispatcher
self._bot_data = dispatcher.bot_data
self._chat_data = None
self._user_data = None
self.args = None
@@ -80,6 +90,20 @@ class CallbackContext(object):
self.error = None
self.job = None
@property
def dispatcher(self):
""":class:`telegram.ext.Dispatcher`: The dispatcher associated with this context."""
return self._dispatcher
@property
def bot_data(self):
return self._bot_data
@bot_data.setter
def bot_data(self, value):
raise AttributeError("You can not assign a new value to bot_data, see "
"https://git.io/fjxKe")
@property
def chat_data(self):
return self._chat_data
@@ -107,6 +131,7 @@ class CallbackContext(object):
@classmethod
def from_update(cls, update, dispatcher):
self = cls(dispatcher)
if update is not None and isinstance(update, Update):
chat = update.effective_chat
user = update.effective_user
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+29 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -178,14 +178,14 @@ class ConversationHandler(Handler):
if persistent and not self.name:
raise ValueError("Conversations can't be persistent when handler is unnamed.")
self.persistent = persistent
self.persistence = None
self._persistence = None
""":obj:`telegram.ext.BasePersistance`: The persistence used to store conversations.
Set by dispatcher"""
self.map_to_parent = map_to_parent
self.timeout_jobs = dict()
self._timeout_jobs_lock = Lock()
self.conversations = dict()
self._conversations = dict()
self._conversations_lock = Lock()
self.logger = logging.getLogger(__name__)
@@ -225,6 +225,32 @@ class ConversationHandler(Handler):
"since inline queries have no chat context.")
break
@property
def persistence(self):
return self._persistence
@persistence.setter
def persistence(self, persistence):
self._persistence = persistence
# Set persistence for nested conversations
for handlers in self.states.values():
for handler in handlers:
if isinstance(handler, ConversationHandler):
handler.persistence = self.persistence
@property
def conversations(self):
return self._conversations
@conversations.setter
def conversations(self, value):
self._conversations = value
# Set conversations for nested conversations
for handlers in self.states.values():
for handler in handlers:
if isinstance(handler, ConversationHandler):
handler.conversations = self.persistence.get_conversations(handler.name)
def _get_key(self, update):
chat = update.effective_chat
user = update.effective_user
+127
View File
@@ -0,0 +1,127 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2020
# 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 the class Defaults, which allows to pass default values to Updater."""
from telegram.utils.helpers import DEFAULT_NONE
class Defaults:
"""Convenience Class to gather all parameters with a (user defined) default value
Attributes:
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width toxt or URLs in your bot's message.
disable_notification (:obj:`bool`): Optional. Sends the message silently. Users will
receive a notification with no sound.
disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in this
message.
timeout (:obj:`int` | :obj:`float`): Optional. If this value is specified, use it as the
read timeout from the server (instead of the one specified during creation of the
connection pool).
quote (:obj:`bool`): Optional. If set to ``True``, the reply is sent as an actual reply to
the 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.
Parameters:
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width toxt or URLs in your bot's message.
disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
receive a notification with no sound.
disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this
message.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as the
read timeout from the server (instead of the one specified during creation of the
connection pool).
quote (:obj:`bool`, opitonal): If set to ``True``, the reply is sent as an actual reply to
the 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.
"""
def __init__(self,
parse_mode=None,
disable_notification=None,
disable_web_page_preview=None,
# Timeout needs special treatment, since the bot methods have two different
# default values for timeout (None and 20s)
timeout=DEFAULT_NONE,
quote=None):
self._parse_mode = parse_mode
self._disable_notification = disable_notification
self._disable_web_page_preview = disable_web_page_preview
self._timeout = timeout
self._quote = quote
@property
def parse_mode(self):
return self._parse_mode
@parse_mode.setter
def parse_mode(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
@property
def disable_notification(self):
return self._disable_notification
@disable_notification.setter
def disable_notification(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
@property
def disable_web_page_preview(self):
return self._disable_web_page_preview
@disable_web_page_preview.setter
def disable_web_page_preview(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
@property
def timeout(self):
return self._timeout
@timeout.setter
def timeout(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
@property
def quote(self):
return self._quote
@quote.setter
def quote(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
def __hash__(self):
return hash((self._parse_mode,
self._disable_notification,
self._disable_web_page_preview,
self._timeout,
self._quote))
def __eq__(self, other):
if isinstance(other, Defaults):
return self.__dict__ == other.__dict__
return False
def __ne__(self, other):
return not self == other
+67 -8
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -20,7 +20,7 @@
from copy import deepcopy
from telegram.utils.helpers import decode_user_chat_data_from_json,\
decode_conversations_from_json, enocde_conversations_to_json
decode_conversations_from_json, encode_conversations_to_json
try:
import ujson as json
@@ -31,36 +31,51 @@ from telegram.ext import BasePersistence
class DictPersistence(BasePersistence):
"""Using python's dicts and json for making you bot persistent.
"""Using python's dicts and json for making your bot persistent.
Attributes:
store_user_data (:obj:`bool`): Whether user_data should be saved by this
persistence class.
store_chat_data (:obj:`bool`): Whether chat_data should be saved by this
persistence class.
store_bot_data (:obj:`bool`): Whether bot_data should be saved by this
persistence class.
Args:
store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this
persistence class. Default is ``True``.
store_chat_data (:obj:`bool`, optional): Whether user_data should be saved by this
persistence class. Default is ``True``.
store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this
persistence class. Default is ``True`` .
user_data_json (:obj:`str`, optional): Json string that will be used to reconstruct
user_data on creating this persistence. Default is ``""``.
chat_data_json (:obj:`str`, optional): Json string that will be used to reconstruct
chat_data on creating this persistence. Default is ``""``.
bot_data_json (:obj:`str`, optional): Json string that will be used to reconstruct
bot_data on creating this persistence. Default is ``""``.
conversations_json (:obj:`str`, optional): Json string that will be used to reconstruct
conversation on creating this persistence. Default is ``""``.
"""
def __init__(self, store_user_data=True, store_chat_data=True, user_data_json='',
chat_data_json='', conversations_json=''):
self.store_user_data = store_user_data
self.store_chat_data = store_chat_data
def __init__(self,
store_user_data=True,
store_chat_data=True,
store_bot_data=True,
user_data_json='',
chat_data_json='',
bot_data_json='',
conversations_json=''):
super(DictPersistence, self).__init__(store_user_data=store_user_data,
store_chat_data=store_chat_data,
store_bot_data=store_bot_data)
self._user_data = None
self._chat_data = None
self._bot_data = None
self._conversations = None
self._user_data_json = None
self._chat_data_json = None
self._bot_data_json = None
self._conversations_json = None
if user_data_json:
try:
@@ -74,6 +89,14 @@ class DictPersistence(BasePersistence):
self._chat_data_json = chat_data_json
except (ValueError, AttributeError):
raise TypeError("Unable to deserialize chat_data_json. Not valid JSON")
if bot_data_json:
try:
self._bot_data = json.loads(bot_data_json)
self._bot_data_json = bot_data_json
except (ValueError, AttributeError):
raise TypeError("Unable to deserialize bot_data_json. Not valid JSON")
if not isinstance(self._bot_data, dict):
raise TypeError("bot_data_json must be serialized dict")
if conversations_json:
try:
@@ -108,6 +131,19 @@ class DictPersistence(BasePersistence):
else:
return json.dumps(self.chat_data)
@property
def bot_data(self):
""":obj:`dict`: The bot_data as a dict"""
return self._bot_data
@property
def bot_data_json(self):
""":obj:`str`: The bot_data serialized as a JSON-string."""
if self._bot_data_json:
return self._bot_data_json
else:
return json.dumps(self.bot_data)
@property
def conversations(self):
""":obj:`dict`: The conversations as a dict"""
@@ -119,7 +155,7 @@ class DictPersistence(BasePersistence):
if self._conversations_json:
return self._conversations_json
else:
return enocde_conversations_to_json(self.conversations)
return encode_conversations_to_json(self.conversations)
def get_user_data(self):
"""Returns the user_data created from the ``user_data_json`` or an empty defaultdict.
@@ -145,6 +181,18 @@ class DictPersistence(BasePersistence):
self._chat_data = defaultdict(dict)
return deepcopy(self.chat_data)
def get_bot_data(self):
"""Returns the bot_data created from the ``bot_data_json`` or an empty dict.
Returns:
:obj:`defaultdict`: The restored user data.
"""
if self.bot_data:
pass
else:
self._bot_data = {}
return deepcopy(self.bot_data)
def get_conversations(self, name):
"""Returns the conversations created from the ``conversations_json`` or an empty
defaultdict.
@@ -194,3 +242,14 @@ class DictPersistence(BasePersistence):
return
self._chat_data[chat_id] = data
self._chat_data_json = None
def update_bot_data(self, data):
"""Will update the bot_data (if changed).
Args:
data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`.
"""
if self._bot_data == data:
return
self._bot_data = data.copy()
self._bot_data_json = None
+28 -7
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -79,6 +79,7 @@ class Dispatcher(object):
decorator.
user_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the user.
chat_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the chat.
bot_data (:obj:`dict`): A dictionary handlers can use to store data for the bot.
persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to
store data that should be persistent over restarts
@@ -121,8 +122,8 @@ class Dispatcher(object):
TelegramDeprecationWarning, stacklevel=3)
self.user_data = defaultdict(dict)
""":obj:`dict`: A dictionary handlers can use to store data for the user."""
self.chat_data = defaultdict(dict)
self.bot_data = {}
if persistence:
if not isinstance(persistence, BasePersistence):
raise TypeError("persistence should be based on telegram.ext.BasePersistence")
@@ -135,11 +136,13 @@ class Dispatcher(object):
self.chat_data = self.persistence.get_chat_data()
if not isinstance(self.chat_data, defaultdict):
raise ValueError("chat_data must be of type defaultdict")
if self.persistence.store_bot_data:
self.bot_data = self.persistence.get_bot_data()
if not isinstance(self.bot_data, dict):
raise ValueError("bot_data must be of type dict")
else:
self.persistence = None
self.job_queue = job_queue
self.handlers = {}
"""Dict[:obj:`int`, List[:class:`telegram.ext.Handler`]]: Holds the handlers per group."""
self.groups = []
@@ -162,6 +165,10 @@ class Dispatcher(object):
else:
self._set_singleton(None)
@property
def exception_event(self):
return self.__exception_event
def _init_async_threads(self, base_name, workers):
base_name = '{}_'.format(base_name) if base_name else ''
@@ -325,6 +332,17 @@ class Dispatcher(object):
"""
if self.persistence and isinstance(update, Update):
if self.persistence.store_bot_data:
try:
self.persistence.update_bot_data(self.bot_data)
except Exception as e:
try:
self.dispatch_error(update, e)
except Exception:
message = 'Saving bot data raised an error and an ' \
'uncaught error was raised while handling ' \
'the error with an error_handler'
self.logger.exception(message)
if self.persistence.store_chat_data and update.effective_chat:
chat_id = update.effective_chat.id
try:
@@ -395,7 +413,8 @@ class Dispatcher(object):
def add_handler(self, handler, group=DEFAULT_GROUP):
"""Register a handler.
TL;DR: Order and priority counts. 0 or 1 handlers per group will be used.
TL;DR: Order and priority counts. 0 or 1 handlers per group will be used. End handling of
update with :class:`telegram.ext.DispatcherHandlerStop`.
A handler must be an instance of a subclass of :class:`telegram.ext.Handler`. All handlers
are organized in groups with a numeric value. The default group is 0. All groups will be
@@ -428,8 +447,8 @@ class Dispatcher(object):
raise ValueError(
"Conversationhandler {} can not be persistent if dispatcher has no "
"persistence".format(handler.name))
handler.conversations = self.persistence.get_conversations(handler.name)
handler.persistence = self.persistence
handler.conversations = self.persistence.get_conversations(handler.name)
if group not in self.handlers:
self.handlers[group] = list()
@@ -453,9 +472,11 @@ class Dispatcher(object):
self.groups.remove(group)
def update_persistence(self):
"""Update :attr:`user_data` and :attr:`chat_data` in :attr:`persistence`.
"""Update :attr:`user_data`, :attr:`chat_data` and :attr:`bot_data` in :attr:`persistence`.
"""
if self.persistence:
if self.persistence.store_bot_data:
self.persistence.update_bot_data(self.bot_data)
if self.persistence.store_chat_data:
for chat_id in self.chat_data:
self.persistence.update_chat_data(chat_id, self.chat_data[chat_id])
+54 -46
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -22,7 +22,7 @@ import re
from future.utils import string_types
from telegram import Chat, Update
from telegram import Chat, Update, MessageEntity
__all__ = ['Filters', 'BaseFilter', 'InvertedFilter', 'MergedFilter']
@@ -243,21 +243,18 @@ class Filters(object):
self.name = 'Filters.text({})'.format(iterable)
def filter(self, message):
if message.text and not message.text.startswith('/'):
if message.text:
return message.text in self.iterable
return False
def __call__(self, update):
if isinstance(update, Update):
if self.update_filter:
return self.filter(update)
else:
return self.filter(update.effective_message)
return self.filter(update.effective_message)
else:
return self._TextIterable(update)
def filter(self, message):
return bool(message.text and not message.text.startswith('/'))
return bool(message.text)
text = _Text()
"""Text Messages. If an iterable of strings is passed, it filters messages to only allow those
@@ -296,10 +293,7 @@ class Filters(object):
def __call__(self, update):
if isinstance(update, Update):
if self.update_filter:
return self.filter(update)
else:
return self.filter(update.effective_message)
return self.filter(update.effective_message)
else:
return self._CaptionIterable(update)
@@ -321,11 +315,41 @@ class Filters(object):
class _Command(BaseFilter):
name = 'Filters.command'
class _CommandOnlyStart(BaseFilter):
def __init__(self, only_start):
self.only_start = only_start
self.name = 'Filters.command({})'.format(only_start)
def filter(self, message):
return (message.entities
and any([e.type == MessageEntity.BOT_COMMAND for e in message.entities]))
def __call__(self, update):
if isinstance(update, Update):
return self.filter(update.effective_message)
else:
return self._CommandOnlyStart(update)
def filter(self, message):
return bool(message.text and message.text.startswith('/'))
return (message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND
and message.entities[0].offset == 0)
command = _Command()
"""Messages starting with ``/``."""
"""
Messages with a :attr:`telegram.MessageEntity.BOT_COMMAND`. By default only allows
messages `starting` with a bot command. Pass ``False`` to also allow messages that contain a
bot command `anywhere` in the text.
Examples::
MessageHandler(Filters.command, command_at_start_callback)
MessageHandler(Filters.command(False), command_anywhere_callback)
Args:
update (:obj:`bool`, optional): Whether to only allow messages that `start` with a bot
command. Defaults to ``True``.
"""
class regex(BaseFilter):
"""
@@ -481,38 +505,6 @@ class Filters(object):
``Filters.document`` for all document messages.
Attributes:
category: This Filter filters documents by their category in the mime-type attribute.
Example:
``Filters.documents.category('audio/')`` filters all types
of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'. The following
attributes can be used as a shortcut like: ``Filters.document.audio``
application:
audio:
image:
video:
text:
mime_type: This Filter filters documents by their mime-type attribute.
Example:
``Filters.documents.mime_type('audio/mpeg')`` filters all audio in mp3 format. The
following attributes can be used as a shortcut like: ``Filters.document.jpg``
apk:
doc:
docx:
exe:
gif:
jpg:
mp3:
pdf:
py:
svg:
txt:
targz:
wav:
xml:
zip:
category: This Filter filters documents by their category in the mime-type attribute
Note:
@@ -956,6 +948,15 @@ officedocument.wordprocessingml.document")``-
passport_data = _PassportData()
"""Messages that contain a :class:`telegram.PassportData`"""
class _Poll(BaseFilter):
name = 'Filters.poll'
def filter(self, message):
return bool(message.poll)
poll = _Poll()
"""Messages that contain a :class:`telegram.Poll`."""
class language(BaseFilter):
"""Filters messages to only allow those which are from users with a certain language code.
@@ -987,8 +988,10 @@ officedocument.wordprocessingml.document")``-
class _UpdateType(BaseFilter):
update_filter = True
name = 'Filters.update'
class _Message(BaseFilter):
name = 'Filters.update.message'
update_filter = True
def filter(self, update):
@@ -997,6 +1000,7 @@ officedocument.wordprocessingml.document")``-
message = _Message()
class _EditedMessage(BaseFilter):
name = 'Filters.update.edited_message'
update_filter = True
def filter(self, update):
@@ -1005,6 +1009,7 @@ officedocument.wordprocessingml.document")``-
edited_message = _EditedMessage()
class _Messages(BaseFilter):
name = 'Filters.update.messages'
update_filter = True
def filter(self, update):
@@ -1013,6 +1018,7 @@ officedocument.wordprocessingml.document")``-
messages = _Messages()
class _ChannelPost(BaseFilter):
name = 'Filters.update.channel_post'
update_filter = True
def filter(self, update):
@@ -1022,6 +1028,7 @@ officedocument.wordprocessingml.document")``-
class _EditedChannelPost(BaseFilter):
update_filter = True
name = 'Filters.update.edited_channel_post'
def filter(self, update):
return update.edited_channel_post is not None
@@ -1030,6 +1037,7 @@ officedocument.wordprocessingml.document")``-
class _ChannelPosts(BaseFilter):
update_filter = True
name = 'Filters.update.channel_posts'
def filter(self, update):
return update.channel_post is not None or update.edited_channel_post is not None
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+28 -15
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -95,13 +95,14 @@ class JobQueue(object):
"""
# get time at which to run:
time_spec = time_spec or job.interval
if time_spec is None:
time_spec = job.interval
if time_spec is None:
raise ValueError("no time specification given for scheduling non-repeating job")
next_t = to_float_timestamp(time_spec, reference_timestamp=previous_t)
# enqueue:
self.logger.debug('Putting job %s with t=%f', job.name, time_spec)
self.logger.debug('Putting job %s with t=%s', job.name, time_spec)
self._queue.put((next_t, job))
# Wake up the loop if this job should be executed next
@@ -112,9 +113,12 @@ class JobQueue(object):
Args:
callback (:obj:`callable`): The callback function that should be executed by the new
job. It should take ``bot, job`` as parameters, where ``job`` is the
:class:`telegram.ext.Job` instance. It can be used to access its
``job.context`` or change it to a repeating job.
job. Callback signature for context based API:
``def callback(CallbackContext)``
``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
when (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \
:obj:`datetime.datetime` | :obj:`datetime.time`):
Time in or at which the job should run. This parameter will be interpreted
@@ -149,9 +153,12 @@ class JobQueue(object):
Args:
callback (:obj:`callable`): The callback function that should be executed by the new
job. It should take ``bot, job`` as parameters, where ``job`` is the
:class:`telegram.ext.Job` instance. It can be used to access its
``Job.context`` or change it to a repeating job.
job. Callback signature for context based API:
``def callback(CallbackContext)``
``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`): The interval in which
the job will run. If it is an :obj:`int` or a :obj:`float`, it will be interpreted
as seconds.
@@ -200,9 +207,12 @@ class JobQueue(object):
Args:
callback (:obj:`callable`): The callback function that should be executed by the new
job. It should take ``bot, job`` as parameters, where ``job`` is the
:class:`telegram.ext.Job` instance. It can be used to access its ``Job.context``
or change it to a repeating job.
job. Callback signature for context based API:
``def callback(CallbackContext)``
``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone
(``time.tzinfo``) is ``None``, UTC will be assumed.
days (Tuple[:obj:`int`], optional): Defines on which days of the week the job should
@@ -357,9 +367,12 @@ class Job(object):
Args:
callback (:obj:`callable`): The callback function that should be executed by the new job.
It should take ``bot, job`` as parameters, where ``job`` is the
:class:`telegram.ext.Job` instance. It can be used to access it's :attr:`context`
or change it to a repeating job.
Callback signature for context based API:
``def callback(CallbackContext)``
a ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`, optional): The time
interval between executions of the job. If it is an :obj:`int` or a :obj:`float`,
it will be interpreted as seconds. If you don't set this value, you must set
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -4,7 +4,7 @@
# Tymofii A. Khodniev (thodnev) <thodnev@mail.ru>
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+55 -5
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -34,6 +34,8 @@ class PicklePersistence(BasePersistence):
persistence class.
store_chat_data (:obj:`bool`): Optional. Whether user_data should be saved by this
persistence class.
store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this
persistence class.
single_file (:obj:`bool`): Optional. When ``False`` will store 3 sperate files of
`filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is
``True``.
@@ -48,6 +50,8 @@ class PicklePersistence(BasePersistence):
persistence class. Default is ``True``.
store_chat_data (:obj:`bool`, optional): Whether user_data should be saved by this
persistence class. Default is ``True``.
store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this
persistence class. Default is ``True`` .
single_file (:obj:`bool`, optional): When ``False`` will store 3 sperate files of
`filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is
``True``.
@@ -56,15 +60,21 @@ class PicklePersistence(BasePersistence):
on any transaction *and* on call fo :meth:`flush`. Default is ``False``.
"""
def __init__(self, filename, store_user_data=True, store_chat_data=True, single_file=True,
def __init__(self, filename,
store_user_data=True,
store_chat_data=True,
store_bot_data=True,
single_file=True,
on_flush=False):
super(PicklePersistence, self).__init__(store_user_data=store_user_data,
store_chat_data=store_chat_data,
store_bot_data=store_bot_data)
self.filename = filename
self.store_user_data = store_user_data
self.store_chat_data = store_chat_data
self.single_file = single_file
self.on_flush = on_flush
self.user_data = None
self.chat_data = None
self.bot_data = None
self.conversations = None
def load_singlefile(self):
@@ -74,11 +84,14 @@ class PicklePersistence(BasePersistence):
all = pickle.load(f)
self.user_data = defaultdict(dict, all['user_data'])
self.chat_data = defaultdict(dict, all['chat_data'])
# For backwards compatibility with files not containing bot data
self.bot_data = all.get('bot_data', {})
self.conversations = all['conversations']
except IOError:
self.conversations = {}
self.user_data = defaultdict(dict)
self.chat_data = defaultdict(dict)
self.bot_data = {}
except pickle.UnpicklingError:
raise TypeError("File {} does not contain valid pickle data".format(filename))
except Exception:
@@ -98,7 +111,7 @@ class PicklePersistence(BasePersistence):
def dump_singlefile(self):
with open(self.filename, "wb") as f:
all = {'conversations': self.conversations, 'user_data': self.user_data,
'chat_data': self.chat_data}
'chat_data': self.chat_data, 'bot_data': self.bot_data}
pickle.dump(all, f)
def dump_file(self, filename, data):
@@ -145,6 +158,24 @@ class PicklePersistence(BasePersistence):
self.load_singlefile()
return deepcopy(self.chat_data)
def get_bot_data(self):
"""Returns the bot_data from the pickle file if it exsists or an empty dict.
Returns:
:obj:`defaultdict`: The restored bot data.
"""
if self.bot_data:
pass
elif not self.single_file:
filename = "{}_bot_data".format(self.filename)
data = self.load_file(filename)
if not data:
data = {}
self.bot_data = data
else:
self.load_singlefile()
return deepcopy(self.bot_data)
def get_conversations(self, name):
"""Returns the conversations from the pickle file if it exsists or an empty defaultdict.
@@ -221,6 +252,23 @@ class PicklePersistence(BasePersistence):
else:
self.dump_singlefile()
def update_bot_data(self, data):
"""Will update the bot_data (if changed) and depending on :attr:`on_flush` save the
pickle file.
Args:
data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`.
"""
if self.bot_data == data:
return
self.bot_data = data.copy()
if not self.on_flush:
if not self.single_file:
filename = "{}_bot_data".format(self.filename)
self.dump_file(filename, self.bot_data)
else:
self.dump_singlefile()
def flush(self):
""" Will save all data in memory to pickle file(s).
"""
@@ -232,5 +280,7 @@ class PicklePersistence(BasePersistence):
self.dump_file("{}_user_data".format(self.filename), self.user_data)
if self.chat_data:
self.dump_file("{}_chat_data".format(self.filename), self.chat_data)
if self.bot_data:
self.dump_file("{}_bot_data".format(self.filename), self.bot_data)
if self.conversations:
self.dump_file("{}_conversations".format(self.filename), self.conversations)
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+119 -67
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -62,25 +62,33 @@ class Updater(object):
Args:
token (:obj:`str`, optional): The bot's token given by the @BotFather.
base_url (:obj:`str`, optional): Base_url for the bot.
base_file_url (:obj:`str`, optional): Base_file_url for the bot.
workers (:obj:`int`, optional): Amount of threads in the thread pool for functions
decorated with ``@run_async``.
bot (:class:`telegram.Bot`, optional): A pre-initialized bot instance. If a pre-initialized
bot is used, it is the user's responsibility to create it using a `Request`
instance with a large enough connection pool.
decorated with ``@run_async`` (ignored if `dispatcher` argument is used).
bot (:class:`telegram.Bot`, optional): A pre-initialized bot instance (ignored if
`dispatcher` argument is used). If a pre-initialized bot is used, it is the user's
responsibility to create it using a `Request` instance with a large enough connection
pool.
dispatcher (:class:`telegram.ext.Dispatcher`, optional): A pre-initialized dispatcher
instance. If a pre-initialized dispatcher is used, it is the user's responsibility to
create it with proper arguments.
private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data.
private_key_password (:obj:`bytes`, optional): Password for above private key.
user_sig_handler (:obj:`function`, optional): Takes ``signum, frame`` as positional
arguments. This will be called when a signal is received, defaults are (SIGINT,
SIGTERM, SIGABRT) setable with :attr:`idle`.
request_kwargs (:obj:`dict`, optional): Keyword args to control the creation of a
`telegram.utils.request.Request` object (ignored if `bot` argument is used). The
request_kwargs are very useful for the advanced users who would like to control the
default timeouts and/or control the proxy used for http communication.
use_context (:obj:`bool`, optional): If set to ``True`` Use the context based callback API.
During the deprecation period of the old API the default is ``False``. **New users**:
set this to ``True``.
`telegram.utils.request.Request` object (ignored if `bot` or `dispatcher` argument is
used). The request_kwargs are very useful for the advanced users who would like to
control the default timeouts and/or control the proxy used for http communication.
use_context (:obj:`bool`, optional): If set to ``True`` Use the context based callback API
(ignored if `dispatcher` argument is used). During the deprecation period of the old
API the default is ``False``. **New users**: set this to ``True``.
persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to
store data that should be persistent over restarts.
store data that should be persistent over restarts (ignored if `dispatcher` argument is
used).
defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to
be used if not set explicitly in the bot methods.
Note:
You must supply either a :attr:`bot` or a :attr:`token` argument.
@@ -102,53 +110,85 @@ class Updater(object):
user_sig_handler=None,
request_kwargs=None,
persistence=None,
use_context=False):
defaults=None,
use_context=False,
dispatcher=None,
base_file_url=None):
if (token is None) and (bot is None):
raise ValueError('`token` or `bot` must be passed')
if (token is not None) and (bot is not None):
raise ValueError('`token` and `bot` are mutually exclusive')
if (private_key is not None) and (bot is not None):
raise ValueError('`bot` and `private_key` are mutually exclusive')
if dispatcher is None:
if (token is None) and (bot is None):
raise ValueError('`token` or `bot` must be passed')
if (token is not None) and (bot is not None):
raise ValueError('`token` and `bot` are mutually exclusive')
if (private_key is not None) and (bot is not None):
raise ValueError('`bot` and `private_key` are mutually exclusive')
else:
if bot is not None:
raise ValueError('`dispatcher` and `bot` are mutually exclusive')
if persistence is not None:
raise ValueError('`dispatcher` and `persistence` are mutually exclusive')
if workers is not None:
raise ValueError('`dispatcher` and `workers` are mutually exclusive')
if use_context != dispatcher.use_context:
raise ValueError('`dispatcher` and `use_context` are mutually exclusive')
self.logger = logging.getLogger(__name__)
con_pool_size = workers + 4
if dispatcher is None:
con_pool_size = workers + 4
if bot is not None:
self.bot = bot
if bot.request.con_pool_size < con_pool_size:
if bot is not None:
self.bot = bot
if bot.request.con_pool_size < con_pool_size:
self.logger.warning(
'Connection pool of Request object is smaller than optimal value (%s)',
con_pool_size)
else:
# we need a connection pool the size of:
# * for each of the workers
# * 1 for Dispatcher
# * 1 for polling Updater (even if webhook is used, we can spare a connection)
# * 1 for JobQueue
# * 1 for main thread
if request_kwargs is None:
request_kwargs = {}
if 'con_pool_size' not in request_kwargs:
request_kwargs['con_pool_size'] = con_pool_size
self._request = Request(**request_kwargs)
self.bot = Bot(token,
base_url,
base_file_url=base_file_url,
request=self._request,
private_key=private_key,
private_key_password=private_key_password,
defaults=defaults)
self.update_queue = Queue()
self.job_queue = JobQueue()
self.__exception_event = Event()
self.persistence = persistence
self.dispatcher = Dispatcher(self.bot,
self.update_queue,
job_queue=self.job_queue,
workers=workers,
exception_event=self.__exception_event,
persistence=persistence,
use_context=use_context)
self.job_queue.set_dispatcher(self.dispatcher)
else:
con_pool_size = dispatcher.workers + 4
self.bot = dispatcher.bot
if self.bot.request.con_pool_size < con_pool_size:
self.logger.warning(
'Connection pool of Request object is smaller than optimal value (%s)',
con_pool_size)
else:
# we need a connection pool the size of:
# * for each of the workers
# * 1 for Dispatcher
# * 1 for polling Updater (even if webhook is used, we can spare a connection)
# * 1 for JobQueue
# * 1 for main thread
if request_kwargs is None:
request_kwargs = {}
if 'con_pool_size' not in request_kwargs:
request_kwargs['con_pool_size'] = con_pool_size
self._request = Request(**request_kwargs)
self.bot = Bot(token, base_url, request=self._request, private_key=private_key,
private_key_password=private_key_password)
self.update_queue = dispatcher.update_queue
self.__exception_event = dispatcher.exception_event
self.persistence = dispatcher.persistence
self.job_queue = dispatcher.job_queue
self.dispatcher = dispatcher
self.user_sig_handler = user_sig_handler
self.update_queue = Queue()
self.job_queue = JobQueue()
self.__exception_event = Event()
self.persistence = persistence
self.dispatcher = Dispatcher(
self.bot,
self.update_queue,
job_queue=self.job_queue,
workers=workers,
exception_event=self.__exception_event,
persistence=persistence,
use_context=use_context)
self.job_queue.set_dispatcher(self.dispatcher)
self.last_update_id = 0
self.running = False
self.is_idle = False
@@ -156,9 +196,14 @@ class Updater(object):
self.__lock = Lock()
self.__threads = []
# Just for passing to WebhookAppClass
self._default_quote = defaults.quote if defaults else None
def _init_thread(self, target, name, *args, **kwargs):
thr = Thread(target=self._thread_wrapper, name="Bot:{}:{}".format(self.bot.id, name),
args=(target,) + args, kwargs=kwargs)
thr = Thread(target=self._thread_wrapper,
name="Bot:{}:{}".format(self.bot.id, name),
args=(target,) + args,
kwargs=kwargs)
thr.start()
self.__threads.append(thr)
@@ -288,9 +333,10 @@ class Updater(object):
self.logger.debug('Bootstrap done')
def polling_action_cb():
updates = self.bot.get_updates(
self.last_update_id, timeout=timeout, read_latency=read_latency,
allowed_updates=allowed_updates)
updates = self.bot.get_updates(self.last_update_id,
timeout=timeout,
read_latency=read_latency,
allowed_updates=allowed_updates)
if updates:
if not self.running:
@@ -370,7 +416,8 @@ class Updater(object):
url_path = '/{0}'.format(url_path)
# Create Tornado app instance
app = WebhookAppClass(url_path, self.bot, self.update_queue)
app = WebhookAppClass(url_path, self.bot, self.update_queue,
default_quote=self._default_quote)
# Form SSL Context
# An SSLError is raised if the private key does not match with the certificate
@@ -391,12 +438,11 @@ class Updater(object):
if not webhook_url:
webhook_url = self._gen_webhook_url(listen, port, url_path)
self._bootstrap(
max_retries=bootstrap_retries,
clean=clean,
webhook_url=webhook_url,
cert=open(cert, 'rb'),
allowed_updates=allowed_updates)
self._bootstrap(max_retries=bootstrap_retries,
clean=clean,
webhook_url=webhook_url,
cert=open(cert, 'rb'),
allowed_updates=allowed_updates)
elif clean:
self.logger.warning("cleaning updates is not supported if "
"SSL-termination happens elsewhere; skipping")
@@ -407,7 +453,12 @@ class Updater(object):
def _gen_webhook_url(listen, port, url_path):
return 'https://{listen}:{port}{path}'.format(listen=listen, port=port, path=url_path)
def _bootstrap(self, max_retries, clean, webhook_url, allowed_updates, cert=None,
def _bootstrap(self,
max_retries,
clean,
webhook_url,
allowed_updates,
cert=None,
bootstrap_interval=5):
retries = [0]
@@ -423,15 +474,16 @@ class Updater(object):
return False
def bootstrap_set_webhook():
self.bot.set_webhook(
url=webhook_url, certificate=cert, allowed_updates=allowed_updates)
self.bot.set_webhook(url=webhook_url,
certificate=cert,
allowed_updates=allowed_updates)
return False
def bootstrap_onerr_cb(exc):
if not isinstance(exc, Unauthorized) and (max_retries < 0 or retries[0] < max_retries):
retries[0] += 1
self.logger.warning('Failed bootstrap phase; try=%s max_retries=%s',
retries[0], max_retries)
self.logger.warning('Failed bootstrap phase; try=%s max_retries=%s', retries[0],
max_retries)
else:
self.logger.error('Failed bootstrap phase after %s retries (%s)', retries[0], exc)
raise exc
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+9 -5
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains an object that represents a Telegram File."""
from base64 import b64decode
from os.path import basename
import os
from future.backports.urllib import parse as urllib_parse
@@ -76,9 +77,10 @@ class File(TelegramObject):
def download(self, custom_path=None, out=None, timeout=None):
"""
Download this file. By default, the file is saved in the current working directory with its
original filename as reported by Telegram. If a :attr:`custom_path` is supplied, it will be
saved to that path instead. If :attr:`out` is defined, the file contents will be saved to
that object using the ``out.write`` method.
original filename as reported by Telegram. If the file has no filename, it the file ID will
be used as filename. If a :attr:`custom_path` is supplied, it will be saved to that path
instead. If :attr:`out` is defined, the file contents will be saved to that object using
the ``out.write`` method.
Note:
:attr:`custom_path` and :attr:`out` are mutually exclusive.
@@ -116,8 +118,10 @@ class File(TelegramObject):
else:
if custom_path:
filename = custom_path
else:
elif self.file_path:
filename = basename(self.file_path)
else:
filename = os.path.join(os.getcwd(), self.file_id)
buf = self.bot.request.retrieve(url, timeout=timeout)
if self._credentials:
+1 -1
View File
@@ -2,7 +2,7 @@
# pylint: disable=W0622,E0611
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+26 -24
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""Base class for Telegram InputMedia Objects."""
from telegram import TelegramObject, InputFile, PhotoSize, Animation, Video, Audio, Document
from telegram.utils.helpers import DEFAULT_NONE
class InputMedia(TelegramObject):
@@ -44,7 +45,7 @@ class InputMediaAnimation(InputMedia):
Lastly you can pass an existing :class:`telegram.Animation` object to send.
thumb (`filelike object`): Optional. Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
caption (:obj:`str`): Optional. Caption of the animation to be sent, 0-1024 characters.
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
@@ -61,7 +62,7 @@ class InputMediaAnimation(InputMedia):
Lastly you can pass an existing :class:`telegram.Animation` object to send.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
caption (:obj:`str`, optional): Caption of the animation to be sent, 0-1024 characters.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
@@ -77,7 +78,13 @@ class InputMediaAnimation(InputMedia):
arguments.
"""
def __init__(self, media, thumb=None, caption=None, parse_mode=None, width=None, height=None,
def __init__(self,
media,
thumb=None,
caption=None,
parse_mode=DEFAULT_NONE,
width=None,
height=None,
duration=None):
self.type = 'animation'
@@ -98,8 +105,7 @@ class InputMediaAnimation(InputMedia):
if caption:
self.caption = caption
if parse_mode:
self.parse_mode = parse_mode
self.parse_mode = parse_mode
if width:
self.width = width
if height:
@@ -133,7 +139,7 @@ class InputMediaPhoto(InputMedia):
in :class:`telegram.ParseMode` for the available modes.
"""
def __init__(self, media, caption=None, parse_mode=None):
def __init__(self, media, caption=None, parse_mode=DEFAULT_NONE):
self.type = 'photo'
if isinstance(media, PhotoSize):
@@ -145,8 +151,7 @@ class InputMediaPhoto(InputMedia):
if caption:
self.caption = caption
if parse_mode:
self.parse_mode = parse_mode
self.parse_mode = parse_mode
class InputMediaVideo(InputMedia):
@@ -170,7 +175,7 @@ class InputMediaVideo(InputMedia):
for streaming.
thumb (`filelike object`): Optional. Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
Args:
@@ -188,7 +193,7 @@ class InputMediaVideo(InputMedia):
for streaming.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
Note:
@@ -198,7 +203,7 @@ class InputMediaVideo(InputMedia):
"""
def __init__(self, media, caption=None, width=None, height=None, duration=None,
supports_streaming=None, parse_mode=None, thumb=None):
supports_streaming=None, parse_mode=DEFAULT_NONE, thumb=None):
self.type = 'video'
if isinstance(media, Video):
@@ -218,8 +223,7 @@ class InputMediaVideo(InputMedia):
if caption:
self.caption = caption
if parse_mode:
self.parse_mode = parse_mode
self.parse_mode = parse_mode
if width:
self.width = width
if height:
@@ -250,7 +254,7 @@ class InputMediaAudio(InputMedia):
title (:obj:`str`): Optional. Title of the audio as defined by sender or by audio tags.
thumb (`filelike object`): Optional. Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
Args:
@@ -267,7 +271,7 @@ class InputMediaAudio(InputMedia):
title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
Note:
@@ -276,7 +280,7 @@ class InputMediaAudio(InputMedia):
optional arguments.
"""
def __init__(self, media, thumb=None, caption=None, parse_mode=None,
def __init__(self, media, thumb=None, caption=None, parse_mode=DEFAULT_NONE,
duration=None, performer=None, title=None):
self.type = 'audio'
@@ -297,8 +301,7 @@ class InputMediaAudio(InputMedia):
if caption:
self.caption = caption
if parse_mode:
self.parse_mode = parse_mode
self.parse_mode = parse_mode
if duration:
self.duration = duration
if performer:
@@ -323,7 +326,7 @@ class InputMediaDocument(InputMedia):
in :class:`telegram.ParseMode` for the available modes.
thumb (`filelike object`): Optional. Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
Args:
@@ -336,11 +339,11 @@ class InputMediaDocument(InputMedia):
in :class:`telegram.ParseMode` for the available modes.
thumb (`filelike object`, optional): Thumbnail of the
file sent. The thumbnail should be in JPEG format and less than 200 kB in size.
A thumbnail's width and height should not exceed 90. Ignored if the file is not
A thumbnail's width and height should not exceed 320. Ignored if the file is not
is passed as a string or file_id.
"""
def __init__(self, media, thumb=None, caption=None, parse_mode=None):
def __init__(self, media, thumb=None, caption=None, parse_mode=DEFAULT_NONE):
self.type = 'document'
if isinstance(media, Document):
@@ -357,5 +360,4 @@ class InputMediaDocument(InputMedia):
if caption:
self.caption = caption
if parse_mode:
self.parse_mode = parse_mode
self.parse_mode = parse_mode
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+3 -3
View File
@@ -2,7 +2,7 @@
# pylint: disable=R0902,R0912,R0913
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -35,7 +35,7 @@ class InlineQuery(TelegramObject):
from_user (:class:`telegram.User`): Sender.
location (:class:`telegram.Location`): Optional. Sender location, only for bots that
request user location.
query (:obj:`str`): Text of the query (up to 512 characters).
query (:obj:`str`): Text of the query (up to 256 characters).
offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot.
Args:
@@ -43,7 +43,7 @@ class InlineQuery(TelegramObject):
from_user (:class:`telegram.User`): Sender.
location (:class:`telegram.Location`, optional): Sender location, only for bots that
request user location.
query (:obj:`str`): Text of the query (up to 512 characters).
query (:obj:`str`): Text of the query (up to 256 characters).
offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
+9 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -41,3 +41,11 @@ class InlineQueryResult(TelegramObject):
self.id = str(id)
self._id_attrs = (self.id,)
@property
def _has_parse_mode(self):
return hasattr(self, 'parse_mode')
@property
def _has_input_message_content(self):
return hasattr(self, 'input_message_content')
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+3 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultAudio."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultAudio(InlineQueryResult):
@@ -70,7 +71,7 @@ class InlineQueryResultAudio(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedAudio."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedAudio(InlineQueryResult):
@@ -61,7 +62,7 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultCachedAudio, self).__init__('audio', id)
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedDocument."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedDocument(InlineQueryResult):
@@ -67,7 +68,7 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultCachedDocument, self).__init__('document', id)
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedGif."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedGif(InlineQueryResult):
@@ -65,7 +66,7 @@ class InlineQueryResultCachedGif(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultCachedGif, self).__init__('gif', id)
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
@@ -65,7 +66,7 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultCachedMpeg4Gif, self).__init__('mpeg4_gif', id)
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultPhoto"""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedPhoto(InlineQueryResult):
@@ -68,7 +69,7 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultCachedPhoto, self).__init__('photo', id)
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedVideo."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedVideo(InlineQueryResult):
@@ -68,7 +69,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultCachedVideo, self).__init__('video', id)
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedVoice."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedVoice(InlineQueryResult):
@@ -64,7 +65,7 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultCachedVoice, self).__init__('voice', id)
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+3 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultDocument"""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultDocument(InlineQueryResult):
@@ -82,7 +83,7 @@ class InlineQueryResultDocument(InlineQueryResult):
thumb_url=None,
thumb_width=None,
thumb_height=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultDocument, self).__init__('document', id)
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+3 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultGif."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultGif(InlineQueryResult):
@@ -76,7 +77,7 @@ class InlineQueryResultGif(InlineQueryResult):
reply_markup=None,
input_message_content=None,
gif_duration=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+3 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultMpeg4Gif(InlineQueryResult):
@@ -77,7 +78,7 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
reply_markup=None,
input_message_content=None,
mpeg4_duration=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
+3 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultPhoto."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultPhoto(InlineQueryResult):
@@ -78,7 +79,7 @@ class InlineQueryResultPhoto(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
super(InlineQueryResultPhoto, self).__init__('photo', id)
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+3 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultVideo."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultVideo(InlineQueryResult):
@@ -83,7 +84,7 @@ class InlineQueryResultVideo(InlineQueryResult):
description=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
+3 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultVoice."""
from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultVoice(InlineQueryResult):
@@ -68,7 +69,7 @@ class InlineQueryResultVoice(InlineQueryResult):
caption=None,
reply_markup=None,
input_message_content=None,
parse_mode=None,
parse_mode=DEFAULT_NONE,
**kwargs):
# Required
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+8 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -29,4 +29,10 @@ class InputMessageContent(TelegramObject):
:class:`telegram.InputVenueMessageContent` for more details.
"""
pass
@property
def _has_parse_mode(self):
return hasattr(self, 'parse_mode')
@property
def _has_disable_web_page_preview(self):
return hasattr(self, 'disable_web_page_preview')
+7 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InputTextMessageContent."""
from telegram import InputMessageContent
from telegram.utils.helpers import DEFAULT_NONE
class InputTextMessageContent(InputMessageContent):
@@ -43,7 +44,11 @@ class InputTextMessageContent(InputMessageContent):
"""
def __init__(self, message_text, parse_mode=None, disable_web_page_preview=None, **kwargs):
def __init__(self,
message_text,
parse_mode=DEFAULT_NONE,
disable_web_page_preview=DEFAULT_NONE,
**kwargs):
# Required
self.message_text = message_text
# Optionals
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+1 -1
View File
@@ -2,7 +2,7 @@
# pylint: disable=R0903
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2019
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
+67 -44
View File
@@ -2,7 +2,7 @@
# pylint: disable=R0902,R0912,R0913
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -109,6 +109,8 @@ class Message(TelegramObject):
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
default_quote (:obj:`bool`): Optional. Default setting for the `quote` parameter of the
:attr:`reply_text` and friends.
Args:
message_id (:obj:`int`): Unique message identifier inside this chat.
@@ -214,6 +216,8 @@ class Message(TelegramObject):
information about the poll.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message. login_url buttons are represented as ordinary url buttons.
default_quote (:obj:`bool`, optional): Default setting for the `quote` parameter of the
:attr:`reply_text` and friends.
"""
@@ -277,6 +281,7 @@ class Message(TelegramObject):
forward_sender_name=None,
reply_markup=None,
bot=None,
default_quote=None,
**kwargs):
# Required
self.message_id = int(message_id)
@@ -328,6 +333,7 @@ class Message(TelegramObject):
self.poll = poll
self.reply_markup = reply_markup
self.bot = bot
self.default_quote = default_quote
self._id_attrs = (self.message_id,)
@@ -339,18 +345,13 @@ class Message(TelegramObject):
@property
def link(self):
""":obj:`str`: Convenience property. If the chat of the message is not
a private chat, returns a t.me link of the message."""
if self.chat.type != Chat.PRIVATE:
a private chat or normal group, returns a t.me link of the message."""
if self.chat.type not in [Chat.PRIVATE, Chat.GROUP]:
if self.chat.username:
to_link = self.chat.username
else:
if self.chat.type != Chat.GROUP:
# Get rid of leading -100 for supergroups
id_to_link = str(self.chat.id)[4:]
else:
# Get rid of leading minus for regular groups
id_to_link = str(self.chat.id)[1:]
to_link = "c/{}".format(id_to_link)
# Get rid of leading -100 for supergroups
to_link = "c/{}".format(str(self.chat.id)[4:])
return "https://t.me/{}/{}".format(to_link, self.message_id)
return None
@@ -363,13 +364,22 @@ class Message(TelegramObject):
data['from_user'] = User.de_json(data.get('from'), bot)
data['date'] = from_timestamp(data['date'])
data['chat'] = Chat.de_json(data.get('chat'), bot)
chat = data.get('chat')
if chat:
chat['default_quote'] = data.get('default_quote')
data['chat'] = Chat.de_json(chat, bot)
data['entities'] = MessageEntity.de_list(data.get('entities'), bot)
data['caption_entities'] = MessageEntity.de_list(data.get('caption_entities'), bot)
data['forward_from'] = User.de_json(data.get('forward_from'), bot)
data['forward_from_chat'] = Chat.de_json(data.get('forward_from_chat'), bot)
forward_from_chat = data.get('forward_from_chat')
if forward_from_chat:
forward_from_chat['default_quote'] = data.get('default_quote')
data['forward_from_chat'] = Chat.de_json(forward_from_chat, bot)
data['forward_date'] = from_timestamp(data.get('forward_date'))
data['reply_to_message'] = Message.de_json(data.get('reply_to_message'), bot)
reply_to_message = data.get('reply_to_message')
if reply_to_message:
reply_to_message['default_quote'] = data.get('default_quote')
data['reply_to_message'] = Message.de_json(reply_to_message, bot)
data['edit_date'] = from_timestamp(data.get('edit_date'))
data['audio'] = Audio.de_json(data.get('audio'), bot)
data['document'] = Document.de_json(data.get('document'), bot)
@@ -386,7 +396,10 @@ class Message(TelegramObject):
data['new_chat_members'] = User.de_list(data.get('new_chat_members'), bot)
data['left_chat_member'] = User.de_json(data.get('left_chat_member'), bot)
data['new_chat_photo'] = PhotoSize.de_list(data.get('new_chat_photo'), bot)
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)
pinned_message = data.get('pinned_message')
if pinned_message:
pinned_message['default_quote'] = data.get('default_quote')
data['pinned_message'] = Message.de_json(pinned_message, bot)
data['invoice'] = Invoice.de_json(data.get('invoice'), bot)
data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot)
data['passport_data'] = PassportData.de_json(data.get('passport_data'), bot)
@@ -469,7 +482,8 @@ class Message(TelegramObject):
del kwargs['quote']
else:
if self.chat.type != Chat.PRIVATE:
if ((self.default_quote is None and self.chat.type != Chat.PRIVATE)
or self.default_quote):
kwargs['reply_to_message_id'] = self.message_id
def reply_text(self, *args, **kwargs):
@@ -580,7 +594,7 @@ class Message(TelegramObject):
bot.send_audio(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): If set to ``True``, the photo is sent as an actual reply
quote (:obj:`bool`, optional): 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.
@@ -597,9 +611,10 @@ class Message(TelegramObject):
bot.send_document(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): 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.
@@ -614,9 +629,10 @@ class Message(TelegramObject):
bot.send_animation(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): If set to ``True``, the animation 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.
@@ -631,9 +647,10 @@ class Message(TelegramObject):
bot.send_sticker(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): 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.
@@ -648,9 +665,10 @@ class Message(TelegramObject):
bot.send_video(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): 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.
@@ -665,9 +683,10 @@ class Message(TelegramObject):
bot.send_video_note(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): If set to ``True``, the video note 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.
@@ -682,9 +701,10 @@ class Message(TelegramObject):
bot.send_voice(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): If set to ``True``, the voice note 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.
@@ -699,9 +719,10 @@ class Message(TelegramObject):
bot.send_location(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): 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.
@@ -716,9 +737,10 @@ class Message(TelegramObject):
bot.send_venue(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): 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.
@@ -733,9 +755,10 @@ class Message(TelegramObject):
bot.send_contact(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): 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.
quote (:obj:`bool`, optional): 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.
@@ -750,7 +773,7 @@ class Message(TelegramObject):
bot.send_poll(update.message.chat_id, *args, **kwargs)
Keyword Args:
quote (:obj:`bool`, optional): If set to ``True``, the photo is sent as an actual reply
quote (:obj:`bool`, optional): If set to ``True``, the poll 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.
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2018
# Copyright (C) 2015-2020
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify

Some files were not shown because too many files have changed in this diff Show More