mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-19 07:35:19 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aa8966832b | |||
| e27427676d | |||
| 8175fd7b53 | |||
| 2875bae881 | |||
| c756aa1c02 | |||
| c2f04331f3 | |||
| 5293ec49ff | |||
| 9319903343 | |||
| 95e2aad9bd | |||
| 73f4f26da5 | |||
| 24b2bf335c | |||
| fc3fa0f515 | |||
| 87657bcd70 | |||
| 81b58c7d00 | |||
| dd7d1255d1 | |||
| f813d4f5ec | |||
| 623863cee1 | |||
| aa125e59fb | |||
| 68c844df0c | |||
| 3779d454f3 | |||
| 5d168bd479 | |||
| 1c8bb21790 | |||
| 054c976ad6 | |||
| bc2679f2ae | |||
| 17dae68654 | |||
| 7734c1d6a6 | |||
| aeca3ca174 | |||
| 21fdaa4ff7 | |||
| 79f29c4b9e | |||
| a2d8ca3663 | |||
| 6f76bfc2de | |||
| 97ebebefc1 | |||
| 119743433d | |||
| b0ad07f30f | |||
| 114cb787ea | |||
| 5d1ef673a3 | |||
| 3e1cb08567 | |||
| 29a4062945 | |||
| 2ff6fe9901 | |||
| 34b91f5062 | |||
| cc6c4a6eb9 | |||
| fc9456e1a8 | |||
| 41ba57f064 | |||
| b205751aee | |||
| c4f13bd1bb | |||
| 7d7397317e | |||
| 631954e5d9 | |||
| 90ed128a61 | |||
| 2a2b679362 | |||
| f75e329225 | |||
| ea7c54ba07 | |||
| 3c7b037eaa | |||
| c15a1bc151 | |||
| 9e7314134e | |||
| 37271e4a02 | |||
| 0e78606d37 | |||
| cb0736fb3d | |||
| e0233a59a0 | |||
| 6e158042e1 | |||
| d791a6ee89 | |||
| 5a3e142358 | |||
| 37a58fe1ad | |||
| 80281cc66d | |||
| fffa9d8a7c | |||
| 806b71030f | |||
| 764c5dac53 | |||
| 007dc5807a | |||
| 16534872a7 | |||
| a13245dfbf |
@@ -61,3 +61,10 @@ target/
|
||||
|
||||
# Sublime Text 2
|
||||
*.sublime*
|
||||
|
||||
# unitests files
|
||||
telegram.mp3
|
||||
telegram.mp4
|
||||
telegram.ogg
|
||||
telegram.png
|
||||
telegram.webp
|
||||
|
||||
+2
-1
@@ -9,9 +9,10 @@ python:
|
||||
install:
|
||||
- pip install pylint flake8 coveralls
|
||||
- pip install -r requirements.txt
|
||||
- 'if [[ $TRAVIS_PYTHON_VERSION == 2.6 ]]; then pip install unittest2; fi'
|
||||
script:
|
||||
- nosetests --with-coverage --cover-package telegram/
|
||||
- flake8 telegram
|
||||
- 'if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then pylint -E telegram; fi'
|
||||
- 'if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then pylint -E telegram --disable=no-name-in-module,import-error; fi'
|
||||
after_success:
|
||||
coveralls
|
||||
|
||||
@@ -19,6 +19,7 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||
- `macrojames <https://github.com/macrojames>`_
|
||||
- `naveenvhegde <https://github.com/naveenvhegde>`_
|
||||
- `njittam <https://github.com/njittam>`_
|
||||
- `Noam Meltzer <https://github.com/tsnoam>`_
|
||||
- `Rahiel Kasim <https://github.com/rahiel>`_
|
||||
- `sooyhwang <https://github.com/sooyhwang>`_
|
||||
- `wjt <https://github.com/wjt>`_
|
||||
|
||||
+30
@@ -1,3 +1,33 @@
|
||||
**2016-01-05**
|
||||
|
||||
*Released 3.2.0*
|
||||
|
||||
- Introducing ``JobQueue`` (original author: @franciscod)
|
||||
- Streamlining all exceptions to ``TelegramError`` (Special thanks to @tsnoam)
|
||||
- Proper locking of ``Updater`` and ``Dispatcher`` ``start`` and ``stop`` methods
|
||||
- Small bugfixes
|
||||
|
||||
**2015-12-29**
|
||||
|
||||
*Released 3.1.2*
|
||||
|
||||
- Fix custom path for file downloads
|
||||
- Don't stop the dispatcher thread on uncaught errors in handlers
|
||||
|
||||
**2015-12-21**
|
||||
|
||||
*Released 3.1.1*
|
||||
|
||||
- Fix a bug where asynchronous handlers could not have additional arguments
|
||||
- Add ``groups`` and ``groupdict`` as additional arguments for regex-based handlers
|
||||
|
||||
**2015-12-16**
|
||||
|
||||
*Released 3.1.0*
|
||||
|
||||
- The ``chat``-field in ``Message`` is now of type ``Chat``. (API update Oct 8 2015)
|
||||
- ``Message`` now contains the optional fields ``supergroup_chat_created``, ``migrate_to_chat_id``, ``migrate_from_chat_id`` and ``channel_chat_created``. (API update Nov 2015)
|
||||
|
||||
**2015-12-08**
|
||||
|
||||
*Released 3.0.0*
|
||||
|
||||
+2
-2
@@ -35,5 +35,5 @@ If you have any question or concerns, feel free to reach out to me.
|
||||
.. _`Code of Conduct`: https://www.python.org/psf/codeofconduct/
|
||||
.. _`Google Python Style Guide`: https://google-styleguide.googlecode.com/svn/trunk/pyguide.html
|
||||
.. _`Google Python Style Docstrings`: http://sphinx-doc.org/latest/ext/example_google.html
|
||||
.. _CHANGES: https://github.com/leandrotoledo/python-telegram-bot/blob/master/CHANGES
|
||||
.. _AUTHORS.rst: https://github.com/leandrotoledo/python-telegram-bot/blob/master/AUTHORS.rst
|
||||
.. _CHANGES: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/CHANGES
|
||||
.. _AUTHORS.rst: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/AUTHORS.rst
|
||||
|
||||
+70
-29
@@ -1,11 +1,12 @@
|
||||
Python Telegram Bot
|
||||
.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-logo-text_768.png?raw=true
|
||||
:align: center
|
||||
:target: https://github.com/python-telegram-bot/logos
|
||||
:alt: python-telegram-bot Logo
|
||||
|
||||
A Python wrapper around the Telegram Bot API.
|
||||
|
||||
*Stay tuned for library updates and new releases on our* `Telegram Channel <http://telegram.me/pythontelegrambotchannel>`_.
|
||||
|
||||
By `Leandro Toledo <leandrotoledodesouza@gmail.com>`_
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/python-telegram-bot.svg
|
||||
:target: https://pypi.python.org/pypi/python-telegram-bot
|
||||
:alt: PyPi Package Version
|
||||
@@ -22,16 +23,16 @@ By `Leandro Toledo <leandrotoledodesouza@gmail.com>`_
|
||||
:target: http://www.gnu.org/licenses/lgpl-3.0.html
|
||||
:alt: LGPLv3 License
|
||||
|
||||
.. image:: https://travis-ci.org/leandrotoledo/python-telegram-bot.svg?branch=master
|
||||
:target: https://travis-ci.org/leandrotoledo/python-telegram-bot
|
||||
.. image:: https://travis-ci.org/python-telegram-bot/python-telegram-bot.svg?branch=master
|
||||
:target: https://travis-ci.org/python-telegram-bot/python-telegram-bot
|
||||
:alt: Travis CI Status
|
||||
|
||||
.. image:: https://codeclimate.com/github/leandrotoledo/python-telegram-bot/badges/gpa.svg
|
||||
:target: https://codeclimate.com/github/leandrotoledo/python-telegram-bot
|
||||
.. image:: https://codeclimate.com/github/python-telegram-bot/python-telegram-bot/badges/gpa.svg
|
||||
:target: https://codeclimate.com/github/python-telegram-bot/python-telegram-bot
|
||||
:alt: Code Climate
|
||||
|
||||
.. image:: https://coveralls.io/repos/leandrotoledo/python-telegram-bot/badge.svg?branch=master&service=github
|
||||
:target: https://coveralls.io/github/leandrotoledo/python-telegram-bot?branch=master
|
||||
.. image:: https://coveralls.io/repos/python-telegram-bot/python-telegram-bot/badge.svg?branch=master&service=github
|
||||
:target: https://coveralls.io/github/python-telegram-bot/python-telegram-bot?branch=master
|
||||
:alt: Coveralls
|
||||
|
||||
=================
|
||||
@@ -52,15 +53,17 @@ Table of contents
|
||||
|
||||
- `Getting started`_
|
||||
|
||||
1. `API`_
|
||||
|
||||
2. `The Updater class`_
|
||||
1. `The Updater class`_
|
||||
|
||||
3. `Logging`_
|
||||
2. `API`_
|
||||
|
||||
3. `JobQueue`_
|
||||
|
||||
4. `Examples`_
|
||||
4. `Logging`_
|
||||
|
||||
5. `Documentation`_
|
||||
5. `Examples`_
|
||||
|
||||
6. `Documentation`_
|
||||
|
||||
- `License`_
|
||||
|
||||
@@ -133,11 +136,11 @@ Or upgrade to the latest version::
|
||||
_`Getting the code`
|
||||
===================
|
||||
|
||||
The code is hosted at https://github.com/leandrotoledo/python-telegram-bot
|
||||
The code is hosted at https://github.com/python-telegram-bot/python-telegram-bot
|
||||
|
||||
Check out the latest development version anonymously with::
|
||||
|
||||
$ git clone https://github.com/leandrotoledo/python-telegram-bot
|
||||
$ git clone https://github.com/python-telegram-bot/python-telegram-bot
|
||||
$ cd python-telegram-bot
|
||||
|
||||
Run tests:
|
||||
@@ -154,9 +157,9 @@ _`Getting started`
|
||||
|
||||
View the last release API documentation at: https://core.telegram.org/bots/api
|
||||
|
||||
------
|
||||
--------------------
|
||||
_`The Updater class`
|
||||
------
|
||||
--------------------
|
||||
|
||||
The ``Updater`` class is the new way to create bots with ``python-telegram-bot``. It provides an easy-to-use interface to the ``telegram.Bot`` by caring about getting new updates from telegram and forwarding them to the ``Dispatcher`` class. We can register handler functions in the ``Dispatcher`` to make our bot react to Telegram commands, messages and even arbitrary updates.
|
||||
|
||||
@@ -212,7 +215,7 @@ Now it's time to stop the bot::
|
||||
|
||||
>>> updater.stop()
|
||||
|
||||
Check out more examples in the `examples folder <https://github.com/leandrotoledo/python-telegram-bot/tree/master/examples>`_!
|
||||
Check out more examples in the `examples folder <https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples>`_!
|
||||
|
||||
------
|
||||
_`API`
|
||||
@@ -298,9 +301,39 @@ There are many more API methods, to read the full API documentation::
|
||||
$ pydoc telegram.Bot
|
||||
|
||||
-----------
|
||||
_`Logging`
|
||||
_`JobQueue`
|
||||
-----------
|
||||
|
||||
The ``JobQueue`` allows you to perform tasks with a delay or even periodically. The ``Updater`` will create one for you::
|
||||
|
||||
>>> from telegram import Updater
|
||||
>>> u = Updater('TOKEN')
|
||||
>>> j = u.job_queue
|
||||
|
||||
The job queue uses functions for tasks, so we define one and add it to the queue. Usually, when the first job is added to the queue, it wil start automatically. We can prevent this by setting ``prevent_autostart=True``::
|
||||
|
||||
>>> def job1(bot):
|
||||
... bot.sendMessage(chat_id='@examplechannel', text='One message every minute')
|
||||
>>> j.put(job1, 60, next_t=0, prevent_autostart=True)
|
||||
|
||||
You can also have a job that will not be executed repeatedly::
|
||||
|
||||
>>> def job2(bot):
|
||||
... bot.sendMessage(chat_id='@examplechannel', text='A single message with 30s delay')
|
||||
>>> j.put(job2, 30, repeat=False)
|
||||
|
||||
Now, because we didn't prevent the auto start this time, the queue will start ticking. It runs in a seperate thread, so it is non-blocking. When we stop the Updater, the related queue will be stopped as well::
|
||||
|
||||
>>> u.stop()
|
||||
|
||||
We can also stop the job queue by itself::
|
||||
|
||||
>>> j.stop()
|
||||
|
||||
----------
|
||||
_`Logging`
|
||||
----------
|
||||
|
||||
You can get logs in your main application by calling `logging` and setting the log level you want::
|
||||
|
||||
>>> import logging
|
||||
@@ -317,14 +350,26 @@ _`Examples`
|
||||
|
||||
Here follows some examples to help you to get your own Bot up to speed:
|
||||
|
||||
- `echobot <https://github.com/leandrotoledo/python-telegram-bot/blob/master/examples/echobot.py>`_ replies back messages.
|
||||
- `echobot2 <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/echobot2.py>`_ replies back messages.
|
||||
|
||||
- `roboed <https://github.com/leandrotoledo/python-telegram-bot/blob/master/examples/roboed.py>`_ talks to `Robô Ed <http://www.ed.conpet.gov.br/br/converse.php>`_.
|
||||
- `clibot <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/clibot.py>`_ has a command line interface.
|
||||
|
||||
- `timerbot <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/timerbot.py>`_ uses the ``JobQueue`` to send timed messages.
|
||||
|
||||
- `Welcome Bot <https://github.com/jh0ker/welcomebot>`_ greets everyone who joins a group chat.
|
||||
|
||||
Legacy examples (pre-3.0):
|
||||
|
||||
- `echobot <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/legacy/echobot.py>`_ replies back messages.
|
||||
|
||||
- `roboed <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/legacy/roboed.py>`_ talks to `Robô Ed <http://www.ed.conpet.gov.br/br/converse.php>`_.
|
||||
|
||||
- `Simple-Echo-Telegram-Bot <https://github.com/sooyhwang/Simple-Echo-Telegram-Bot>`_ simple Python Telegram bot that echoes your input with Flask microframework, setWebhook method, and Google App Engine (optional) - by @sooyhwang.
|
||||
|
||||
- `DevOps Reaction Bot <https://github.com/leandrotoledo/gae-devops-reaction-telegram-bot>`_ sends latest or random posts from `DevOps Reaction <http://devopsreactions.tumblr.com/>`_. Running on `Google App Engine <https://cloud.google.com/appengine>`_ (billing has to be enabled for fully Socket API support).
|
||||
|
||||
Other notable examples:
|
||||
|
||||
- `TwitterForwarderBot <https://github.com/franciscod/telegram-twitter-forwarder-bot>`_ forwards you tweets from people that you have subscribed to.
|
||||
|
||||
================
|
||||
@@ -343,14 +388,10 @@ You may copy, distribute and modify the software provided that modifications are
|
||||
_`Contact`
|
||||
==========
|
||||
|
||||
Feel free to join to our `Telegram group <https://telegram.me/joinchat/ALnA-AJQm5SEwuAzar3nvw>`_.
|
||||
|
||||
If you face trouble joining in the group please ping me `via Telegram <https://telegram.me/leandrotoledo>`_, I'll be glad to add you.
|
||||
Feel free to join to our `Telegram group <https://telegram.me/joinchat/ALnA-AJQm5R7Km9hdCgyng>`_.
|
||||
|
||||
=======
|
||||
_`TODO`
|
||||
=======
|
||||
|
||||
Patches and bug reports are `welcome <https://github.com/leandrotoledo/python-telegram-bot/issues/new>`_, just please keep the style consistent with the original source.
|
||||
|
||||
- Add commands handler.
|
||||
Patches and bug reports are `welcome <https://github.com/python-telegram-bot/python-telegram-bot/issues/new>`_, just please keep the style consistent with the original source.
|
||||
|
||||
+3
-3
@@ -50,7 +50,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Python Telegram Bot'
|
||||
copyright = u'2015, Leandro Toledo'
|
||||
copyright = u'2015-2016, 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 = '3.0'
|
||||
version = '3.2'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '3.0.0'
|
||||
release = '3.2.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
telegram.groupchat module
|
||||
telegram.chat module
|
||||
=========================
|
||||
|
||||
.. automodule:: telegram.groupchat
|
||||
.. automodule:: telegram.chat
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,7 @@
|
||||
telegram.dispatcher module
|
||||
=========================
|
||||
|
||||
.. automodule:: telegram.dispatcher
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,7 @@
|
||||
telegram.jobqueue module
|
||||
========================
|
||||
|
||||
.. automodule:: telegram.jobqueue
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -9,13 +9,16 @@ Submodules
|
||||
telegram.audio
|
||||
telegram.base
|
||||
telegram.bot
|
||||
telegram.updater
|
||||
telegram.dispatcher
|
||||
telegram.jobqueue
|
||||
telegram.chataction
|
||||
telegram.contact
|
||||
telegram.document
|
||||
telegram.emoji
|
||||
telegram.error
|
||||
telegram.forcereply
|
||||
telegram.groupchat
|
||||
telegram.chat
|
||||
telegram.inputfile
|
||||
telegram.location
|
||||
telegram.message
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
telegram.updater module
|
||||
=========================
|
||||
|
||||
.. automodule:: telegram.updater
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,116 @@
|
||||
CC0 1.0 Universal
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||
and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||
depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||
a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||
including without limitation warranties of title, merchantability, fitness
|
||||
for a particular purpose, non infringement, or the absence of latent or
|
||||
other defects, accuracy, or the present or absence of errors, whether or not
|
||||
discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without limitation
|
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
disclaims responsibility for obtaining any necessary consents, permissions
|
||||
or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to this
|
||||
CC0 or use of the Work.
|
||||
|
||||
For more information, please see
|
||||
<http://creativecommons.org/publicdomain/zero/1.0/>
|
||||
@@ -1,4 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Example Bot to show some of the functionality of the library
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
This Bot uses the Updater class to handle the bot.
|
||||
@@ -9,8 +13,8 @@ Then, the bot is started and the CLI-Loop is entered, where all text inputs are
|
||||
inserted into the update queue for the bot to handle.
|
||||
|
||||
Usage:
|
||||
Basic Echobot example, repeats messages. Reply to last chat from the command
|
||||
line by typing "/reply <text>"
|
||||
Repeats messages with a delay.
|
||||
Reply to last chat from the command line by typing "/reply <text>"
|
||||
Type 'stop' on the command line to stop the bot.
|
||||
"""
|
||||
|
||||
@@ -18,24 +22,20 @@ from telegram import Updater
|
||||
from telegram.dispatcher import run_async
|
||||
from time import sleep
|
||||
import logging
|
||||
import sys
|
||||
|
||||
root = logging.getLogger()
|
||||
root.setLevel(logging.INFO)
|
||||
|
||||
ch = logging.StreamHandler(sys.stdout)
|
||||
ch.setLevel(logging.INFO)
|
||||
formatter = \
|
||||
logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
ch.setFormatter(formatter)
|
||||
root.addHandler(ch)
|
||||
|
||||
last_chat_id = 0
|
||||
# Enable Logging
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# We use this var to save the last chat id, so we can reply to it
|
||||
last_chat_id = 0
|
||||
|
||||
# Command Handlers
|
||||
|
||||
# Define a few (command) handlers. These usually take the two arguments bot and
|
||||
# update. Error handlers also receive the raised TelegramError object in error.
|
||||
def start(bot, update):
|
||||
""" Answer in Telegram """
|
||||
bot.sendMessage(update.message.chat_id, text='Hi!')
|
||||
@@ -65,10 +65,11 @@ def unknown_command(bot, update):
|
||||
|
||||
|
||||
@run_async
|
||||
def message(bot, update):
|
||||
def message(bot, update, **kwargs):
|
||||
"""
|
||||
Example for an asynchronous handler. It's not guaranteed that replies will
|
||||
be in order when using @run_async.
|
||||
be in order when using @run_async. Also, you have to include **kwargs in
|
||||
your parameter list. The kwargs contain all optional parameters that are
|
||||
"""
|
||||
|
||||
sleep(2) # IO-heavy operation here
|
||||
@@ -76,15 +77,12 @@ def message(bot, update):
|
||||
update.message.text)
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
""" Print error to console """
|
||||
logger.warn('Update %s caused error %s' % (update, error))
|
||||
|
||||
|
||||
# These handlers are for updates of type str. We use them to react to inputs
|
||||
# on the command line interface
|
||||
def cli_reply(bot, update, args):
|
||||
"""
|
||||
For any update of type telegram.Update or str, you can get the argument
|
||||
list by appending args to the function parameters.
|
||||
For any update of type telegram.Update or str that contains a command, you
|
||||
can get the argument list by appending args to the function parameters.
|
||||
Here, we reply to the last active chat with the text after the command.
|
||||
"""
|
||||
if last_chat_id is not 0:
|
||||
@@ -96,6 +94,9 @@ def cli_noncommand(bot, update, update_queue):
|
||||
You can also get the update queue as an argument in any handler by
|
||||
appending it to the argument list. Be careful with this though.
|
||||
Here, we put the input string back into the queue, but as a command.
|
||||
|
||||
To learn more about those optional handler parameters, read:
|
||||
http://python-telegram-bot.readthedocs.org/en/latest/telegram.dispatcher.html
|
||||
"""
|
||||
update_queue.put('/%s' % update)
|
||||
|
||||
@@ -104,33 +105,44 @@ def unknown_cli_command(bot, update):
|
||||
logger.warn("Command not found: %s" % update)
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
""" Print error to console """
|
||||
logger.warn('Update %s caused error %s' % (update, error))
|
||||
|
||||
|
||||
def main():
|
||||
# Create the EventHandler and pass it your bot's token.
|
||||
token = 'token'
|
||||
updater = Updater(token, workers=2)
|
||||
token = 'TOKEN'
|
||||
updater = Updater(token, workers=10)
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dp = updater.dispatcher
|
||||
|
||||
# This is how we add handlers for Telegram messages
|
||||
dp.addTelegramCommandHandler("start", start)
|
||||
dp.addTelegramCommandHandler("help", help)
|
||||
dp.addUnknownTelegramCommandHandler(unknown_command)
|
||||
# Message handlers only receive updates that don't contain commands
|
||||
dp.addTelegramMessageHandler(message)
|
||||
# Regex handlers will receive all updates on which their regex matches
|
||||
dp.addTelegramRegexHandler('.*', any_message)
|
||||
|
||||
# String handlers work pretty much the same
|
||||
dp.addStringCommandHandler('reply', cli_reply)
|
||||
dp.addUnknownStringCommandHandler(unknown_cli_command)
|
||||
dp.addStringRegexHandler('[^/].*', cli_noncommand)
|
||||
|
||||
# All TelegramErrors are caught for you and delivered to the error
|
||||
# handler(s). Other types of Errors are not caught.
|
||||
dp.addErrorHandler(error)
|
||||
|
||||
# Start the Bot and store the update Queue, so we can insert updates
|
||||
update_queue = updater.start_polling(poll_interval=0.1, timeout=20)
|
||||
update_queue = updater.start_polling(poll_interval=0.1, timeout=10)
|
||||
|
||||
'''
|
||||
# Alternatively, run with webhook:
|
||||
updater.bot.setWebhook(webhook_url='https://example.com/%s' % token,
|
||||
certificate=open('cert.pem', 'wb'))
|
||||
certificate=open('cert.pem', 'rb'))
|
||||
|
||||
update_queue = updater.start_webhook('0.0.0.0',
|
||||
443,
|
||||
@@ -157,9 +169,9 @@ def main():
|
||||
updater.stop()
|
||||
break
|
||||
|
||||
# else, put the text into the update queue
|
||||
# else, put the text into the update queue to be handled by our handlers
|
||||
elif len(text) > 0:
|
||||
update_queue.put(text) # Put command into queue
|
||||
update_queue.put(text)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,36 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Simple Bot to reply to Telegram messages
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
This Bot uses the Updater class to handle the bot.
|
||||
|
||||
First, a few handler functions are defined. Then, those functions are passed to
|
||||
the Dispatcher and registered at their respective places.
|
||||
Then, the bot is started and the CLI-Loop is entered.
|
||||
Then, the bot is started and runs until we press Ctrl-C on the command line.
|
||||
|
||||
Usage:
|
||||
Basic Echobot example, repeats messages.
|
||||
Type 'stop' on the command line to stop the bot.
|
||||
Press Ctrl-C on the command line or send a signal to the process to stop the
|
||||
bot.
|
||||
"""
|
||||
|
||||
from telegram import Updater
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# Enable logging
|
||||
root = logging.getLogger()
|
||||
root.setLevel(logging.INFO)
|
||||
|
||||
ch = logging.StreamHandler(sys.stdout)
|
||||
ch.setLevel(logging.DEBUG)
|
||||
formatter = \
|
||||
logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
ch.setFormatter(formatter)
|
||||
root.addHandler(ch)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Command Handlers
|
||||
# Define a few command handlers. These usually take the two arguments bot and
|
||||
# update. Error handlers also receive the raised TelegramError object in error.
|
||||
def start(bot, update):
|
||||
bot.sendMessage(update.message.chat_id, text='Hi!')
|
||||
|
||||
@@ -61,14 +60,15 @@ def main():
|
||||
# on noncommand i.e message - echo the message on Telegram
|
||||
dp.addTelegramMessageHandler(echo)
|
||||
|
||||
# on error - print error to stdout
|
||||
# log all errors
|
||||
dp.addErrorHandler(error)
|
||||
|
||||
# Start the Bot
|
||||
updater.start_polling(timeout=5)
|
||||
updater.start_polling()
|
||||
|
||||
# Run the bot until the user presses Ctrl-C or the process receives SIGINT,
|
||||
# SIGTERM or SIGABRT
|
||||
# Run the bot until the you presses Ctrl-C or the process receives SIGINT,
|
||||
# SIGTERM or SIGABRT. This should be used most of the time, since
|
||||
# start_polling() is non-blocking and will stop the bot gracefully.
|
||||
updater.idle()
|
||||
|
||||
if __name__ == '__main__':
|
||||
@@ -2,21 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Simple Bot to reply to Telegram messages
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
import logging
|
||||
import telegram
|
||||
@@ -2,23 +2,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Robô Ed Telegram Bot
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
|
||||
__author__ = 'leandrotoledodesouza@gmail.com'
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
import logging
|
||||
import telegram
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Simple Bot to send timed Telegram messages
|
||||
# This program is dedicated to the public domain under the CC0 license.
|
||||
|
||||
"""
|
||||
This Bot uses the Updater class to handle the bot and the JobQueue to send
|
||||
timed messages.
|
||||
|
||||
First, a few handler functions are defined. Then, those functions are passed to
|
||||
the Dispatcher and registered at their respective places.
|
||||
Then, the bot is started and runs until we press Ctrl-C on the command line.
|
||||
|
||||
Usage:
|
||||
Basic Alarm Bot example, sends a message after a set time.
|
||||
Press Ctrl-C on the command line or send a signal to the process to stop the
|
||||
bot.
|
||||
"""
|
||||
|
||||
from telegram import Updater
|
||||
import logging
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
job_queue = None
|
||||
|
||||
|
||||
# Define a few command handlers. These usually take the two arguments bot and
|
||||
# update. Error handlers also receive the raised TelegramError object in error.
|
||||
def start(bot, update):
|
||||
bot.sendMessage(update.message.chat_id, text='Hi! Use /set <seconds> to '
|
||||
'set a timer')
|
||||
|
||||
|
||||
def set(bot, update, args):
|
||||
""" Adds a job to the queue """
|
||||
chat_id = update.message.chat_id
|
||||
try:
|
||||
# args[0] should contain the time for the timer in seconds
|
||||
due = int(args[0])
|
||||
|
||||
def alarm(bot):
|
||||
""" Inner function to send the alarm message """
|
||||
bot.sendMessage(chat_id, text='Beep!')
|
||||
|
||||
# Add job to queue
|
||||
job_queue.put(alarm, due, repeat=False)
|
||||
bot.sendMessage(chat_id, text='Timer successfully set!')
|
||||
|
||||
except IndexError:
|
||||
bot.sendMessage(chat_id, text='Usage: /set <seconds>')
|
||||
except ValueError:
|
||||
bot.sendMessage(chat_id, text='Usage: /set <seconds>')
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logger.warn('Update "%s" caused error "%s"' % (update, error))
|
||||
|
||||
|
||||
def main():
|
||||
global job_queue
|
||||
|
||||
updater = Updater("148447715:AAFj2qskb3_sMMzlDhgTuoP7VAABNHpT0BU")
|
||||
job_queue = updater.job_queue
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dp = updater.dispatcher
|
||||
|
||||
# on different commands - answer in Telegram
|
||||
dp.addTelegramCommandHandler("start", start)
|
||||
dp.addTelegramCommandHandler("help", start)
|
||||
dp.addTelegramCommandHandler("set", set)
|
||||
|
||||
# log all errors
|
||||
dp.addErrorHandler(error)
|
||||
|
||||
# Start the Bot
|
||||
updater.start_polling()
|
||||
|
||||
# Block until the you presses Ctrl-C or the process receives SIGINT,
|
||||
# SIGTERM or SIGABRT. This should be used most of the time, since
|
||||
# start_polling() is non-blocking and will stop the bot gracefully.
|
||||
updater.idle()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -26,11 +26,11 @@ def requirements():
|
||||
|
||||
setup(
|
||||
name='python-telegram-bot',
|
||||
version='3.0.0',
|
||||
version='3.2.0',
|
||||
author='Leandro Toledo',
|
||||
author_email='leandrotoledodesouza@gmail.com',
|
||||
author_email='devs@python-telegram-bot.org',
|
||||
license='LGPLv3',
|
||||
url='https://github.com/leandrotoledo/python-telegram-bot',
|
||||
url='https://github.com/python-telegram-bot/python-telegram-bot',
|
||||
keywords='python telegram bot api wrapper',
|
||||
description='A Python wrapper around the Telegram Bot API',
|
||||
long_description=(read('README.rst')),
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
@@ -18,12 +19,12 @@
|
||||
|
||||
"""A library that provides a Python interface to the Telegram Bot API"""
|
||||
|
||||
__author__ = 'leandrotoledodesouza@gmail.com'
|
||||
__version__ = '3.0.0'
|
||||
__author__ = 'devs@python-telegram-bot.org'
|
||||
__version__ = '3.2.0'
|
||||
|
||||
from .base import TelegramObject
|
||||
from .user import User
|
||||
from .groupchat import GroupChat
|
||||
from .chat import Chat
|
||||
from .photosize import PhotoSize
|
||||
from .audio import Audio
|
||||
from .voice import Voice
|
||||
@@ -48,11 +49,12 @@ from .message import Message
|
||||
from .update import Update
|
||||
from .bot import Bot
|
||||
from .dispatcher import Dispatcher
|
||||
from .jobqueue import JobQueue
|
||||
from .updater import Updater
|
||||
|
||||
__all__ = ['Bot', 'Updater', 'Dispatcher', 'Emoji', 'TelegramError',
|
||||
'InputFile', 'ReplyMarkup', 'ForceReply', 'ReplyKeyboardHide',
|
||||
'ReplyKeyboardMarkup', 'UserProfilePhotos', 'ChatAction',
|
||||
'Location', 'Contact', 'Video', 'Sticker', 'Document', 'File',
|
||||
'Audio', 'PhotoSize', 'GroupChat', 'Update', 'ParseMode', 'Message',
|
||||
'User', 'TelegramObject', 'NullHandler', 'Voice']
|
||||
'Audio', 'PhotoSize', 'Chat', 'Update', 'ParseMode', 'Message',
|
||||
'User', 'TelegramObject', 'NullHandler', 'Voice', 'JobQueue']
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+22
-14
@@ -2,7 +2,8 @@
|
||||
# pylint: disable=E0611,E0213,E1102,C0103,E1101,W0613,R0913,R0904
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
@@ -52,7 +53,7 @@ class Bot(TelegramObject):
|
||||
def __init__(self,
|
||||
token,
|
||||
base_url=None):
|
||||
self.token = token
|
||||
self.token = self._valid_token(token)
|
||||
|
||||
if base_url is None:
|
||||
self.base_url = 'https://api.telegram.org/bot%s' % self.token
|
||||
@@ -191,8 +192,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - telegram.User or
|
||||
telegram.GroupChat id.
|
||||
Unique identifier for the message recipient - telegram.Chat id.
|
||||
parse_mode:
|
||||
Send Markdown, if you want Telegram apps to show bold, italic and
|
||||
inline URLs in your bot's message. For the moment, only Telegram
|
||||
@@ -234,10 +234,10 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
from_chat_id:
|
||||
Unique identifier for the chat where the original message was sent
|
||||
- User or GroupChat id.
|
||||
- Chat id.
|
||||
message_id:
|
||||
Unique message identifier.
|
||||
|
||||
@@ -268,7 +268,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
photo:
|
||||
Photo to send. You can either pass a file_id as String to resend a
|
||||
photo that is already on the Telegram servers, or upload a new
|
||||
@@ -319,7 +319,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
audio:
|
||||
Audio file to send. You can either pass a file_id as String to
|
||||
resend an audio that is already on the Telegram servers, or upload
|
||||
@@ -366,7 +366,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
document:
|
||||
File to send. You can either pass a file_id as String to resend a
|
||||
file that is already on the Telegram servers, or upload a new file
|
||||
@@ -405,7 +405,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
sticker:
|
||||
Sticker to send. You can either pass a file_id as String to resend
|
||||
a sticker that is already on the Telegram servers, or upload a new
|
||||
@@ -441,7 +441,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
video:
|
||||
Video to send. You can either pass a file_id as String to resend a
|
||||
video that is already on the Telegram servers, or upload a new
|
||||
@@ -490,7 +490,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
voice:
|
||||
Audio file to send. You can either pass a file_id as String to
|
||||
resend an audio that is already on the Telegram servers, or upload
|
||||
@@ -529,7 +529,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
latitude:
|
||||
Latitude of location.
|
||||
longitude:
|
||||
@@ -565,7 +565,7 @@ class Bot(TelegramObject):
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
Unique identifier for the message recipient - Chat id.
|
||||
action:
|
||||
Type of action to broadcast. Choose one, depending on what the user
|
||||
is about to receive:
|
||||
@@ -745,3 +745,11 @@ class Bot(TelegramObject):
|
||||
def __reduce__(self):
|
||||
return (self.__class__, (self.token,
|
||||
self.base_url.replace(self.token, '')))
|
||||
|
||||
@staticmethod
|
||||
def _valid_token(token):
|
||||
"""a very basic validation on token"""
|
||||
left, sep, _right = token.partition(':')
|
||||
if (not sep) or (not left.isdigit()) or (len(left) < 3):
|
||||
raise TelegramError('Invalid token')
|
||||
return token
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
# pylint: disable=C0103,W0622
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
@@ -17,22 +18,25 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram GroupChat"""
|
||||
"""This module contains a object that represents a Telegram Chat"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class GroupChat(TelegramObject):
|
||||
"""This object represents a Telegram GroupChat.
|
||||
class Chat(TelegramObject):
|
||||
"""This object represents a Telegram Chat.
|
||||
|
||||
Attributes:
|
||||
id (int):
|
||||
title (str):
|
||||
type (str):
|
||||
type (str): Can be 'private', 'group', 'supergroup' or 'channel'
|
||||
title (str): Title, for channels and group chats
|
||||
username (str): Username, for private chats and channels if available
|
||||
first_name (str): First name of the other party in a private chat
|
||||
last_name (str): Last name of the other party in a private chat
|
||||
|
||||
Args:
|
||||
id (int):
|
||||
title (str):
|
||||
type (str):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
@@ -41,24 +45,27 @@ class GroupChat(TelegramObject):
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
title,
|
||||
type,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.id = int(id)
|
||||
self.title = title
|
||||
self.type = type
|
||||
# Optionals
|
||||
self.type = kwargs.get('type', '')
|
||||
self.title = kwargs.get('title', '')
|
||||
self.username = kwargs.get('username', '')
|
||||
self.first_name = kwargs.get('first_name', '')
|
||||
self.last_name = kwargs.get('last_name', '')
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
data (dict):
|
||||
|
||||
Returns:
|
||||
telegram.GroupChat:
|
||||
telegram.Chat:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return GroupChat(**data)
|
||||
return Chat(**data)
|
||||
@@ -2,7 +2,8 @@
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+126
-82
@@ -1,4 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2016
|
||||
# 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 Dispatcher class.
|
||||
@@ -21,7 +39,9 @@ async_lock = Lock()
|
||||
|
||||
def run_async(func):
|
||||
"""
|
||||
Function decorator that will run the function in a new thread.
|
||||
Function decorator that will run the function in a new thread. A function
|
||||
decorated with this will have to include **kwargs in their parameter list,
|
||||
which will contain all optional parameters.
|
||||
|
||||
Args:
|
||||
func (function): The function to run in the thread.
|
||||
@@ -31,24 +51,24 @@ def run_async(func):
|
||||
"""
|
||||
|
||||
@wraps(func)
|
||||
def pooled(*args, **kwargs):
|
||||
def pooled(*pargs, **kwargs):
|
||||
"""
|
||||
A wrapper to run a thread in a thread pool
|
||||
"""
|
||||
global running_async, async_lock
|
||||
result = func(*args, **kwargs)
|
||||
result = func(*pargs, **kwargs)
|
||||
semaphore.release()
|
||||
with async_lock:
|
||||
running_async -= 1
|
||||
return result
|
||||
|
||||
@wraps(func)
|
||||
def async_func(*args, **kwargs):
|
||||
def async_func(*pargs, **kwargs):
|
||||
"""
|
||||
A wrapper to run a function in a thread
|
||||
"""
|
||||
global running_async, async_lock
|
||||
thread = Thread(target=pooled, args=args, kwargs=kwargs)
|
||||
thread = Thread(target=pooled, args=pargs, kwargs=kwargs)
|
||||
semaphore.acquire()
|
||||
with async_lock:
|
||||
running_async += 1
|
||||
@@ -61,33 +81,49 @@ def run_async(func):
|
||||
class Dispatcher:
|
||||
"""
|
||||
This class dispatches all kinds of updates to its registered handlers.
|
||||
A handler is a function that usually takes the following parameters
|
||||
|
||||
A handler is a function that usually takes the following parameters:
|
||||
bot: The telegram.Bot instance that received the message
|
||||
update: The update that should be handled by the handler
|
||||
bot:
|
||||
The telegram.Bot instance that received the message
|
||||
update:
|
||||
The update that should be handled by the handler
|
||||
|
||||
Error handlers take an additional parameter:
|
||||
error: The TelegramError instance that was raised during processing the
|
||||
Error handlers take an additional parameter
|
||||
|
||||
error:
|
||||
The TelegramError instance that was raised during processing the
|
||||
update
|
||||
|
||||
All handlers, except error handlers, can also request more information by
|
||||
appending one or more of the following arguments in their argument list for
|
||||
convenience:
|
||||
update_queue: The Queue instance which contains all new updates and is
|
||||
convenience
|
||||
|
||||
update_queue:
|
||||
The Queue instance which contains all new updates and is
|
||||
processed by the Dispatcher. Be careful with this - you might
|
||||
create an infinite loop.
|
||||
args: If the update is an instance str or telegram.Update, this will be
|
||||
args:
|
||||
If the update is an instance str or telegram.Update, this will be
|
||||
a list that contains the content of the message split on spaces,
|
||||
except the first word (usually the command).
|
||||
Example: '/add item1 item2 item3' -> ['item1', 'item2', 'item3']
|
||||
For other updates, args will be None
|
||||
|
||||
Attributes:
|
||||
For regex-based handlers, you can also request information about the match.
|
||||
For all other handlers, these will be None
|
||||
|
||||
groups:
|
||||
A tuple that contains the result of
|
||||
re.match(matcher, ...).groups()
|
||||
groupdict:
|
||||
A dictionary that contains the result of
|
||||
re.match(matcher, ...).groupdict()
|
||||
|
||||
Args:
|
||||
bot (telegram.Bot): The bot object that should be passed to the
|
||||
handlers update_queue (queue.Queue): The synchronized queue that will
|
||||
contain the updates.
|
||||
handlers
|
||||
update_queue (queue.Queue): The synchronized queue that will
|
||||
contain the updates.
|
||||
"""
|
||||
def __init__(self, bot, update_queue, workers=4):
|
||||
self.bot = bot
|
||||
@@ -103,6 +139,7 @@ class Dispatcher:
|
||||
self.error_handlers = []
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.running = False
|
||||
self.__lock = Lock()
|
||||
|
||||
global semaphore
|
||||
if not semaphore:
|
||||
@@ -123,37 +160,48 @@ class Dispatcher:
|
||||
the update queue.
|
||||
"""
|
||||
|
||||
self.running = True
|
||||
self.logger.info('Dispatcher thread started')
|
||||
self.__lock.acquire()
|
||||
if not self.running:
|
||||
self.running = True
|
||||
self.__lock.release()
|
||||
self.logger.info('Dispatcher thread started')
|
||||
|
||||
while True:
|
||||
update = None
|
||||
while True:
|
||||
update = None
|
||||
|
||||
try:
|
||||
# Pop update from update queue.
|
||||
# Blocks if no updates are available.
|
||||
update = self.update_queue.get()
|
||||
try:
|
||||
# Pop update from update queue.
|
||||
# Blocks if no updates are available.
|
||||
update = self.update_queue.get()
|
||||
|
||||
if type(update) is self._Stop:
|
||||
break
|
||||
if type(update) is self._Stop:
|
||||
break
|
||||
|
||||
self.processUpdate(update)
|
||||
self.logger.debug('Processed Update: %s' % update)
|
||||
self.processUpdate(update)
|
||||
self.logger.debug('Processed Update: %s' % update)
|
||||
|
||||
# Dispatch any errors
|
||||
except TelegramError as te:
|
||||
self.logger.warn("Error was raised while processing Update.")
|
||||
self.dispatchError(update, te)
|
||||
# Dispatch any errors
|
||||
except TelegramError as te:
|
||||
self.logger.warn("Error was raised while processing "
|
||||
"Update.")
|
||||
self.dispatchError(update, te)
|
||||
|
||||
# All other errors should not stop the thread, just print them
|
||||
except:
|
||||
self.logger.exception("An uncaught error was raised while "
|
||||
"processing an update")
|
||||
else:
|
||||
self.__lock.release()
|
||||
self.logger.info('Dispatcher thread stopped')
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops the thread
|
||||
"""
|
||||
if self.running:
|
||||
self.running = False
|
||||
self.update_queue.put(self._Stop())
|
||||
with self.__lock:
|
||||
if self.running:
|
||||
self.running = False
|
||||
self.update_queue.put(self._Stop())
|
||||
|
||||
def processUpdate(self, update):
|
||||
"""
|
||||
@@ -176,7 +224,7 @@ class Dispatcher:
|
||||
self.dispatchStringCommand(update)
|
||||
handled = True
|
||||
elif type(update) is str:
|
||||
self.dispatchStringRegex(update)
|
||||
self.dispatchRegex(update)
|
||||
handled = True
|
||||
|
||||
# An error happened while polling
|
||||
@@ -186,7 +234,7 @@ class Dispatcher:
|
||||
|
||||
# Telegram update (regex)
|
||||
if isinstance(update, Update):
|
||||
self.dispatchTelegramRegex(update)
|
||||
self.dispatchRegex(update)
|
||||
handled = True
|
||||
|
||||
# Telegram update (command)
|
||||
@@ -460,25 +508,30 @@ class Dispatcher:
|
||||
else:
|
||||
self.dispatchTo(self.unknown_telegram_command_handlers, update)
|
||||
|
||||
def dispatchTelegramRegex(self, update):
|
||||
def dispatchRegex(self, update):
|
||||
"""
|
||||
Dispatches an update to all regex handlers that match the message
|
||||
string.
|
||||
Dispatches an update to all string or telegram regex handlers that
|
||||
match the string/message content.
|
||||
|
||||
Args:
|
||||
command (str): The command keyword
|
||||
update (telegram.Update): The Telegram update that contains the
|
||||
command
|
||||
update (str, Update): The update that should be checked for matches
|
||||
"""
|
||||
|
||||
matching_handlers = []
|
||||
if isinstance(update, Update):
|
||||
handlers = self.telegram_regex_handlers
|
||||
to_match = update.message.text
|
||||
elif isinstance(update, str):
|
||||
handlers = self.string_regex_handlers
|
||||
to_match = update
|
||||
|
||||
for matcher in self.telegram_regex_handlers:
|
||||
if match(matcher, update.message.text):
|
||||
for handler in self.telegram_regex_handlers[matcher]:
|
||||
matching_handlers.append(handler)
|
||||
|
||||
self.dispatchTo(matching_handlers, update)
|
||||
for matcher in handlers:
|
||||
m = match(matcher, to_match)
|
||||
if m:
|
||||
for handler in handlers[matcher]:
|
||||
self.call_handler(handler,
|
||||
update,
|
||||
groups=m.groups(),
|
||||
groupdict=m.groupdict())
|
||||
|
||||
def dispatchStringCommand(self, update):
|
||||
"""
|
||||
@@ -495,26 +548,6 @@ class Dispatcher:
|
||||
else:
|
||||
self.dispatchTo(self.unknown_string_command_handlers, update)
|
||||
|
||||
def dispatchStringRegex(self, update):
|
||||
"""
|
||||
Dispatches an update to all string regex handlers that match the
|
||||
string.
|
||||
|
||||
Args:
|
||||
command (str): The command keyword
|
||||
update (telegram.Update): The Telegram update that contains the
|
||||
command
|
||||
"""
|
||||
|
||||
matching_handlers = []
|
||||
|
||||
for matcher in self.string_regex_handlers:
|
||||
if match(matcher, update):
|
||||
for handler in self.string_regex_handlers[matcher]:
|
||||
matching_handlers.append(handler)
|
||||
|
||||
self.dispatchTo(matching_handlers, update)
|
||||
|
||||
def dispatchType(self, update):
|
||||
"""
|
||||
Dispatches an update of any type.
|
||||
@@ -526,9 +559,6 @@ class Dispatcher:
|
||||
for t in self.type_handlers:
|
||||
if isinstance(update, t):
|
||||
self.dispatchTo(self.type_handlers[t], update)
|
||||
else:
|
||||
self.dispatchError(update, TelegramError(
|
||||
"Received update of unknown type %s" % type(update)))
|
||||
|
||||
def dispatchTelegramMessage(self, update):
|
||||
"""
|
||||
@@ -553,7 +583,7 @@ class Dispatcher:
|
||||
for handler in self.error_handlers:
|
||||
handler(self.bot, update, error)
|
||||
|
||||
def dispatchTo(self, handlers, update):
|
||||
def dispatchTo(self, handlers, update, **kwargs):
|
||||
"""
|
||||
Dispatches an update to a list of handlers.
|
||||
|
||||
@@ -563,9 +593,9 @@ class Dispatcher:
|
||||
"""
|
||||
|
||||
for handler in handlers:
|
||||
self.call_handler(handler, update)
|
||||
self.call_handler(handler, update, **kwargs)
|
||||
|
||||
def call_handler(self, handler, update):
|
||||
def call_handler(self, handler, update, **kwargs):
|
||||
"""
|
||||
Calls an update handler. Checks the handler for keyword arguments and
|
||||
fills them, if possible.
|
||||
@@ -574,13 +604,21 @@ class Dispatcher:
|
||||
handler (function): An update handler function
|
||||
update (any): An update
|
||||
"""
|
||||
kwargs = {}
|
||||
|
||||
target_kwargs = {}
|
||||
fargs = getargspec(handler).args
|
||||
|
||||
if 'update_queue' in fargs:
|
||||
kwargs['update_queue'] = self.update_queue
|
||||
'''
|
||||
async handlers will receive all optional arguments, since we can't
|
||||
their argument list.
|
||||
'''
|
||||
|
||||
if 'args' in fargs:
|
||||
is_async = 'pargs' == getargspec(handler).varargs
|
||||
|
||||
if is_async or 'update_queue' in fargs:
|
||||
target_kwargs['update_queue'] = self.update_queue
|
||||
|
||||
if is_async or 'args' in fargs:
|
||||
if isinstance(update, Update):
|
||||
args = update.message.text.split(' ')[1:]
|
||||
elif isinstance(update, str):
|
||||
@@ -588,6 +626,12 @@ class Dispatcher:
|
||||
else:
|
||||
args = None
|
||||
|
||||
kwargs['args'] = args
|
||||
target_kwargs['args'] = args
|
||||
|
||||
handler(self.bot, update, **kwargs)
|
||||
if is_async or 'groups' in fargs:
|
||||
target_kwargs['groups'] = kwargs.get('groups', None)
|
||||
|
||||
if is_async or 'groupdict' in fargs:
|
||||
target_kwargs['groupdict'] = kwargs.get('groupdict', None)
|
||||
|
||||
handler(self.bot, update, **target_kwargs)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@
|
||||
# pylint: disable=C0103,C0301,R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+28
-8
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
@@ -18,7 +19,22 @@
|
||||
|
||||
"""This module contains a object that represents a Telegram Error"""
|
||||
|
||||
import re
|
||||
|
||||
def _lstrip_str(in_s, lstr):
|
||||
"""
|
||||
Args:
|
||||
in_s (str): in string
|
||||
lstr (str): substr to strip from left side
|
||||
|
||||
Returns:
|
||||
str:
|
||||
|
||||
"""
|
||||
if in_s.startswith(lstr):
|
||||
res = in_s[len(lstr):]
|
||||
else:
|
||||
res = in_s
|
||||
return res
|
||||
|
||||
|
||||
class TelegramError(Exception):
|
||||
@@ -26,16 +42,20 @@ class TelegramError(Exception):
|
||||
|
||||
def __init__(self, message):
|
||||
"""
|
||||
Args:
|
||||
message (str):
|
||||
|
||||
Returns:
|
||||
str:
|
||||
|
||||
"""
|
||||
super(TelegramError, self).__init__()
|
||||
|
||||
api_error = re.match(r'^Error: (?P<message>.*)', message)
|
||||
if api_error:
|
||||
self.message = api_error.group('message').capitalize()
|
||||
else:
|
||||
self.message = message
|
||||
msg = _lstrip_str(message, 'Error: ')
|
||||
msg = _lstrip_str(msg, '[Error]: ')
|
||||
if msg != message:
|
||||
# api_error - capitalize the msg...
|
||||
msg = msg.capitalize()
|
||||
self.message = msg
|
||||
|
||||
def __str__(self):
|
||||
return '%s' % (self.message)
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
@@ -74,7 +75,7 @@ class File(TelegramObject):
|
||||
url = self.file_path
|
||||
|
||||
if custom_path:
|
||||
filename = basename(custom_path)
|
||||
filename = custom_path
|
||||
else:
|
||||
filename = basename(url)
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
# pylint: disable=W0622,E0611
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
@@ -35,7 +36,7 @@ from telegram import TelegramError
|
||||
|
||||
DEFAULT_MIME_TYPE = 'application/octet-stream'
|
||||
USER_AGENT = 'Python Telegram Bot' \
|
||||
' (https://github.com/leandrotoledo/python-telegram-bot)'
|
||||
' (https://github.com/python-telegram-bot/python-telegram-bot)'
|
||||
|
||||
|
||||
class InputFile(object):
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2016
|
||||
# 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 JobQueue
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
from threading import Thread, Lock
|
||||
|
||||
try:
|
||||
from queue import PriorityQueue
|
||||
except ImportError:
|
||||
from Queue import PriorityQueue
|
||||
|
||||
|
||||
class JobQueue(object):
|
||||
"""
|
||||
This class allows you to periodically perform tasks with the bot.
|
||||
|
||||
Attributes:
|
||||
tick_interval (float):
|
||||
queue (PriorityQueue):
|
||||
bot (Bot):
|
||||
running (bool):
|
||||
|
||||
Args:
|
||||
bot (Bot): The bot instance that should be passed to the jobs
|
||||
|
||||
Keyword Args:
|
||||
tick_interval (Optional[float]): The interval this queue should check
|
||||
the newest task in seconds. Defaults to 1.0
|
||||
"""
|
||||
|
||||
def __init__(self, bot, tick_interval=1.0):
|
||||
self.tick_interval = tick_interval
|
||||
self.queue = PriorityQueue()
|
||||
self.bot = bot
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.__lock = Lock()
|
||||
self.running = False
|
||||
|
||||
def put(self,
|
||||
run,
|
||||
interval,
|
||||
repeat=True,
|
||||
next_t=None,
|
||||
prevent_autostart=False):
|
||||
"""
|
||||
Queue a new job. If the JobQueue is not running, it will be started.
|
||||
|
||||
Args:
|
||||
run (function): A function that takes the parameter `bot`
|
||||
interval (float): The interval in seconds in which `run` should be
|
||||
executed
|
||||
repeat (Optional[bool]): If `False`, job will only be executed once
|
||||
next_t (Optional[float]): Time in seconds in which run should be
|
||||
executed first. Defaults to `interval`
|
||||
prevent_autostart (Optional[bool]): If `True`, the job queue will
|
||||
not be started automatically if it is not running.
|
||||
"""
|
||||
name = run.__name__
|
||||
|
||||
job = JobQueue.Job()
|
||||
job.run = run
|
||||
job.interval = interval
|
||||
job.name = name
|
||||
job.repeat = repeat
|
||||
|
||||
if next_t is None:
|
||||
next_t = interval
|
||||
|
||||
next_t += time.time()
|
||||
|
||||
self.logger.debug("Putting a %s with t=%f" % (job.name, next_t))
|
||||
self.queue.put((next_t, job))
|
||||
|
||||
if not self.running and not prevent_autostart:
|
||||
self.logger.info("Auto-starting JobQueue")
|
||||
self.start()
|
||||
|
||||
def tick(self):
|
||||
"""
|
||||
Run all jobs that are due and re-enqueue them with their interval
|
||||
"""
|
||||
now = time.time()
|
||||
|
||||
self.logger.debug("Ticking jobs with t=%f" % now)
|
||||
while not self.queue.empty():
|
||||
t, j = self.queue.queue[0]
|
||||
self.logger.debug("Peeked at %s with t=%f" % (j.name, t))
|
||||
|
||||
if t < now:
|
||||
self.queue.get()
|
||||
self.logger.info("Running job %s" % j.name)
|
||||
try:
|
||||
j.run(self.bot)
|
||||
except:
|
||||
self.logger.exception("An uncaught error was raised while "
|
||||
"executing job %s" % j.name)
|
||||
if j.repeat:
|
||||
self.put(j.run, j.interval)
|
||||
continue
|
||||
|
||||
self.logger.debug("Next task isn't due yet. Finished!")
|
||||
break
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starts the job_queue thread.
|
||||
"""
|
||||
self.__lock.acquire()
|
||||
if not self.running:
|
||||
self.running = True
|
||||
self.__lock.release()
|
||||
job_queue_thread = Thread(target=self._start,
|
||||
name="job_queue")
|
||||
job_queue_thread.start()
|
||||
self.logger.info('Job Queue thread started')
|
||||
else:
|
||||
self.__lock.release()
|
||||
|
||||
def _start(self):
|
||||
"""
|
||||
Thread target of thread 'job_queue'. Runs in background and performs
|
||||
ticks on the job queue.
|
||||
"""
|
||||
while self.running:
|
||||
self.tick()
|
||||
time.sleep(self.tick_interval)
|
||||
|
||||
self.logger.info('Job Queue thread stopped')
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops the thread
|
||||
"""
|
||||
with self.__lock:
|
||||
self.running = False
|
||||
|
||||
class Job(object):
|
||||
""" Inner class that represents a job """
|
||||
interval = None
|
||||
name = None
|
||||
repeat = None
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
def __lt__(self, other):
|
||||
return False
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+12
-8
@@ -2,7 +2,8 @@
|
||||
# pylint: disable=R0902,R0912,R0913
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
@@ -22,7 +23,7 @@
|
||||
from datetime import datetime
|
||||
from time import mktime
|
||||
|
||||
from telegram import (Audio, Contact, Document, GroupChat, Location, PhotoSize,
|
||||
from telegram import (Audio, Contact, Document, Chat, Location, PhotoSize,
|
||||
Sticker, TelegramObject, User, Video, Voice)
|
||||
|
||||
|
||||
@@ -60,7 +61,7 @@ class Message(TelegramObject):
|
||||
message_id (int):
|
||||
from_user (:class:`telegram.User`):
|
||||
date (:class:`datetime.datetime`):
|
||||
chat (:class:`telegram.User` or :class:`telegram.GroupChat`):
|
||||
chat (:class:`telegram.Chat`):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
@@ -116,6 +117,12 @@ class Message(TelegramObject):
|
||||
self.new_chat_photo = kwargs.get('new_chat_photo')
|
||||
self.delete_chat_photo = bool(kwargs.get('delete_chat_photo', False))
|
||||
self.group_chat_created = bool(kwargs.get('group_chat_created', False))
|
||||
self.supergroup_chat_created = bool(kwargs.get(
|
||||
'supergroup_chat_created', False))
|
||||
self.migrate_to_chat_id = int(kwargs.get('migrate_to_chat_id', 0))
|
||||
self.migrate_from_chat_id = int(kwargs.get('migrate_from_chat_id', 0))
|
||||
self.channel_chat_created = bool(kwargs.get('channel_chat_created',
|
||||
False))
|
||||
|
||||
@property
|
||||
def chat_id(self):
|
||||
@@ -126,7 +133,7 @@ class Message(TelegramObject):
|
||||
def de_json(data):
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
data (dict):
|
||||
|
||||
Returns:
|
||||
telegram.Message:
|
||||
@@ -136,10 +143,7 @@ class Message(TelegramObject):
|
||||
|
||||
data['from_user'] = User.de_json(data.get('from'))
|
||||
data['date'] = datetime.fromtimestamp(data['date'])
|
||||
if 'first_name' in data.get('chat', ''):
|
||||
data['chat'] = User.de_json(data.get('chat'))
|
||||
elif 'title' in data.get('chat', ''):
|
||||
data['chat'] = GroupChat.de_json(data.get('chat'))
|
||||
data['chat'] = Chat.de_json(data.get('chat'))
|
||||
data['forward_from'] = \
|
||||
User.de_json(data.get('forward_from'))
|
||||
data['forward_date'] = \
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+105
-52
@@ -1,4 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2016
|
||||
# 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 Updater, which tries to make creating Telegram
|
||||
@@ -7,12 +25,12 @@ Bots intuitive!
|
||||
import logging
|
||||
import os
|
||||
import ssl
|
||||
from threading import Thread
|
||||
from threading import Thread, Lock
|
||||
from time import sleep
|
||||
import subprocess
|
||||
from signal import signal, SIGINT, SIGTERM, SIGABRT
|
||||
from telegram import (Bot, TelegramError, dispatcher, Dispatcher,
|
||||
NullHandler)
|
||||
NullHandler, JobQueue)
|
||||
from telegram.utils.webhookhandler import (WebhookServer, WebhookHandler)
|
||||
|
||||
# Adjust for differences in Python versions
|
||||
@@ -47,16 +65,33 @@ class Updater:
|
||||
Attributes:
|
||||
|
||||
Args:
|
||||
token (str): The bots token given by the @BotFather
|
||||
token (Optional[str]): The bot's token given by the @BotFather
|
||||
base_url (Optional[str]):
|
||||
workers (Optional[int]): Amount of threads in the thread pool for
|
||||
functions decorated with @run_async
|
||||
bot (Optional[Bot]):
|
||||
|
||||
Raises:
|
||||
ValueError: If both `token` and `bot` are passed or none of them.
|
||||
"""
|
||||
|
||||
def __init__(self, token, base_url=None, workers=4):
|
||||
def __init__(self,
|
||||
token=None,
|
||||
base_url=None,
|
||||
workers=4,
|
||||
bot=None,
|
||||
job_queue_tick_interval=1.0):
|
||||
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')
|
||||
|
||||
self.bot = Bot(token, base_url)
|
||||
if bot is not None:
|
||||
self.bot = bot
|
||||
else:
|
||||
self.bot = Bot(token, base_url)
|
||||
self.update_queue = Queue()
|
||||
self.job_queue = JobQueue(self.bot, job_queue_tick_interval)
|
||||
self.dispatcher = Dispatcher(self.bot, self.update_queue,
|
||||
workers=workers)
|
||||
self.last_update_id = 0
|
||||
@@ -64,14 +99,15 @@ class Updater:
|
||||
self.running = False
|
||||
self.is_idle = False
|
||||
self.httpd = None
|
||||
self.__lock = Lock()
|
||||
|
||||
def start_polling(self, poll_interval=1.0, timeout=10, network_delay=2):
|
||||
def start_polling(self, poll_interval=0.0, timeout=10, network_delay=2):
|
||||
"""
|
||||
Starts polling updates from Telegram.
|
||||
|
||||
Args:
|
||||
poll_interval (Optional[float]): Time to wait between polling
|
||||
updates from Telegram in seconds. Default is 1.0
|
||||
updates from Telegram in seconds. Default is 0.0
|
||||
timeout (Optional[float]): Passed to Bot.getUpdates
|
||||
network_delay (Optional[float]): Passed to Bot.getUpdates
|
||||
|
||||
@@ -79,22 +115,25 @@ class Updater:
|
||||
Queue: The update queue that can be filled from the main thread
|
||||
"""
|
||||
|
||||
# Create Thread objects
|
||||
dispatcher_thread = Thread(target=self.dispatcher.start,
|
||||
name="dispatcher")
|
||||
event_handler_thread = Thread(target=self._start_polling,
|
||||
name="updater",
|
||||
args=(poll_interval, timeout,
|
||||
network_delay))
|
||||
with self.__lock:
|
||||
if not self.running:
|
||||
self.running = True
|
||||
|
||||
self.running = True
|
||||
# Create Thread objects
|
||||
dispatcher_thread = Thread(target=self.dispatcher.start,
|
||||
name="dispatcher")
|
||||
updater_thread = Thread(target=self._start_polling,
|
||||
name="updater",
|
||||
args=(poll_interval,
|
||||
timeout,
|
||||
network_delay))
|
||||
|
||||
# Start threads
|
||||
dispatcher_thread.start()
|
||||
event_handler_thread.start()
|
||||
# Start threads
|
||||
dispatcher_thread.start()
|
||||
updater_thread.start()
|
||||
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
|
||||
def start_webhook(self,
|
||||
listen='127.0.0.1',
|
||||
@@ -120,21 +159,27 @@ class Updater:
|
||||
Queue: The update queue that can be filled from the main thread
|
||||
"""
|
||||
|
||||
# Create Thread objects
|
||||
dispatcher_thread = Thread(target=self.dispatcher.start,
|
||||
name="dispatcher")
|
||||
event_handler_thread = Thread(target=self._start_webhook,
|
||||
name="updater",
|
||||
args=(listen, port, url_path, cert, key))
|
||||
with self.__lock:
|
||||
if not self.running:
|
||||
self.running = True
|
||||
|
||||
self.running = True
|
||||
# Create Thread objects
|
||||
dispatcher_thread = Thread(target=self.dispatcher.start,
|
||||
name="dispatcher")
|
||||
updater_thread = Thread(target=self._start_webhook,
|
||||
name="updater",
|
||||
args=(listen,
|
||||
port,
|
||||
url_path,
|
||||
cert,
|
||||
key))
|
||||
|
||||
# Start threads
|
||||
dispatcher_thread.start()
|
||||
event_handler_thread.start()
|
||||
# Start threads
|
||||
dispatcher_thread.start()
|
||||
updater_thread.start()
|
||||
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
|
||||
def _start_polling(self, poll_interval, timeout, network_delay):
|
||||
"""
|
||||
@@ -175,9 +220,11 @@ class Updater:
|
||||
except URLError as e:
|
||||
self.logger.error("Error while getting Updates: %s" % e)
|
||||
# increase waiting times on subsequent errors up to 30secs
|
||||
if current_interval < 30:
|
||||
if current_interval == 0:
|
||||
current_interval = 1
|
||||
elif current_interval < 30:
|
||||
current_interval += current_interval / 2
|
||||
if current_interval > 30:
|
||||
elif current_interval > 30:
|
||||
current_interval = 30
|
||||
|
||||
self.logger.info('Updater thread stopped')
|
||||
@@ -217,26 +264,31 @@ class Updater:
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops the polling/webhook thread and the dispatcher
|
||||
Stops the polling/webhook thread, the dispatcher and the job queue
|
||||
"""
|
||||
self.logger.info('Stopping Updater and Dispatcher...')
|
||||
self.logger.debug('This might take a long time if you set a high value'
|
||||
' as polling timeout.')
|
||||
self.running = False
|
||||
|
||||
if self.httpd:
|
||||
self.logger.info(
|
||||
'Waiting for current webhook connection to be closed... '
|
||||
'Send a Telegram message to the bot to exit immediately.')
|
||||
self.httpd.shutdown()
|
||||
self.httpd = None
|
||||
self.job_queue.stop()
|
||||
with self.__lock:
|
||||
if self.running:
|
||||
self.running = False
|
||||
self.logger.info('Stopping Updater and Dispatcher...')
|
||||
self.logger.debug('This might take a long time if you set a '
|
||||
'high value as polling timeout.')
|
||||
|
||||
self.logger.debug("Requesting Dispatcher to stop...")
|
||||
self.dispatcher.stop()
|
||||
while dispatcher.running_async > 0:
|
||||
sleep(1)
|
||||
if self.httpd:
|
||||
self.logger.info(
|
||||
'Waiting for current webhook connection to be '
|
||||
'closed... Send a Telegram message to the bot to exit '
|
||||
'immediately.')
|
||||
self.httpd.shutdown()
|
||||
self.httpd = None
|
||||
|
||||
self.logger.debug("Dispatcher stopped.")
|
||||
self.logger.debug("Requesting Dispatcher to stop...")
|
||||
self.dispatcher.stop()
|
||||
while dispatcher.running_async > 0:
|
||||
sleep(1)
|
||||
|
||||
self.logger.debug("Dispatcher stopped.")
|
||||
|
||||
def signal_handler(self, signum, frame):
|
||||
self.is_idle = False
|
||||
@@ -244,12 +296,13 @@ class Updater:
|
||||
|
||||
def idle(self, stop_signals=(SIGINT, SIGTERM, SIGABRT)):
|
||||
"""
|
||||
Waits for the user to press Ctrl-C and stops the updater
|
||||
Blocks until one of the signals are received and stops the updater
|
||||
|
||||
Args:
|
||||
stop_signals: Iterable containing signals from the signal module
|
||||
that should be subscribed to. Updater.stop() will be called on
|
||||
receiving one of those signals.
|
||||
receiving one of those signals. Defaults to (SIGINT, SIGTERM,
|
||||
SIGABRT)
|
||||
"""
|
||||
for sig in stop_signals:
|
||||
signal(sig, self.signal_handler)
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
# pylint: disable=C0103,W0622
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+49
-31
@@ -2,7 +2,8 @@
|
||||
# pylint: disable=no-name-in-module,unused-import
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
@@ -19,6 +20,7 @@
|
||||
|
||||
"""This module contains methods to make POST and GET requests"""
|
||||
|
||||
import functools
|
||||
import json
|
||||
import socket
|
||||
from ssl import SSLError
|
||||
@@ -45,7 +47,11 @@ def _parse(json_data):
|
||||
Returns:
|
||||
A JSON parsed as Python dict with results.
|
||||
"""
|
||||
data = json.loads(json_data.decode())
|
||||
decoded_s = json_data.decode('utf-8')
|
||||
try:
|
||||
data = json.loads(decoded_s)
|
||||
except ValueError:
|
||||
raise TelegramError('Invalid server response')
|
||||
|
||||
if not data.get('ok') and data.get('description'):
|
||||
return data['description']
|
||||
@@ -53,6 +59,34 @@ def _parse(json_data):
|
||||
return data['result']
|
||||
|
||||
|
||||
def _try_except_req(func):
|
||||
"""Decorator for requests to handle known exceptions"""
|
||||
@functools.wraps(func)
|
||||
def decorator(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except HTTPError as error:
|
||||
if error.getcode() == 403:
|
||||
raise TelegramError('Unauthorized')
|
||||
if error.getcode() == 502:
|
||||
raise TelegramError('Bad Gateway')
|
||||
|
||||
try:
|
||||
message = _parse(error.read())
|
||||
except ValueError:
|
||||
message = 'Unknown HTTPError {0}'.format(error.getcode())
|
||||
|
||||
raise TelegramError(message)
|
||||
except (SSLError, socket.timeout) as error:
|
||||
if "operation timed out" in str(error):
|
||||
raise TelegramError("Timed out")
|
||||
|
||||
raise TelegramError(str(error))
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
@_try_except_req
|
||||
def get(url):
|
||||
"""Request an URL.
|
||||
Args:
|
||||
@@ -67,6 +101,7 @@ def get(url):
|
||||
return _parse(result)
|
||||
|
||||
|
||||
@_try_except_req
|
||||
def post(url,
|
||||
data,
|
||||
network_delay=2.):
|
||||
@@ -91,39 +126,22 @@ def post(url,
|
||||
else:
|
||||
timeout = None
|
||||
|
||||
try:
|
||||
if InputFile.is_inputfile(data):
|
||||
data = InputFile(data)
|
||||
request = Request(url,
|
||||
data=data.to_form(),
|
||||
headers=data.headers)
|
||||
else:
|
||||
data = json.dumps(data)
|
||||
request = Request(url,
|
||||
data=data.encode(),
|
||||
headers={'Content-Type': 'application/json'})
|
||||
if InputFile.is_inputfile(data):
|
||||
data = InputFile(data)
|
||||
request = Request(url,
|
||||
data=data.to_form(),
|
||||
headers=data.headers)
|
||||
else:
|
||||
data = json.dumps(data)
|
||||
request = Request(url,
|
||||
data=data.encode(),
|
||||
headers={'Content-Type': 'application/json'})
|
||||
|
||||
result = urlopen(request, timeout=timeout).read()
|
||||
except HTTPError as error:
|
||||
if error.getcode() == 403:
|
||||
raise TelegramError('Unauthorized')
|
||||
if error.getcode() == 502:
|
||||
raise TelegramError('Bad Gateway')
|
||||
|
||||
try:
|
||||
message = _parse(error.read())
|
||||
except ValueError:
|
||||
message = 'Unknown HTTPError'
|
||||
|
||||
raise TelegramError(message)
|
||||
except (SSLError, socket.timeout) as error:
|
||||
if "operation timed out" in str(error):
|
||||
raise TelegramError("Timed out")
|
||||
|
||||
raise TelegramError(str(error))
|
||||
result = urlopen(request, timeout=timeout).read()
|
||||
return _parse(result)
|
||||
|
||||
|
||||
@_try_except_req
|
||||
def download(url,
|
||||
filename):
|
||||
"""Download a file by its URL.
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# 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
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
+36
-2
@@ -2,7 +2,8 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -20,9 +21,14 @@
|
||||
"""This module contains a object that represents Tests for Telegram Bot"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
from datetime import datetime
|
||||
import sys
|
||||
|
||||
if sys.version_info[0:2] == (2, 6):
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
import unittest
|
||||
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
@@ -137,5 +143,33 @@ class BotTest(BaseTest, unittest.TestCase):
|
||||
self.assertTrue(self.is_json(upf.to_json()))
|
||||
self.assertEqual(upf.photos[0][0].file_size, 12421)
|
||||
|
||||
def _test_invalid_token(self, token):
|
||||
print('Testing invalid token: {0}'.format(token))
|
||||
self.assertRaisesRegexp(telegram.TelegramError, 'Invalid token', telegram.Bot, token)
|
||||
|
||||
def testInvalidToken1(self):
|
||||
self._test_invalid_token('123')
|
||||
|
||||
def testInvalidToken2(self):
|
||||
self._test_invalid_token('12a:')
|
||||
|
||||
def testInvalidToken3(self):
|
||||
self._test_invalid_token('12:')
|
||||
|
||||
def testUnauthToken(self):
|
||||
print('Testing unauthorized token')
|
||||
with self.assertRaisesRegexp(telegram.TelegramError, 'Unauthorized'):
|
||||
bot = telegram.Bot('1234:abcd1234')
|
||||
bot.getMe()
|
||||
|
||||
def testInvalidSrvResp(self):
|
||||
print('Testing invalid server response')
|
||||
with self.assertRaisesRegexp(telegram.TelegramError, 'Invalid server response'):
|
||||
# bypass the valid token check
|
||||
bot_cls = type('bot_cls', (telegram.Bot, ), {'_valid_token': lambda self, token: token})
|
||||
bot = bot_cls('12')
|
||||
bot.getMe()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -16,7 +17,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents Tests for Telegram GroupChat"""
|
||||
"""This module contains a object that represents Tests for Telegram Chat"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
@@ -27,8 +28,8 @@ import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class GroupChatTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram GroupChat."""
|
||||
class ChatTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Chat."""
|
||||
|
||||
def setUp(self):
|
||||
self.id = -28767330
|
||||
@@ -42,36 +43,36 @@ class GroupChatTest(BaseTest, unittest.TestCase):
|
||||
}
|
||||
|
||||
def test_group_chat_de_json_empty_json(self):
|
||||
"""Test GroupChat.de_json() method"""
|
||||
print('Testing GroupChat.de_json() - Empty JSON')
|
||||
"""Test Chat.de_json() method"""
|
||||
print('Testing Chat.de_json() - Empty JSON')
|
||||
|
||||
group_chat = telegram.GroupChat.de_json({})
|
||||
group_chat = telegram.Chat.de_json({})
|
||||
|
||||
self.assertEqual(group_chat, None)
|
||||
|
||||
def test_group_chat_de_json(self):
|
||||
"""Test GroupChat.de_json() method"""
|
||||
print('Testing GroupChat.de_json()')
|
||||
"""Test Chat.de_json() method"""
|
||||
print('Testing Chat.de_json()')
|
||||
|
||||
group_chat = telegram.GroupChat.de_json(self.json_dict)
|
||||
group_chat = telegram.Chat.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(group_chat.id, self.id)
|
||||
self.assertEqual(group_chat.title, self.title)
|
||||
self.assertEqual(group_chat.type, self.type)
|
||||
|
||||
def test_group_chat_to_json(self):
|
||||
"""Test GroupChat.to_json() method"""
|
||||
print('Testing GroupChat.to_json()')
|
||||
"""Test Chat.to_json() method"""
|
||||
print('Testing Chat.to_json()')
|
||||
|
||||
group_chat = telegram.GroupChat.de_json(self.json_dict)
|
||||
group_chat = telegram.Chat.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(group_chat.to_json()))
|
||||
|
||||
def test_group_chat_to_dict(self):
|
||||
"""Test GroupChat.to_dict() method"""
|
||||
print('Testing GroupChat.to_dict()')
|
||||
"""Test Chat.to_dict() method"""
|
||||
print('Testing Chat.to_dict()')
|
||||
|
||||
group_chat = telegram.GroupChat.de_json(self.json_dict)
|
||||
group_chat = telegram.Chat.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(group_chat.to_dict()))
|
||||
self.assertEqual(group_chat['id'], self.id)
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""
|
||||
This module contains a object that represents Tests for JobQueue
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
from time import sleep
|
||||
|
||||
if sys.version_info[0:2] == (2, 6):
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
import unittest
|
||||
|
||||
try:
|
||||
from urllib2 import urlopen, Request
|
||||
except ImportError:
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
sys.path.append('.')
|
||||
|
||||
from telegram import JobQueue, Updater
|
||||
from tests.base import BaseTest
|
||||
|
||||
# Enable logging
|
||||
root = logging.getLogger()
|
||||
root.setLevel(logging.INFO)
|
||||
|
||||
ch = logging.StreamHandler(sys.stdout)
|
||||
ch.setLevel(logging.WARN)
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
ch.setFormatter(formatter)
|
||||
root.addHandler(ch)
|
||||
|
||||
|
||||
class JobQueueTest(BaseTest, unittest.TestCase):
|
||||
"""
|
||||
This object represents Tests for Updater, Dispatcher, WebhookServer and
|
||||
WebhookHandler
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.jq = JobQueue("Bot", tick_interval=0.005)
|
||||
self.result = 0
|
||||
|
||||
def tearDown(self):
|
||||
if self.jq is not None:
|
||||
self.jq.stop()
|
||||
|
||||
def job1(self, bot):
|
||||
self.result += 1
|
||||
|
||||
def job2(self, bot):
|
||||
raise Exception("Test Error")
|
||||
|
||||
def test_basic(self):
|
||||
print('Testing basic job queue function')
|
||||
self.jq.put(self.job1, 0.1)
|
||||
sleep(1.5)
|
||||
self.assertGreaterEqual(self.result, 10)
|
||||
|
||||
def test_noRepeat(self):
|
||||
print('Testing job queue without repeat')
|
||||
self.jq.put(self.job1, 0.1, repeat=False)
|
||||
sleep(0.5)
|
||||
self.assertEqual(1, self.result)
|
||||
|
||||
def test_nextT(self):
|
||||
print('Testing job queue with a set next_t value')
|
||||
self.jq.put(self.job1, 0.1, next_t=0.5)
|
||||
sleep(0.45)
|
||||
self.assertEqual(0, self.result)
|
||||
sleep(0.1)
|
||||
self.assertEqual(1, self.result)
|
||||
|
||||
def test_multiple(self):
|
||||
print('Testing job queue with multiple jobs')
|
||||
self.jq.put(self.job1, 0.1, repeat=False)
|
||||
self.jq.put(self.job1, 0.2, repeat=False)
|
||||
self.jq.put(self.job1, 0.4)
|
||||
sleep(1)
|
||||
self.assertEqual(4, self.result)
|
||||
|
||||
def test_error(self):
|
||||
print('Testing job queue starting twice with an erroneous job')
|
||||
self.jq.put(self.job2, 0.1)
|
||||
self.jq.put(self.job1, 0.2)
|
||||
self.jq.start()
|
||||
sleep(0.4)
|
||||
self.assertEqual(1, self.result)
|
||||
|
||||
def test_inUpdater(self):
|
||||
print('Testing job queue created by updater')
|
||||
u = Updater(bot="MockBot", job_queue_tick_interval=0.005)
|
||||
u.job_queue.put(self.job1, 0.1)
|
||||
sleep(0.15)
|
||||
self.assertEqual(1, self.result)
|
||||
u.stop()
|
||||
sleep(0.4)
|
||||
self.assertEqual(1, self.result)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -38,6 +39,7 @@ class UpdateTest(BaseTest, unittest.TestCase):
|
||||
'last_name': "S.",
|
||||
'username': "leandrotoledo"},
|
||||
'chat': {'id': 12173560,
|
||||
'type': 'private',
|
||||
'first_name': "Leandro",
|
||||
'last_name': "S.",
|
||||
'username': "leandrotoledo"},
|
||||
|
||||
+88
-45
@@ -2,7 +2,8 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -22,7 +23,6 @@ This module contains a object that represents Tests for Updater, Dispatcher,
|
||||
WebhookServer and WebhookHandler
|
||||
"""
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
@@ -31,6 +31,11 @@ from random import randrange
|
||||
from time import sleep
|
||||
from datetime import datetime
|
||||
|
||||
if sys.version_info[0:2] == (2, 6):
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
import unittest
|
||||
|
||||
try:
|
||||
from urllib2 import urlopen, Request
|
||||
except ImportError:
|
||||
@@ -38,7 +43,7 @@ except ImportError:
|
||||
|
||||
sys.path.append('.')
|
||||
|
||||
from telegram import Update, Message, TelegramError, User, GroupChat, Updater
|
||||
from telegram import Update, Message, TelegramError, User, Chat, Updater, Bot
|
||||
from telegram.dispatcher import run_async
|
||||
from tests.base import BaseTest
|
||||
from threading import Lock, Thread
|
||||
@@ -61,14 +66,18 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.updater = Updater('', workers=2)
|
||||
|
||||
self.updater = None
|
||||
self.received_message = None
|
||||
self.message_count = 0
|
||||
self.lock = Lock()
|
||||
|
||||
def _setup_updater(self, *args, **kwargs):
|
||||
bot = MockBot(*args, **kwargs)
|
||||
self.updater = Updater(workers=2, bot=bot)
|
||||
|
||||
def tearDown(self):
|
||||
self.updater.stop()
|
||||
if self.updater is not None:
|
||||
self.updater.stop()
|
||||
|
||||
def reset(self):
|
||||
self.message_count = 0
|
||||
@@ -79,7 +88,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
self.message_count += 1
|
||||
|
||||
@run_async
|
||||
def asyncHandlerTest(self, bot, update):
|
||||
def asyncHandlerTest(self, bot, update, **kwargs):
|
||||
sleep(1)
|
||||
with self.lock:
|
||||
self.received_message = update.message.text
|
||||
@@ -89,6 +98,10 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
self.received_message = update
|
||||
self.message_count += 1
|
||||
|
||||
def regexGroupHandlerTest(self, bot, update, groups=None, groupdict=None):
|
||||
self.received_message = (groups, groupdict)
|
||||
self.message_count += 1
|
||||
|
||||
def additionalArgsTest(self, bot, update, update_queue, args):
|
||||
self.received_message = update
|
||||
self.message_count += 1
|
||||
@@ -97,6 +110,15 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
elif args[0] == 'noresend':
|
||||
pass
|
||||
|
||||
@run_async
|
||||
def asyncAdditionalHandlerTest(self, bot, update, update_queue=None,
|
||||
**kwargs):
|
||||
sleep(1)
|
||||
with self.lock:
|
||||
if update_queue is not None:
|
||||
self.received_message = update.message.text
|
||||
self.message_count += 1
|
||||
|
||||
def errorRaisingHandlerTest(self, bot, update):
|
||||
raise TelegramError(update)
|
||||
|
||||
@@ -106,8 +128,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_addRemoveTelegramMessageHandler(self):
|
||||
print('Testing add/removeTelegramMessageHandler')
|
||||
bot = MockBot('Test')
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('Test')
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.telegramHandlerTest)
|
||||
@@ -119,13 +140,13 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
d.removeTelegramMessageHandler(self.telegramHandlerTest)
|
||||
self.reset()
|
||||
|
||||
bot.send_messages = 1
|
||||
self.updater.bot.send_messages = 1
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_addTelegramMessageHandlerMultipleMessages(self):
|
||||
print('Testing addTelegramMessageHandler and send 100 messages...')
|
||||
self.updater.bot = MockBot('Multiple', 100)
|
||||
self._setup_updater('Multiple', 100)
|
||||
self.updater.dispatcher.addTelegramMessageHandler(
|
||||
self.telegramHandlerTest)
|
||||
self.updater.start_polling(0.0)
|
||||
@@ -135,8 +156,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_addRemoveTelegramRegexHandler(self):
|
||||
print('Testing add/removeStringRegexHandler')
|
||||
bot = MockBot('Test2')
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('Test2')
|
||||
d = self.updater.dispatcher
|
||||
regobj = re.compile('Te.*')
|
||||
self.updater.dispatcher.addTelegramRegexHandler(regobj,
|
||||
@@ -149,14 +169,13 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
d.removeTelegramRegexHandler(regobj, self.telegramHandlerTest)
|
||||
self.reset()
|
||||
|
||||
bot.send_messages = 1
|
||||
self.updater.bot.send_messages = 1
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_addRemoveTelegramCommandHandler(self):
|
||||
print('Testing add/removeTelegramCommandHandler')
|
||||
bot = MockBot('/test')
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('/test')
|
||||
d = self.updater.dispatcher
|
||||
self.updater.dispatcher.addTelegramCommandHandler(
|
||||
'test', self.telegramHandlerTest)
|
||||
@@ -168,14 +187,13 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
d.removeTelegramCommandHandler('test', self.telegramHandlerTest)
|
||||
self.reset()
|
||||
|
||||
bot.send_messages = 1
|
||||
self.updater.bot.send_messages = 1
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_addRemoveUnknownTelegramCommandHandler(self):
|
||||
print('Testing add/removeUnknownTelegramCommandHandler')
|
||||
bot = MockBot('/test2')
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('/test2')
|
||||
d = self.updater.dispatcher
|
||||
self.updater.dispatcher.addUnknownTelegramCommandHandler(
|
||||
self.telegramHandlerTest)
|
||||
@@ -187,14 +205,13 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
d.removeUnknownTelegramCommandHandler(self.telegramHandlerTest)
|
||||
self.reset()
|
||||
|
||||
bot.send_messages = 1
|
||||
self.updater.bot.send_messages = 1
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_addRemoveStringRegexHandler(self):
|
||||
print('Testing add/removeStringRegexHandler')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('', messages=0)
|
||||
d = self.updater.dispatcher
|
||||
d.addStringRegexHandler('Te.*', self.stringHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
@@ -212,8 +229,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_addRemoveStringCommandHandler(self):
|
||||
print('Testing add/removeStringCommandHandler')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('', messages=0)
|
||||
d = self.updater.dispatcher
|
||||
d.addStringCommandHandler(
|
||||
'test3', self.stringHandlerTest)
|
||||
@@ -233,8 +249,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_addRemoveUnknownStringCommandHandler(self):
|
||||
print('Testing add/removeUnknownStringCommandHandler')
|
||||
bot = MockBot('/test')
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('/test')
|
||||
d = self.updater.dispatcher
|
||||
d.addUnknownStringCommandHandler(
|
||||
self.stringHandlerTest)
|
||||
@@ -247,14 +262,13 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
d.removeUnknownStringCommandHandler(self.stringHandlerTest)
|
||||
self.reset()
|
||||
|
||||
bot.send_messages = 1
|
||||
self.updater.bot.send_messages = 1
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_addRemoveErrorHandler(self):
|
||||
print('Testing add/removeErrorHandler')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('', messages=0)
|
||||
d = self.updater.dispatcher
|
||||
d.addErrorHandler(self.errorHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
@@ -273,8 +287,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_errorInHandler(self):
|
||||
print('Testing error in Handler')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('', messages=0)
|
||||
d = self.updater.dispatcher
|
||||
d.addStringRegexHandler('.*',
|
||||
self.errorRaisingHandlerTest)
|
||||
@@ -287,8 +300,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_errorOnGetUpdates(self):
|
||||
print('Testing error on getUpdates')
|
||||
bot = MockBot('', raise_error=True)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('', raise_error=True)
|
||||
d = self.updater.dispatcher
|
||||
d.addErrorHandler(self.errorHandlerTest)
|
||||
self.updater.start_polling(0.01)
|
||||
@@ -297,8 +309,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_addRemoveTypeHandler(self):
|
||||
print('Testing add/removeTypeHandler')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('', messages=0)
|
||||
d = self.updater.dispatcher
|
||||
d.addTypeHandler(dict, self.stringHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
@@ -317,8 +328,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_runAsync(self):
|
||||
print('Testing @run_async')
|
||||
bot = MockBot('Test5', messages=2)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('Test5', messages=2)
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.asyncHandlerTest)
|
||||
@@ -329,7 +339,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_additionalArgs(self):
|
||||
print('Testing additional arguments for handlers')
|
||||
self.updater.bot = MockBot('', messages=0)
|
||||
self._setup_updater('', messages=0)
|
||||
self.updater.dispatcher.addStringCommandHandler(
|
||||
'test5', self.additionalArgsTest)
|
||||
|
||||
@@ -339,10 +349,33 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
self.assertEqual(self.received_message, '/test5 noresend')
|
||||
self.assertEqual(self.message_count, 2)
|
||||
|
||||
def test_regexGroupHandler(self):
|
||||
print('Testing optional groups and groupdict parameters')
|
||||
self._setup_updater('', messages=0)
|
||||
d = self.updater.dispatcher
|
||||
d.addStringRegexHandler('^(This).*?(?P<testgroup>regex group).*',
|
||||
self.regexGroupHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
queue.put('This is a test message for regex group matching.')
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, (('This', 'regex group'),
|
||||
{'testgroup': 'regex group'}))
|
||||
|
||||
|
||||
def test_runAsyncWithAdditionalArgs(self):
|
||||
print('Testing @run_async with additional parameters')
|
||||
self._setup_updater('Test6', messages=2)
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.asyncAdditionalHandlerTest)
|
||||
self.updater.start_polling(0.01)
|
||||
sleep(1.2)
|
||||
self.assertEqual(self.received_message, 'Test6')
|
||||
self.assertEqual(self.message_count, 2)
|
||||
|
||||
def test_webhook(self):
|
||||
print('Testing Webhook')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('', messages=0)
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.telegramHandlerTest)
|
||||
@@ -359,7 +392,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
# Now, we send an update to the server via urlopen
|
||||
message = Message(1, User(1, "Tester"), datetime.now(),
|
||||
GroupChat(1, "Test Group"))
|
||||
Chat(1, "group", title="Test Group"))
|
||||
|
||||
message.text = "Webhook Test"
|
||||
update = Update(1)
|
||||
@@ -403,8 +436,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_webhook_no_ssl(self):
|
||||
print('Testing Webhook without SSL')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
self._setup_updater('', messages=0)
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.telegramHandlerTest)
|
||||
@@ -416,7 +448,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
# Now, we send an update to the server via urlopen
|
||||
message = Message(1, User(1, "Tester 2"), datetime.now(),
|
||||
GroupChat(1, "Test Group 2"))
|
||||
Chat(1, 'group', title="Test Group 2"))
|
||||
|
||||
message.text = "Webhook Test 2"
|
||||
update = Update(1)
|
||||
@@ -446,7 +478,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
|
||||
def test_idle(self):
|
||||
print('Testing idle')
|
||||
self.updater.bot = MockBot('Test6', messages=0)
|
||||
self._setup_updater('Test6', messages=0)
|
||||
self.updater.start_polling(poll_interval=0.01)
|
||||
Thread(target=self.signalsender).start()
|
||||
self.updater.idle()
|
||||
@@ -454,6 +486,17 @@ class UpdaterTest(BaseTest, unittest.TestCase):
|
||||
sleep(1)
|
||||
self.updater.running = False
|
||||
|
||||
def test_createBot(self):
|
||||
updater = Updater('123:abcd')
|
||||
self.assertIsNotNone(updater.bot)
|
||||
|
||||
def test_mutualExclusiveTokenBot(self):
|
||||
bot = Bot('123:zyxw')
|
||||
self.assertRaises(ValueError, Updater, token='123:abcd', bot=bot)
|
||||
|
||||
def test_noTokenOrBot(self):
|
||||
self.assertRaises(ValueError, Updater)
|
||||
|
||||
|
||||
class MockBot:
|
||||
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
# Copyright (C) 2015-2016
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
Reference in New Issue
Block a user