mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2026-06-19 23:55:29 +00:00
Compare commits
299 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6622ea3ec0 | |||
| bcadfc5398 | |||
| 89ecb04a85 | |||
| 56ab40d94f | |||
| f5ac1ae067 | |||
| 23507202e8 | |||
| 185bff7117 | |||
| 9f07900d99 | |||
| 809fe4b74f | |||
| 8a4d5c5de7 | |||
| 1976822dd0 | |||
| e60694a8cc | |||
| 14b4c1ac62 | |||
| d5890d403b | |||
| ef569b68c6 | |||
| 628a4c4eac | |||
| 83d2ca3aa7 | |||
| 29cdfe671e | |||
| f21b6046c5 | |||
| 8090658ab4 | |||
| f49f592f0d | |||
| c2853fa1ef | |||
| e1f3f346bc | |||
| 1005ad57ce | |||
| 0b72acc7c8 | |||
| 8d267ed896 | |||
| 83812f3af6 | |||
| 658b5ff1c0 | |||
| 593153128c | |||
| d91f210f7c | |||
| 65177e791f | |||
| 15501e185b | |||
| 1782d0d19b | |||
| 88fbf3b5cf | |||
| c7a1d8dca3 | |||
| 3e732a0736 | |||
| 628e1b743a | |||
| e4de3f00b8 | |||
| 32c021fdd5 | |||
| a6e5a71e05 | |||
| 4d87e236be | |||
| 29ab0556f0 | |||
| fca8aee177 | |||
| 6a80a33aef | |||
| 7c9928c58f | |||
| 0cd7aa92ae | |||
| 6626d4534e | |||
| 6b309397e8 | |||
| 618df51811 | |||
| d38add1a1c | |||
| 1c7e784662 | |||
| 0006294f29 | |||
| c1f194a310 | |||
| cccd6e5baf | |||
| a0baa68cf3 | |||
| 62b79df0a4 | |||
| 1246039872 | |||
| ed6dd76ae8 | |||
| 70de2bd3f1 | |||
| 8bde310ec7 | |||
| be368f7d74 | |||
| 9defc41774 | |||
| ee8b78aa0d | |||
| 0b8fd24771 | |||
| 396dc6cd3c | |||
| ba3d174fde | |||
| ab313488ad | |||
| d808462fb6 | |||
| 71e73c3999 | |||
| a55df8b5e1 | |||
| f59efe0f4b | |||
| 1b79a57673 | |||
| ae59a18e2d | |||
| 12201f392d | |||
| 8f3fe123e3 | |||
| 04050ca883 | |||
| c3b3d51286 | |||
| 10451509f1 | |||
| ff0d724f32 | |||
| c64e577049 | |||
| f08dca0af6 | |||
| 8c0bcbf5bb | |||
| 596fc2aeda | |||
| 968b19e8b7 | |||
| 7993328ff7 | |||
| 16349ac69a | |||
| 45712c52f1 | |||
| 235dcd2ad2 | |||
| ed92d1c254 | |||
| 0b4c23f50e | |||
| 63c895c0a0 | |||
| 3162bc60e9 | |||
| 206802cf4d | |||
| 5eb4f8e5cd | |||
| 0a27e3927b | |||
| 401add78d3 | |||
| af375eb402 | |||
| 2797111ced | |||
| d7d4889c50 | |||
| bf356e124f | |||
| d7fd43ca79 | |||
| 42e11d169e | |||
| c1fae0b5ee | |||
| ef99bab435 | |||
| 93afd3eabe | |||
| 61dac76bee | |||
| 245f5abc45 | |||
| 0f8f6584ce | |||
| dd498ded00 | |||
| 5d2999818b | |||
| eb1f197ff4 | |||
| 4bc03ed56a | |||
| 9191d333ca | |||
| c6533a2d69 | |||
| 6c13762c93 | |||
| 06c09b96cf | |||
| 8a5ec3b2a1 | |||
| 21c26aed2f | |||
| 5fe1481ae9 | |||
| 1879cff82d | |||
| cd5e805692 | |||
| 90a77ab7a1 | |||
| 3928e27cf4 | |||
| 45b1124553 | |||
| 252b43dcb7 | |||
| c19a84ac05 | |||
| 404fdc2dd7 | |||
| 2ec56abe7e | |||
| 63a8700258 | |||
| d363185031 | |||
| aabaaa9049 | |||
| eb2be61eac | |||
| 0688691974 | |||
| d3d5c1e907 | |||
| cbf66d411d | |||
| 0e5b48f3b4 | |||
| df7cfdc8d0 | |||
| 89015e5ecc | |||
| 025d4c9a75 | |||
| d3bea4c3b4 | |||
| a6c12adda2 | |||
| dcb9129809 | |||
| bd1f171f51 | |||
| 54efb034a4 | |||
| fe94f146bb | |||
| 22b492762b | |||
| fea0c5cc2b | |||
| 688d6af541 | |||
| bcbd32cdd3 | |||
| 3fa8b97ed2 | |||
| 7cd4e2e205 | |||
| f2b0cb46a2 | |||
| cf5d184766 | |||
| 5738dc553f | |||
| 386accab80 | |||
| e7686db759 | |||
| 6c9490f2c6 | |||
| 855ab19dea | |||
| 797a3e6ea4 | |||
| bbd443d397 | |||
| 4e1597c614 | |||
| 75e338d5df | |||
| 1919f873c0 | |||
| a1f35355f6 | |||
| c4c17e8036 | |||
| 3024c1ce3d | |||
| b79530b10c | |||
| 778c63a6d3 | |||
| f623db06ea | |||
| 026673dc05 | |||
| 6893da5dd3 | |||
| d5a9c185f0 | |||
| cbdeacd22d | |||
| 1e2fdedc45 | |||
| c1c0e66233 | |||
| eb557e0eba | |||
| a7ac4193fe | |||
| 354bfcad79 | |||
| a1e12d424c | |||
| 38c6d002c8 | |||
| c8a14bf34d | |||
| 53c44f14bd | |||
| e75deea25c | |||
| 17b8bb4881 | |||
| 009862593b | |||
| e2fa052f54 | |||
| dcfe08dbda | |||
| dc2dfa24ad | |||
| ce58f45c4f | |||
| 7059930b5d | |||
| 77977b99b1 | |||
| ed77afaab9 | |||
| c7f2add463 | |||
| 8a074fd719 | |||
| cfa5e8a6fe | |||
| c6bf13e407 | |||
| 6237bb636c | |||
| 0496781501 | |||
| 4a761d0611 | |||
| 714adc13ee | |||
| fa387d1821 | |||
| 073d43fd75 | |||
| 5c0eeac036 | |||
| 64ca4d7b82 | |||
| 6d7542ce50 | |||
| 0cfaaa590c | |||
| 48bb8a2413 | |||
| 36dc1633f5 | |||
| e1edeb7bec | |||
| a409fc511d | |||
| 69d705a99f | |||
| cdcf2481ba | |||
| 5c4f0f152a | |||
| f29a6f0e36 | |||
| 1b0c3731de | |||
| 4be946d116 | |||
| 73e36e3b73 | |||
| 6141e76693 | |||
| 61ef876532 | |||
| 060442e0ae | |||
| 2254440671 | |||
| 65a224884f | |||
| 0218aa2f4e | |||
| 28e81ee9f6 | |||
| 6ffcdcf2fe | |||
| 89bab207b6 | |||
| 69aa1c252b | |||
| 5b8f41b3c1 | |||
| ea5c690e7a | |||
| 9145f24efa | |||
| c590d9c2fd | |||
| cfd401f22b | |||
| 7f790c3cb2 | |||
| 30749c3b66 | |||
| 8f0447156b | |||
| df000f8086 | |||
| 3d835527e0 | |||
| 323052a6c9 | |||
| ef4871cce1 | |||
| f355af1d2b | |||
| 121e365348 | |||
| 82f1d18f4b | |||
| 79cdb6cafe | |||
| 49ff02dcf4 | |||
| be23ff5d29 | |||
| 72a7355c2f | |||
| 64cf9ed941 | |||
| bb84113272 | |||
| d740ce89cf | |||
| 245238b3a2 | |||
| e693922fe8 | |||
| 62f06da897 | |||
| 05b7fda4a1 | |||
| 910959b672 | |||
| 881b0b3d06 | |||
| 95ecd44c0e | |||
| 9241534ba6 | |||
| 256d219862 | |||
| 8fddd3b027 | |||
| 3f3cb1edc5 | |||
| f037a8c776 | |||
| 98c489c44f | |||
| a86fc6c2ac | |||
| 1c4595123c | |||
| 942706e20f | |||
| 6837bef9bb | |||
| 6132e65dc3 | |||
| 0f924508f7 | |||
| b20f5af1e1 | |||
| ce58f72566 | |||
| f4839a3afe | |||
| 25f9eb7898 | |||
| c625b9a449 | |||
| e239315cca | |||
| ccdb999e37 | |||
| 2f99b785b2 | |||
| 41eb45918c | |||
| d43e292499 | |||
| fdb5f2339c | |||
| d03a394075 | |||
| 3658b4231c | |||
| 1d6e9502cb | |||
| 92ca92341a | |||
| 0691b1e971 | |||
| 8746222cf6 | |||
| 32dc05ed36 | |||
| ba5902c1d4 | |||
| 80371c9f6e | |||
| a8fd6b5061 | |||
| 53f5911aad | |||
| d4870148c7 | |||
| 6e2881b31b | |||
| 686aecb914 | |||
| 35f31bf136 | |||
| 56f6845969 | |||
| 505df01ae1 | |||
| 3be58b759f | |||
| 5dc1e4cac1 | |||
| 2cecca8324 |
@@ -0,0 +1,5 @@
|
||||
languages:
|
||||
Python: true
|
||||
exclude_paths:
|
||||
- "telegram/emoji.py"
|
||||
- "tests/*"
|
||||
@@ -0,0 +1,5 @@
|
||||
[run]
|
||||
source = telegram
|
||||
|
||||
[report]
|
||||
omit = tests/
|
||||
@@ -43,6 +43,7 @@ htmlcov/
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.coveralls.yml
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
@@ -57,3 +58,6 @@ docs/_build/
|
||||
# PyBuilder
|
||||
target/
|
||||
.idea/
|
||||
|
||||
# Sublime Text 2
|
||||
*.sublime*
|
||||
|
||||
+7
-2
@@ -4,9 +4,14 @@ python:
|
||||
- "2.7"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "pypy"
|
||||
- "pypy3"
|
||||
install:
|
||||
- pip install coveralls
|
||||
- pip install pylint flake8 coveralls
|
||||
- pip install -r requirements.txt
|
||||
script:
|
||||
coverage run telegram_test.py
|
||||
- nosetests --with-coverage --cover-package telegram/
|
||||
- flake8 telegram
|
||||
- 'if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then pylint -E telegram; fi'
|
||||
after_success:
|
||||
coveralls
|
||||
|
||||
@@ -9,10 +9,17 @@ Contributors
|
||||
The following wonderful people contributed directly or indirectly to this project:
|
||||
|
||||
- `Avanatiker <https://github.com/Avanatiker>`_
|
||||
- `Balduro <https://github.com/Balduro>`_
|
||||
- `bimmlerd <https://github.com/bimmlerd>`_
|
||||
- `ErgoZ Riftbit Vaper <https://github.com/ergoz>`_
|
||||
- `franciscod <https://github.com/franciscod>`_
|
||||
- `JASON0916 <https://github.com/JASON0916>`_
|
||||
- `jh0ker <https://github.com/jh0ker>`_
|
||||
- `JRoot3D <https://github.com/JRoot3D>`_
|
||||
- `macrojames <https://github.com/macrojames>`_
|
||||
- `naveenvhegde <https://github.com/naveenvhegde>`_
|
||||
- `njittam <https://github.com/njittam>`_
|
||||
- `Rahiel Kasim <https://github.com/rahiel>`_
|
||||
- `sooyhwang <https://github.com/sooyhwang>`_
|
||||
- `wjt <https://github.com/wjt>`_
|
||||
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
2015-08-12
|
||||
Released 2.5.3
|
||||
telegram.Bot now supports to be unpickled
|
||||
|
||||
|
||||
2015-08-11
|
||||
Released 2.5.2
|
||||
New changes from Telegram Bot API have been applied
|
||||
telegram.Bot now supports to be pickled
|
||||
Return empty str instead None when message.text is empty
|
||||
|
||||
|
||||
2015-08-10
|
||||
Released 2.5.1
|
||||
Moved from GPLv2 to LGPLv3
|
||||
|
||||
|
||||
2015-08-09
|
||||
Released 2.5
|
||||
Fixes logging calls in API
|
||||
|
||||
|
||||
2015-08-08
|
||||
Released 2.4
|
||||
Fixes Emoji class for Python 3
|
||||
PEP8 improvements
|
||||
|
||||
|
||||
2015-08-08
|
||||
Released 2.3
|
||||
Fixes ForceReply class
|
||||
Remove logging.basicConfig from library
|
||||
|
||||
|
||||
2015-07-25
|
||||
Released 2.2
|
||||
Allows debug=True when initializing telegram.Bot
|
||||
|
||||
|
||||
2015-07-20
|
||||
Released 2.1
|
||||
Fix to_dict for Document and Video
|
||||
|
||||
|
||||
2015-07-19
|
||||
|
||||
Released 2.0
|
||||
Fixes bugs
|
||||
Improves __str__ over to_json()
|
||||
Creates abstractclass TelegramObject
|
||||
|
||||
|
||||
2015-07-15
|
||||
|
||||
Released 1.9
|
||||
Python 3 officially supported
|
||||
PEP8 improvements
|
||||
|
||||
|
||||
2015-07-12
|
||||
|
||||
Released 1.8
|
||||
Fixes crash when replying an unicode text message (special thanks to JRoot3D)
|
||||
|
||||
|
||||
2015-07-11
|
||||
|
||||
Released 1.7
|
||||
Fixes crash when username is not defined on chat (special thanks to JRoot3D)
|
||||
|
||||
|
||||
2015-07-10
|
||||
|
||||
Released 1.6
|
||||
Improvements for GAE support
|
||||
|
||||
|
||||
2015-07-10
|
||||
|
||||
Released 1.5
|
||||
Fixes randomly unicode issues when using InputFile
|
||||
|
||||
|
||||
2015-07-10
|
||||
|
||||
Released 1.4
|
||||
requests lib is no longer required
|
||||
Google App Engine (GAE) is supported
|
||||
|
||||
|
||||
2015-07-10
|
||||
|
||||
Released 1.3
|
||||
Added support to setWebhook (special thanks to macrojames)
|
||||
|
||||
|
||||
2015-07-09
|
||||
|
||||
Released 1.2
|
||||
CustomKeyboard classes now available
|
||||
Emojis available
|
||||
PEP8 improvements
|
||||
|
||||
|
||||
2015-07-08
|
||||
|
||||
Released 1.1
|
||||
PyPi package now available
|
||||
|
||||
|
||||
2015-07-08
|
||||
|
||||
Released 1.0
|
||||
Initial checkin of python-telegram-bot
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
**2015-12-08**
|
||||
|
||||
*Released 3.0.0*
|
||||
|
||||
- Introducing the ``Updater`` and ``Dispatcher`` classes
|
||||
|
||||
**2015-11-11**
|
||||
|
||||
*Released 2.9.2*
|
||||
|
||||
- Error handling on request timeouts has been improved
|
||||
|
||||
**2015-11-10**
|
||||
|
||||
*Released 2.9.1*
|
||||
|
||||
- Add parameter ``network_delay`` to Bot.getUpdates for slow connections
|
||||
|
||||
**2015-11-10**
|
||||
|
||||
*Released 2.9*
|
||||
|
||||
- Emoji class now uses ``bytes_to_native_str`` from ``future`` 3rd party lib
|
||||
- Make ``user_from`` optional to work with channels
|
||||
- Raise exception if Telegram times out on long-polling
|
||||
|
||||
*Special thanks to @jh0ker for all hard work*
|
||||
|
||||
|
||||
**2015-10-08**
|
||||
|
||||
*Released 2.8.7*
|
||||
|
||||
- Type as optional for ``GroupChat`` class
|
||||
|
||||
|
||||
**2015-10-08**
|
||||
|
||||
*Released 2.8.6*
|
||||
|
||||
- Adds type to ``User`` and ``GroupChat`` classes (pre-release Telegram feature)
|
||||
|
||||
|
||||
**2015-09-24**
|
||||
|
||||
*Released 2.8.5*
|
||||
|
||||
- Handles HTTP Bad Gateway (503) errors on request
|
||||
- Fixes regression on ``Audio`` and ``Document`` for unicode fields
|
||||
|
||||
|
||||
**2015-09-20**
|
||||
|
||||
*Released 2.8.4*
|
||||
|
||||
- ``getFile`` and ``File.download`` is now fully supported
|
||||
|
||||
|
||||
**2015-09-10**
|
||||
|
||||
*Released 2.8.3*
|
||||
|
||||
- Moved ``Bot._requestURL`` to its own class (``telegram.utils.request``)
|
||||
- Much better, such wow, Telegram Objects tests
|
||||
- Add consistency for ``str`` properties on Telegram Objects
|
||||
- Better design to test if ``chat_id`` is invalid
|
||||
- Add ability to set custom filename on ``Bot.sendDocument(..,filename='')``
|
||||
- Fix Sticker as ``InputFile``
|
||||
- Send JSON requests over urlencoded post data
|
||||
- Markdown support for ``Bot.sendMessage(..., parse_mode=ParseMode.MARKDOWN)``
|
||||
- Refactor of ``TelegramError`` class (no more handling ``IOError`` or ``URLError``)
|
||||
|
||||
|
||||
**2015-09-05**
|
||||
|
||||
*Released 2.8.2*
|
||||
|
||||
- Fix regression on Telegram ReplyMarkup
|
||||
- Add certificate to ``is_inputfile`` method
|
||||
|
||||
|
||||
**2015-09-05**
|
||||
|
||||
*Released 2.8.1*
|
||||
|
||||
- Fix regression on Telegram objects with thumb properties
|
||||
|
||||
|
||||
**2015-09-04**
|
||||
|
||||
*Released 2.8*
|
||||
|
||||
- TelegramError when ``chat_id`` is empty for send* methods
|
||||
- ``setWebhook`` now supports sending self-signed certificate
|
||||
- Huge redesign of existing Telegram classes
|
||||
- Added support for PyPy
|
||||
- Added docstring for existing classes
|
||||
|
||||
|
||||
**2015-08-19**
|
||||
|
||||
*Released 2.7.1*
|
||||
|
||||
- Fixed JSON serialization for ``message``
|
||||
|
||||
|
||||
**2015-08-17**
|
||||
|
||||
*Released 2.7*
|
||||
|
||||
- Added support for ``Voice`` object and ``sendVoice`` method
|
||||
- Due backward compatibility performer or/and title will be required for ``sendAudio``
|
||||
- Fixed JSON serialization when forwarded message
|
||||
|
||||
|
||||
**2015-08-15**
|
||||
|
||||
*Released 2.6.1*
|
||||
|
||||
- Fixed parsing image header issue on < Python 2.7.3
|
||||
|
||||
|
||||
**2015-08-14**
|
||||
|
||||
*Released 2.6.0*
|
||||
|
||||
- Depreciation of ``require_authentication`` and ``clearCredentials`` methods
|
||||
- Giving ``AUTHORS`` the proper credits for their contribution for this project
|
||||
- ``Message.date`` and ``Message.forward_date`` are now ``datetime`` objects
|
||||
|
||||
|
||||
**2015-08-12**
|
||||
|
||||
*Released 2.5.3*
|
||||
|
||||
- ``telegram.Bot`` now supports to be unpickled
|
||||
|
||||
|
||||
**2015-08-11**
|
||||
|
||||
*Released 2.5.2*
|
||||
|
||||
- New changes from Telegram Bot API have been applied
|
||||
- ``telegram.Bot`` now supports to be pickled
|
||||
- Return empty ``str`` instead ``None`` when ``message.text`` is empty
|
||||
|
||||
|
||||
**2015-08-10**
|
||||
|
||||
*Released 2.5.1*
|
||||
|
||||
- Moved from GPLv2 to LGPLv3
|
||||
|
||||
|
||||
**2015-08-09**
|
||||
|
||||
*Released 2.5*
|
||||
|
||||
- Fixes logging calls in API
|
||||
|
||||
|
||||
**2015-08-08**
|
||||
|
||||
*Released 2.4*
|
||||
|
||||
- Fixes ``Emoji`` class for Python 3
|
||||
- ``PEP8`` improvements
|
||||
|
||||
|
||||
**2015-08-08**
|
||||
|
||||
*Released 2.3*
|
||||
|
||||
- Fixes ``ForceReply`` class
|
||||
- Remove ``logging.basicConfig`` from library
|
||||
|
||||
|
||||
**2015-07-25**
|
||||
|
||||
*Released 2.2*
|
||||
|
||||
- Allows ``debug=True`` when initializing ``telegram.Bot``
|
||||
|
||||
|
||||
**2015-07-20**
|
||||
|
||||
*Released 2.1*
|
||||
|
||||
- Fix ``to_dict`` for ``Document`` and ``Video``
|
||||
|
||||
|
||||
**2015-07-19**
|
||||
|
||||
*Released 2.0*
|
||||
|
||||
- Fixes bugs
|
||||
- Improves ``__str__`` over ``to_json()``
|
||||
- Creates abstract class ``TelegramObject``
|
||||
|
||||
|
||||
**2015-07-15**
|
||||
|
||||
*Released 1.9*
|
||||
|
||||
- Python 3 officially supported
|
||||
- ``PEP8`` improvements
|
||||
|
||||
|
||||
**2015-07-12**
|
||||
|
||||
*Released 1.8*
|
||||
|
||||
- Fixes crash when replying an unicode text message (special thanks to JRoot3D)
|
||||
|
||||
|
||||
**2015-07-11**
|
||||
|
||||
*Released 1.7*
|
||||
|
||||
- Fixes crash when ``username`` is not defined on ``chat`` (special thanks to JRoot3D)
|
||||
|
||||
|
||||
**2015-07-10**
|
||||
|
||||
*Released 1.6*
|
||||
|
||||
- Improvements for GAE support
|
||||
|
||||
|
||||
**2015-07-10**
|
||||
|
||||
*Released 1.5*
|
||||
|
||||
- Fixes randomly unicode issues when using ``InputFile``
|
||||
|
||||
|
||||
**2015-07-10**
|
||||
|
||||
*Released 1.4*
|
||||
|
||||
- ``requests`` lib is no longer required
|
||||
- Google App Engine (GAE) is supported
|
||||
|
||||
|
||||
**2015-07-10**
|
||||
|
||||
*Released 1.3*
|
||||
|
||||
- Added support to ``setWebhook`` (special thanks to macrojames)
|
||||
|
||||
|
||||
**2015-07-09**
|
||||
|
||||
*Released 1.2*
|
||||
|
||||
- ``CustomKeyboard`` classes now available
|
||||
- Emojis available
|
||||
- ``PEP8`` improvements
|
||||
|
||||
|
||||
**2015-07-08**
|
||||
|
||||
*Released 1.1*
|
||||
|
||||
- PyPi package now available
|
||||
|
||||
|
||||
**2015-07-08**
|
||||
|
||||
*Released 1.0*
|
||||
|
||||
- Initial checkin of python-telegram-bot
|
||||
+1
-1
@@ -1 +1 @@
|
||||
include LICENSE LICENSE.lesser Makefile
|
||||
include LICENSE LICENSE.lesser Makefile requirements.txt
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
help:
|
||||
@echo " clean remove unwanted stuff"
|
||||
@echo " lint check style with flake8"
|
||||
@echo " test run tests"
|
||||
.PHONY: clean pep8 lint test install
|
||||
|
||||
clean:
|
||||
rm -fr build
|
||||
@@ -10,8 +7,21 @@ clean:
|
||||
find . -name '*.pyo' -exec rm -f {} \;
|
||||
find . -name '*~' -exec rm -f {} \;
|
||||
|
||||
pep8:
|
||||
flake8 telegram
|
||||
|
||||
lint:
|
||||
flake8 --doctests --max-complexity 10 telegram
|
||||
pylint -E telegram
|
||||
|
||||
test:
|
||||
python telegram_test.py
|
||||
nosetests
|
||||
|
||||
install:
|
||||
pip install -r requirements.txt
|
||||
|
||||
help:
|
||||
@echo "Available targets:"
|
||||
@echo "- clean Clean up the source directory"
|
||||
@echo "- pep8 Check style with flake8"
|
||||
@echo "- lint Check style with pylint"
|
||||
@echo "- test Run tests"
|
||||
|
||||
+96
-12
@@ -2,21 +2,23 @@ Python Telegram Bot
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/python-telegram-bot.svg
|
||||
:target: https://pypi.python.org/pypi/python-telegram-bot
|
||||
:alt: PyPi Package Monthly Download
|
||||
|
||||
|
||||
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=latest
|
||||
:target: https://readthedocs.org/projects/python-telegram-bot/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://img.shields.io/github/license/leandrotoledo/python-telegram-bot.svg
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/python-telegram-bot.svg
|
||||
:target: http://www.gnu.org/licenses/lgpl-3.0.html
|
||||
:alt: LGPLv3 License
|
||||
|
||||
@@ -27,7 +29,7 @@ By `Leandro Toledo <leandrotoledodesouza@gmail.com>`_
|
||||
.. image:: https://codeclimate.com/github/leandrotoledo/python-telegram-bot/badges/gpa.svg
|
||||
:target: https://codeclimate.com/github/leandrotoledo/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
|
||||
:alt: Coveralls
|
||||
@@ -52,11 +54,13 @@ Table of contents
|
||||
|
||||
1. `API`_
|
||||
|
||||
2. `Logging`_
|
||||
|
||||
3. `Examples`_
|
||||
2. `The Updater class`_
|
||||
|
||||
4. `Documentation`_
|
||||
3. `Logging`_
|
||||
|
||||
4. `Examples`_
|
||||
|
||||
5. `Documentation`_
|
||||
|
||||
- `License`_
|
||||
|
||||
@@ -89,10 +93,12 @@ sendAudio Yes
|
||||
sendDocument Yes
|
||||
sendSticker Yes
|
||||
sendVideo Yes
|
||||
sendVoice Yes
|
||||
sendLocation Yes
|
||||
sendChatAction Yes
|
||||
getUpdates Yes
|
||||
getUserProfilePhotos Yes
|
||||
getFile Yes
|
||||
setWebhook Yes
|
||||
========================= ============
|
||||
|
||||
@@ -107,6 +113,8 @@ Python Version *Supported?*
|
||||
2.7 Yes
|
||||
3.3 Yes
|
||||
3.4 Yes
|
||||
PyPy Yes
|
||||
PyPy3 Yes
|
||||
============== ============
|
||||
|
||||
=============
|
||||
@@ -146,10 +154,72 @@ _`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.
|
||||
|
||||
As with the old method, we'll need an Access Token. To generate an Access Token, we have to talk to `BotFather <https://telegram.me/botfather>`_ and follow a few simple steps (described `here <https://core.telegram.org/bots#botfather>`_).
|
||||
|
||||
First, we create an ``Updater`` object::
|
||||
|
||||
>>> from telegram import Updater
|
||||
>>> updater = Updater(token='token')
|
||||
|
||||
For quicker access to the ``Dispatcher`` used by our ``Updater``, we can introduce it locally::
|
||||
|
||||
>>> dispatcher = updater.dispatcher
|
||||
|
||||
Now, we need to define a function that should process a specific type of update::
|
||||
|
||||
>>> def start(bot, update):
|
||||
... bot.sendMessage(chat_id=update.message.chat_id, text="I'm a bot, please talk to me!")
|
||||
|
||||
We want this function to be called on a Telegram message that contains the ``/start`` command, so we need to register it in the dispatcher::
|
||||
|
||||
>>> dispatcher.addTelegramCommandHandler('start', start)
|
||||
|
||||
The last step is to tell the ``Updater`` to start working::
|
||||
|
||||
>>> updater.start_polling()
|
||||
|
||||
Our bot is now up and running (go ahead and try it)! It's not doing anything yet, besides answering to the ``/start`` command. Let's add another handler function and register it::
|
||||
|
||||
>>> def echo(bot, update):
|
||||
... bot.sendMessage(chat_id=update.message.chat_id, text=update.message.text)
|
||||
...
|
||||
>>> dispatcher.addTelegramMessageHandler(echo)
|
||||
|
||||
Our bot should now reply to all messages that are not a command with a message that has the same content.
|
||||
|
||||
People might try to send commands to the bot that it doesn't understand, so we should get that covered as well::
|
||||
|
||||
>>> def unknown(bot, update):
|
||||
... bot.sendMessage(chat_id=update.message.chat_id, text="Sorry, I didn't understand that command.")
|
||||
...
|
||||
>>> dispatcher.addUnknownTelegramCommandHandler(unknown)
|
||||
|
||||
Let's add some functionality to our bot. We want to add the ``/caps`` command, that will take some text as parameter and return it in all caps. We can get the arguments that were passed to the command in the handler function simply by adding it to the parameter list::
|
||||
|
||||
>>> def caps(bot, update, args):
|
||||
... text_caps = ' '.join(args).upper()
|
||||
... bot.sendMessage(chat_id=update.message.chat_id, text=text_caps)
|
||||
...
|
||||
>>> dispatcher.addTelegramCommandHandler('caps', caps)
|
||||
|
||||
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>`_!
|
||||
|
||||
------
|
||||
_`API`
|
||||
------
|
||||
|
||||
Note: Using the ``Bot`` class directly is the 'old' method, but some of this is still important information, even if you're using the ``Updater`` class!
|
||||
|
||||
The API is exposed via the ``telegram.Bot`` class.
|
||||
|
||||
To generate an Access Token you have to talk to `BotFather <https://telegram.me/botfather>`_ and follow a few simple steps (described `here <https://core.telegram.org/bots#botfather>`_).
|
||||
@@ -186,6 +256,10 @@ To post a text message::
|
||||
|
||||
>>> bot.sendMessage(chat_id=chat_id, text="I'm sorry Dave I'm afraid I can't do that.")
|
||||
|
||||
To post a text message with markdown::
|
||||
|
||||
>>> bot.sendMessage(chat_id=chat_id, text="*bold* _italic_ [link](http://google.com).", parse_mode=telegram.ParseMode.MARKDOWN)
|
||||
|
||||
To post an Emoji (special thanks to `Tim Whitlock <http://apps.timwhitlock.info/emoji/tables/unicode>`_)::
|
||||
|
||||
>>> bot.sendMessage(chat_id=chat_id, text=telegram.Emoji.PILE_OF_POO)
|
||||
@@ -194,9 +268,9 @@ To post an image file via URL (right now only sendPhoto supports this)::
|
||||
|
||||
>>> bot.sendPhoto(chat_id=chat_id, photo='https://telegram.org/img/t_logo.png')
|
||||
|
||||
To post an audio file::
|
||||
To post a voice file::
|
||||
|
||||
>>> bot.sendAudio(chat_id=chat_id, audio=open('tests/telegram.ogg', 'rb'))
|
||||
>>> bot.sendVoice(chat_id=chat_id, voice=open('tests/telegram.ogg', 'rb'))
|
||||
|
||||
To tell the user that something is happening on bot's side::
|
||||
|
||||
@@ -213,6 +287,12 @@ To hide `Custom Keyboards <https://core.telegram.org/bots#keyboards>`_::
|
||||
>>> reply_markup = telegram.ReplyKeyboardHide()
|
||||
>>> bot.sendMessage(chat_id=chat_id, text="I'm back.", reply_markup=reply_markup)
|
||||
|
||||
To download a file (you will need its file_id)::
|
||||
|
||||
>>> file_id = message.voice.file_id
|
||||
>>> newFile = bot.getFile(file_id)
|
||||
>>> newFile.download('voice.ogg')
|
||||
|
||||
There are many more API methods, to read the full API documentation::
|
||||
|
||||
$ pydoc telegram.Bot
|
||||
@@ -245,6 +325,8 @@ Here follows some examples to help you to get your own Bot up to speed:
|
||||
|
||||
- `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).
|
||||
|
||||
- `TwitterForwarderBot <https://github.com/franciscod/telegram-twitter-forwarder-bot>`_ forwards you tweets from people that you have subscribed to.
|
||||
|
||||
================
|
||||
_`Documentation`
|
||||
================
|
||||
@@ -261,7 +343,9 @@ You may copy, distribute and modify the software provided that modifications are
|
||||
_`Contact`
|
||||
==========
|
||||
|
||||
Feel free to join to our `Telegram group <https://telegram.me/joinchat/00b9c0f802509b949c1563d56eb053b0>`_.
|
||||
Feel free to join to our `Telegram group <https://telegram.me/joinchat/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.
|
||||
|
||||
=======
|
||||
_`TODO`
|
||||
|
||||
+2
-2
@@ -58,9 +58,9 @@ author = u'Leandro Toledo'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '2.5'
|
||||
version = '3.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '2.5.1'
|
||||
release = '3.0.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -29,6 +29,7 @@ Submodules
|
||||
telegram.user
|
||||
telegram.userprofilephotos
|
||||
telegram.video
|
||||
telegram.voice
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
telegram.voice module
|
||||
=====================
|
||||
|
||||
.. automodule:: telegram.voice
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
+42
-31
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Simple Bot to reply Telegram messages
|
||||
# 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
|
||||
@@ -19,50 +20,60 @@
|
||||
|
||||
import logging
|
||||
import telegram
|
||||
import time
|
||||
from time import sleep
|
||||
|
||||
|
||||
LAST_UPDATE_ID = None
|
||||
try:
|
||||
from urllib.error import URLError
|
||||
except ImportError:
|
||||
from urllib2 import URLError # python 2
|
||||
|
||||
|
||||
def main():
|
||||
global LAST_UPDATE_ID
|
||||
# Telegram Bot Authorization Token
|
||||
bot = telegram.Bot('TOKEN')
|
||||
|
||||
# get the first pending update_id, this is so we can skip over it in case
|
||||
# we get an "Unauthorized" exception.
|
||||
try:
|
||||
update_id = bot.getUpdates()[0].update_id
|
||||
except IndexError:
|
||||
update_id = None
|
||||
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
|
||||
# Telegram Bot Authorization Token
|
||||
bot = telegram.Bot('TOKEN')
|
||||
|
||||
# This will be our global variable to keep the latest update_id when requesting
|
||||
# for updates. It starts with the latest update_id if available.
|
||||
try:
|
||||
LAST_UPDATE_ID = bot.getUpdates()[-1].update_id
|
||||
except IndexError:
|
||||
LAST_UPDATE_ID = None
|
||||
|
||||
while True:
|
||||
echo(bot)
|
||||
time.sleep(3)
|
||||
try:
|
||||
update_id = echo(bot, update_id)
|
||||
except telegram.TelegramError as e:
|
||||
# These are network problems with Telegram.
|
||||
if e.message in ("Bad Gateway", "Timed out"):
|
||||
sleep(1)
|
||||
elif e.message == "Unauthorized":
|
||||
# The user has removed or blocked the bot.
|
||||
update_id += 1
|
||||
else:
|
||||
raise e
|
||||
except URLError as e:
|
||||
# These are network problems on our end.
|
||||
sleep(1)
|
||||
|
||||
|
||||
def echo(bot):
|
||||
global LAST_UPDATE_ID
|
||||
def echo(bot, update_id):
|
||||
|
||||
# Request updates from last updated_id
|
||||
for update in bot.getUpdates(offset=LAST_UPDATE_ID):
|
||||
if LAST_UPDATE_ID < update.update_id:
|
||||
# chat_id is required to reply any message
|
||||
chat_id = update.message.chat_id
|
||||
message = update.message.text.encode('utf-8')
|
||||
# Request updates after the last update_id
|
||||
for update in bot.getUpdates(offset=update_id, timeout=10):
|
||||
# chat_id is required to reply to any message
|
||||
chat_id = update.message.chat_id
|
||||
update_id = update.update_id + 1
|
||||
message = update.message.text
|
||||
|
||||
if (message):
|
||||
# Reply the message
|
||||
bot.sendMessage(chat_id=chat_id,
|
||||
text=message)
|
||||
if message:
|
||||
# Reply to the message
|
||||
bot.sendMessage(chat_id=chat_id,
|
||||
text=message)
|
||||
|
||||
# Updates global offset to get the new updates
|
||||
LAST_UPDATE_ID = update.update_id
|
||||
return update_id
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
+5
-7
@@ -33,17 +33,15 @@ def main():
|
||||
LAST_UPDATE_ID = bot.getUpdates()[-1].update_id # Get lastest update
|
||||
|
||||
while True:
|
||||
for update in bot.getUpdates(offset=LAST_UPDATE_ID):
|
||||
for update in bot.getUpdates(offset=LAST_UPDATE_ID, timeout=10):
|
||||
text = update.message.text
|
||||
chat_id = update.message.chat.id
|
||||
update_id = update.update_id
|
||||
|
||||
if LAST_UPDATE_ID < update_id: # If newer than the initial
|
||||
# LAST_UPDATE_ID
|
||||
if text:
|
||||
roboed = ed(text) # Ask something to Robô Ed
|
||||
bot.sendMessage(chat_id=chat_id, text=roboed)
|
||||
LAST_UPDATE_ID = update_id
|
||||
if text:
|
||||
roboed = ed(text) # Ask something to Robô Ed
|
||||
bot.sendMessage(chat_id=chat_id, text=roboed)
|
||||
LAST_UPDATE_ID = update_id + 1
|
||||
|
||||
|
||||
def ed(text):
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
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, 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>"
|
||||
Type 'stop' on the command line to stop the bot.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Command Handlers
|
||||
def start(bot, update):
|
||||
""" Answer in Telegram """
|
||||
bot.sendMessage(update.message.chat_id, text='Hi!')
|
||||
|
||||
|
||||
def help(bot, update):
|
||||
""" Answer in Telegram """
|
||||
bot.sendMessage(update.message.chat_id, text='Help!')
|
||||
|
||||
|
||||
def any_message(bot, update):
|
||||
""" Print to console """
|
||||
|
||||
# Save last chat_id to use in reply handler
|
||||
global last_chat_id
|
||||
last_chat_id = update.message.chat_id
|
||||
|
||||
logger.info("New message\nFrom: %s\nchat_id: %d\nText: %s" %
|
||||
(update.message.from_user,
|
||||
update.message.chat_id,
|
||||
update.message.text))
|
||||
|
||||
|
||||
def unknown_command(bot, update):
|
||||
""" Answer in Telegram """
|
||||
bot.sendMessage(update.message.chat_id, text='Command not recognized!')
|
||||
|
||||
|
||||
@run_async
|
||||
def message(bot, update):
|
||||
"""
|
||||
Example for an asynchronous handler. It's not guaranteed that replies will
|
||||
be in order when using @run_async.
|
||||
"""
|
||||
|
||||
sleep(2) # IO-heavy operation here
|
||||
bot.sendMessage(update.message.chat_id, text='Echo: %s' %
|
||||
update.message.text)
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
""" Print error to console """
|
||||
logger.warn('Update %s caused error %s' % (update, error))
|
||||
|
||||
|
||||
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.
|
||||
Here, we reply to the last active chat with the text after the command.
|
||||
"""
|
||||
if last_chat_id is not 0:
|
||||
bot.sendMessage(chat_id=last_chat_id, text=' '.join(args))
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
update_queue.put('/%s' % update)
|
||||
|
||||
|
||||
def unknown_cli_command(bot, update):
|
||||
logger.warn("Command not found: %s" % update)
|
||||
|
||||
|
||||
def main():
|
||||
# Create the EventHandler and pass it your bot's token.
|
||||
token = 'token'
|
||||
updater = Updater(token, workers=2)
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dp = updater.dispatcher
|
||||
|
||||
dp.addTelegramCommandHandler("start", start)
|
||||
dp.addTelegramCommandHandler("help", help)
|
||||
dp.addUnknownTelegramCommandHandler(unknown_command)
|
||||
dp.addTelegramMessageHandler(message)
|
||||
dp.addTelegramRegexHandler('.*', any_message)
|
||||
|
||||
dp.addStringCommandHandler('reply', cli_reply)
|
||||
dp.addUnknownStringCommandHandler(unknown_cli_command)
|
||||
dp.addStringRegexHandler('[^/].*', cli_noncommand)
|
||||
|
||||
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)
|
||||
|
||||
'''
|
||||
# Alternatively, run with webhook:
|
||||
updater.bot.setWebhook(webhook_url='https://example.com/%s' % token,
|
||||
certificate=open('cert.pem', 'wb'))
|
||||
|
||||
update_queue = updater.start_webhook('0.0.0.0',
|
||||
443,
|
||||
url_path=token,
|
||||
cert='cert.pem',
|
||||
key='key.key')
|
||||
|
||||
# Or, if SSL is handled by a reverse proxy, the webhook URL is already set
|
||||
# and the reverse proxy is configured to deliver directly to port 6000:
|
||||
|
||||
update_queue = updater.start_webhook('0.0.0.0',
|
||||
6000)
|
||||
'''
|
||||
|
||||
# Start CLI-Loop
|
||||
while True:
|
||||
try:
|
||||
text = raw_input()
|
||||
except NameError:
|
||||
text = input()
|
||||
|
||||
# Gracefully stop the event handler
|
||||
if text == 'stop':
|
||||
updater.stop()
|
||||
break
|
||||
|
||||
# else, put the text into the update queue
|
||||
elif len(text) > 0:
|
||||
update_queue.put(text) # Put command into queue
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
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.
|
||||
|
||||
Usage:
|
||||
Basic Echobot example, repeats messages.
|
||||
Type 'stop' on the command line 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)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Command Handlers
|
||||
def start(bot, update):
|
||||
bot.sendMessage(update.message.chat_id, text='Hi!')
|
||||
|
||||
|
||||
def help(bot, update):
|
||||
bot.sendMessage(update.message.chat_id, text='Help!')
|
||||
|
||||
|
||||
def echo(bot, update):
|
||||
bot.sendMessage(update.message.chat_id, text=update.message.text)
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
logger.warn('Update "%s" caused error "%s"' % (update, error))
|
||||
|
||||
|
||||
def main():
|
||||
# Create the EventHandler and pass it your bot's token.
|
||||
updater = Updater("TOKEN")
|
||||
|
||||
# Get the dispatcher to register handlers
|
||||
dp = updater.dispatcher
|
||||
|
||||
# on different commands - answer in Telegram
|
||||
dp.addTelegramCommandHandler("start", start)
|
||||
dp.addTelegramCommandHandler("help", help)
|
||||
|
||||
# on noncommand i.e message - echo the message on Telegram
|
||||
dp.addTelegramMessageHandler(echo)
|
||||
|
||||
# on error - print error to stdout
|
||||
dp.addErrorHandler(error)
|
||||
|
||||
# Start the Bot
|
||||
updater.start_polling(timeout=5)
|
||||
|
||||
# Run the bot until the user presses Ctrl-C or the process receives SIGINT,
|
||||
# SIGTERM or SIGABRT
|
||||
updater.idle()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1 @@
|
||||
future
|
||||
@@ -13,17 +13,29 @@ def read(*paths):
|
||||
return f.read()
|
||||
|
||||
|
||||
def requirements():
|
||||
"""Build the requirements list for this project"""
|
||||
requirements_list = []
|
||||
|
||||
with open('requirements.txt') as requirements:
|
||||
for install in requirements:
|
||||
requirements_list.append(install.strip())
|
||||
|
||||
return requirements_list
|
||||
|
||||
|
||||
setup(
|
||||
name='python-telegram-bot',
|
||||
version='2.5.3',
|
||||
version='3.0.0',
|
||||
author='Leandro Toledo',
|
||||
author_email='leandrotoledodesouza@gmail.com',
|
||||
license='LGPLv3',
|
||||
url='https://github.com/leandrotoledo/python-telegram-bot',
|
||||
keywords='telegram bot api',
|
||||
keywords='python telegram bot api wrapper',
|
||||
description='A Python wrapper around the Telegram Bot API',
|
||||
long_description=(read('README.rst')),
|
||||
packages=find_packages(exclude=['tests*']),
|
||||
install_requires=requirements(),
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
|
||||
+16
-9
@@ -16,17 +16,17 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""A library that provides a Python interface to the Telegram Bot API"""
|
||||
|
||||
__author__ = 'leandrotoledodesouza@gmail.com'
|
||||
__version__ = '2.5.3'
|
||||
__version__ = '3.0.0'
|
||||
|
||||
from .base import TelegramObject
|
||||
from .user import User
|
||||
from .message import Message
|
||||
from .update import Update
|
||||
from .groupchat import GroupChat
|
||||
from .photosize import PhotoSize
|
||||
from .audio import Audio
|
||||
from .voice import Voice
|
||||
from .document import Document
|
||||
from .sticker import Sticker
|
||||
from .video import Video
|
||||
@@ -38,14 +38,21 @@ from .replymarkup import ReplyMarkup
|
||||
from .replykeyboardmarkup import ReplyKeyboardMarkup
|
||||
from .replykeyboardhide import ReplyKeyboardHide
|
||||
from .forcereply import ForceReply
|
||||
from .inputfile import InputFile
|
||||
from .error import TelegramError
|
||||
from .inputfile import InputFile
|
||||
from .file import File
|
||||
from .nullhandler import NullHandler
|
||||
from .emoji import Emoji
|
||||
from .parsemode import ParseMode
|
||||
from .message import Message
|
||||
from .update import Update
|
||||
from .bot import Bot
|
||||
from .dispatcher import Dispatcher
|
||||
from .updater import Updater
|
||||
|
||||
__all__ = ['Bot', 'Emoji', 'TelegramError', 'InputFile', 'ReplyMarkup',
|
||||
'ForceReply', 'ReplyKeyboardHide', 'ReplyKeyboardMarkup',
|
||||
'UserProfilePhotos', 'ChatAction', 'Location', 'Contact',
|
||||
'Video', 'Sticker', 'Document', 'Audio', 'PhotoSize', 'GroupChat',
|
||||
'Update', 'Message', 'User', 'TelegramObject', 'NullHandler']
|
||||
__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']
|
||||
|
||||
+42
-18
@@ -16,33 +16,57 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Audio"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class Audio(TelegramObject):
|
||||
"""This object represents a Telegram Audio.
|
||||
|
||||
Attributes:
|
||||
file_id (str):
|
||||
duration (int):
|
||||
performer (str):
|
||||
title (str):
|
||||
mime_type (str):
|
||||
file_size (int):
|
||||
|
||||
Args:
|
||||
file_id (str):
|
||||
duration (int):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
performer (Optional[str]):
|
||||
title (Optional[str]):
|
||||
mime_type (Optional[str]):
|
||||
file_size (Optional[int]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
duration,
|
||||
mime_type=None,
|
||||
file_size=None):
|
||||
self.file_id = file_id
|
||||
self.duration = duration
|
||||
self.mime_type = mime_type
|
||||
self.file_size = file_size
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.duration = int(duration)
|
||||
# Optionals
|
||||
self.performer = kwargs.get('performer', '')
|
||||
self.title = kwargs.get('title', '')
|
||||
self.mime_type = str(kwargs.get('mime_type', ''))
|
||||
self.file_size = int(kwargs.get('file_size', 0))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return Audio(file_id=data.get('file_id', None),
|
||||
duration=data.get('duration', None),
|
||||
mime_type=data.get('mime_type', None),
|
||||
file_size=data.get('file_size', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'file_id': self.file_id,
|
||||
'duration': self.duration}
|
||||
if self.mime_type:
|
||||
data['mime_type'] = self.mime_type
|
||||
if self.file_size:
|
||||
data['file_size'] = self.file_size
|
||||
return data
|
||||
Returns:
|
||||
telegram.Audio:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return Audio(**data)
|
||||
|
||||
+28
-4
@@ -16,13 +16,14 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""Base class for Telegram Objects"""
|
||||
|
||||
import json
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from abc import ABCMeta
|
||||
|
||||
|
||||
class TelegramObject(object):
|
||||
"""Base class for most telegram object"""
|
||||
"""Base class for most telegram objects"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@@ -34,11 +35,34 @@ class TelegramObject(object):
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
Returns:
|
||||
telegram.TelegramObject:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def to_json(self):
|
||||
"""
|
||||
Returns:
|
||||
str:
|
||||
"""
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@abstractmethod
|
||||
def to_dict(self):
|
||||
return
|
||||
"""
|
||||
Returns:
|
||||
dict:
|
||||
"""
|
||||
data = dict()
|
||||
|
||||
for key, value in self.__dict__.items():
|
||||
if value:
|
||||
if hasattr(value, 'to_dict'):
|
||||
data[key] = value.to_dict()
|
||||
else:
|
||||
data[key] = value
|
||||
|
||||
return data
|
||||
|
||||
+209
-133
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=E0611,E0213,E1102,C0103,E1101,W0613,R0913,R0904
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
@@ -16,28 +17,38 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Bot"""
|
||||
|
||||
import json
|
||||
try:
|
||||
from urllib.parse import urlencode
|
||||
from urllib.request import urlopen, Request
|
||||
from urllib.error import HTTPError, URLError
|
||||
except ImportError:
|
||||
from urllib import urlencode
|
||||
from urllib2 import urlopen, Request
|
||||
from urllib2 import HTTPError, URLError
|
||||
import functools
|
||||
import logging
|
||||
|
||||
from telegram import (User, Message, Update, UserProfilePhotos, TelegramError,
|
||||
ReplyMarkup, InputFile, TelegramObject, NullHandler)
|
||||
from telegram import (User, Message, Update, UserProfilePhotos, File,
|
||||
TelegramError, ReplyMarkup, TelegramObject, NullHandler)
|
||||
from telegram.utils import request
|
||||
|
||||
h = NullHandler()
|
||||
logging.getLogger(__name__).addHandler(h)
|
||||
H = NullHandler()
|
||||
logging.getLogger(__name__).addHandler(H)
|
||||
|
||||
|
||||
class Bot(TelegramObject):
|
||||
|
||||
"""This object represents a Telegram Bot.
|
||||
|
||||
Attributes:
|
||||
id (int):
|
||||
first_name (str):
|
||||
last_name (str):
|
||||
username (str):
|
||||
name (str):
|
||||
|
||||
Args:
|
||||
token (str):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
base_url (Optional[str]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
token,
|
||||
base_url=None):
|
||||
@@ -48,13 +59,21 @@ class Bot(TelegramObject):
|
||||
else:
|
||||
self.base_url = base_url + self.token
|
||||
|
||||
self.base_file_url = 'https://api.telegram.org/file/bot%s' % self.token
|
||||
|
||||
self.bot = None
|
||||
|
||||
self.log = logging.getLogger(__name__)
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def info(func):
|
||||
"""
|
||||
Returns:
|
||||
"""
|
||||
@functools.wraps(func)
|
||||
def decorator(self, *args, **kwargs):
|
||||
"""
|
||||
decorator
|
||||
"""
|
||||
if not self.bot:
|
||||
self.getMe()
|
||||
|
||||
@@ -65,36 +84,48 @@ class Bot(TelegramObject):
|
||||
@property
|
||||
@info
|
||||
def id(self):
|
||||
"""int: """
|
||||
return self.bot.id
|
||||
|
||||
@property
|
||||
@info
|
||||
def first_name(self):
|
||||
"""str: """
|
||||
return self.bot.first_name
|
||||
|
||||
@property
|
||||
@info
|
||||
def last_name(self):
|
||||
"""str: """
|
||||
return self.bot.last_name
|
||||
|
||||
@property
|
||||
@info
|
||||
def username(self):
|
||||
"""str: """
|
||||
return self.bot.username
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""str: """
|
||||
return '@%s' % self.username
|
||||
|
||||
def log(func):
|
||||
"""
|
||||
Returns:
|
||||
A telegram.Message instance representing the message posted.
|
||||
"""
|
||||
logger = logging.getLogger(func.__module__)
|
||||
|
||||
@functools.wraps(func)
|
||||
def decorator(self, *args, **kwargs):
|
||||
logger.debug('Entering: %s' % func.__name__)
|
||||
"""
|
||||
decorator
|
||||
"""
|
||||
logger.debug('Entering: %s', func.__name__)
|
||||
result = func(self, *args, **kwargs)
|
||||
logger.debug(result)
|
||||
logger.debug('Exiting: %s' % func.__name__)
|
||||
logger.debug('Exiting: %s', func.__name__)
|
||||
return result
|
||||
return decorator
|
||||
|
||||
@@ -105,8 +136,14 @@ class Bot(TelegramObject):
|
||||
"""
|
||||
@functools.wraps(func)
|
||||
def decorator(self, *args, **kwargs):
|
||||
"""
|
||||
decorator
|
||||
"""
|
||||
url, data = func(self, *args, **kwargs)
|
||||
|
||||
if not data.get('chat_id'):
|
||||
raise TelegramError('Invalid chat_id')
|
||||
|
||||
if kwargs.get('reply_to_message_id'):
|
||||
reply_to_message_id = kwargs.get('reply_to_message_id')
|
||||
data['reply_to_message_id'] = reply_to_message_id
|
||||
@@ -118,13 +155,12 @@ class Bot(TelegramObject):
|
||||
else:
|
||||
data['reply_markup'] = reply_markup
|
||||
|
||||
json_data = self._requestUrl(url, 'POST', data=data)
|
||||
data = self._parseAndCheckTelegram(json_data)
|
||||
result = request.post(url, data)
|
||||
|
||||
if data is True:
|
||||
return data
|
||||
if result is True:
|
||||
return result
|
||||
|
||||
return Message.de_json(data)
|
||||
return Message.de_json(result)
|
||||
return decorator
|
||||
|
||||
@log
|
||||
@@ -137,10 +173,9 @@ class Bot(TelegramObject):
|
||||
"""
|
||||
url = '%s/getMe' % self.base_url
|
||||
|
||||
json_data = self._requestUrl(url, 'GET')
|
||||
data = self._parseAndCheckTelegram(json_data)
|
||||
result = request.get(url)
|
||||
|
||||
self.bot = User.de_json(data)
|
||||
self.bot = User.de_json(result)
|
||||
|
||||
return self.bot
|
||||
|
||||
@@ -149,15 +184,19 @@ class Bot(TelegramObject):
|
||||
def sendMessage(self,
|
||||
chat_id,
|
||||
text,
|
||||
parse_mode=None,
|
||||
disable_web_page_preview=None,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None):
|
||||
**kwargs):
|
||||
"""Use this method to send text messages.
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - telegram.User or
|
||||
telegram.GroupChat 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
|
||||
for Android supports this. [Optional]
|
||||
text:
|
||||
Text of the message to be sent.
|
||||
disable_web_page_preview:
|
||||
@@ -178,6 +217,8 @@ class Bot(TelegramObject):
|
||||
data = {'chat_id': chat_id,
|
||||
'text': text}
|
||||
|
||||
if parse_mode:
|
||||
data['parse_mode'] = parse_mode
|
||||
if disable_web_page_preview:
|
||||
data['disable_web_page_preview'] = disable_web_page_preview
|
||||
|
||||
@@ -222,8 +263,7 @@ class Bot(TelegramObject):
|
||||
chat_id,
|
||||
photo,
|
||||
caption=None,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None):
|
||||
**kwargs):
|
||||
"""Use this method to send photos.
|
||||
|
||||
Args:
|
||||
@@ -262,12 +302,20 @@ class Bot(TelegramObject):
|
||||
def sendAudio(self,
|
||||
chat_id,
|
||||
audio,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None):
|
||||
duration=None,
|
||||
performer=None,
|
||||
title=None,
|
||||
**kwargs):
|
||||
"""Use this method to send audio files, if you want Telegram clients to
|
||||
display the file as a playable voice message. For this to work, your
|
||||
audio must be in an .ogg file encoded with OPUS (other formats may be
|
||||
sent as telegram.Document).
|
||||
display them in the music player. Your audio must be in an .mp3 format.
|
||||
On success, the sent Message is returned. Bots can currently send audio
|
||||
files of up to 50 MB in size, this limit may be changed in the future.
|
||||
|
||||
For backward compatibility, when both fields title and description are
|
||||
empty and mime-type of the sent file is not "audio/mpeg", file is sent
|
||||
as playable voice message. In this case, your audio must be in an .ogg
|
||||
file encoded with OPUS. This will be removed in the future. You need to
|
||||
use sendVoice method instead.
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
@@ -276,6 +324,12 @@ class Bot(TelegramObject):
|
||||
Audio file to send. You can either pass a file_id as String to
|
||||
resend an audio that is already on the Telegram servers, or upload
|
||||
a new audio file using multipart/form-data.
|
||||
duration:
|
||||
Duration of sent audio in seconds. [Optional]
|
||||
performer:
|
||||
Performer of sent audio. [Optional]
|
||||
title:
|
||||
Title of sent audio. [Optional]
|
||||
reply_to_message_id:
|
||||
If the message is a reply, ID of the original message. [Optional]
|
||||
reply_markup:
|
||||
@@ -292,6 +346,13 @@ class Bot(TelegramObject):
|
||||
data = {'chat_id': chat_id,
|
||||
'audio': audio}
|
||||
|
||||
if duration:
|
||||
data['duration'] = duration
|
||||
if performer:
|
||||
data['performer'] = performer
|
||||
if title:
|
||||
data['title'] = title
|
||||
|
||||
return url, data
|
||||
|
||||
@log
|
||||
@@ -299,8 +360,8 @@ class Bot(TelegramObject):
|
||||
def sendDocument(self,
|
||||
chat_id,
|
||||
document,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None):
|
||||
filename=None,
|
||||
**kwargs):
|
||||
"""Use this method to send general files.
|
||||
|
||||
Args:
|
||||
@@ -310,6 +371,9 @@ class Bot(TelegramObject):
|
||||
File to send. You can either pass a file_id as String to resend a
|
||||
file that is already on the Telegram servers, or upload a new file
|
||||
using multipart/form-data.
|
||||
filename:
|
||||
File name that shows in telegram message (it is usefull when you
|
||||
send file generated by temp module, for example). [Optional]
|
||||
reply_to_message_id:
|
||||
If the message is a reply, ID of the original message. [Optional]
|
||||
reply_markup:
|
||||
@@ -326,6 +390,9 @@ class Bot(TelegramObject):
|
||||
data = {'chat_id': chat_id,
|
||||
'document': document}
|
||||
|
||||
if filename:
|
||||
data['filename'] = filename
|
||||
|
||||
return url, data
|
||||
|
||||
@log
|
||||
@@ -333,8 +400,7 @@ class Bot(TelegramObject):
|
||||
def sendSticker(self,
|
||||
chat_id,
|
||||
sticker,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None):
|
||||
**kwargs):
|
||||
"""Use this method to send .webp stickers.
|
||||
|
||||
Args:
|
||||
@@ -369,8 +435,7 @@ class Bot(TelegramObject):
|
||||
video,
|
||||
duration=None,
|
||||
caption=None,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None):
|
||||
**kwargs):
|
||||
"""Use this method to send video files, Telegram clients support mp4
|
||||
videos (other formats may be sent as telegram.Document).
|
||||
|
||||
@@ -409,14 +474,57 @@ class Bot(TelegramObject):
|
||||
|
||||
return url, data
|
||||
|
||||
@log
|
||||
@message
|
||||
def sendVoice(self,
|
||||
chat_id,
|
||||
voice,
|
||||
duration=None,
|
||||
**kwargs):
|
||||
"""Use this method to send audio files, if you want Telegram clients to
|
||||
display the file as a playable voice message. For this to work, your
|
||||
audio must be in an .ogg file encoded with OPUS (other formats may be
|
||||
sent as Audio or Document). On success, the sent Message is returned.
|
||||
Bots can currently send audio files of up to 50 MB in size, this limit
|
||||
may be changed in the future.
|
||||
|
||||
Args:
|
||||
chat_id:
|
||||
Unique identifier for the message recipient - User or GroupChat id.
|
||||
voice:
|
||||
Audio file to send. You can either pass a file_id as String to
|
||||
resend an audio that is already on the Telegram servers, or upload
|
||||
a new audio file using multipart/form-data.
|
||||
duration:
|
||||
Duration of sent audio in seconds. [Optional]
|
||||
reply_to_message_id:
|
||||
If the message is a reply, ID of the original message. [Optional]
|
||||
reply_markup:
|
||||
Additional interface options. A JSON-serialized object for a
|
||||
custom reply keyboard, instructions to hide keyboard or to force a
|
||||
reply from the user. [Optional]
|
||||
|
||||
Returns:
|
||||
A telegram.Message instance representing the message posted.
|
||||
"""
|
||||
|
||||
url = '%s/sendVoice' % self.base_url
|
||||
|
||||
data = {'chat_id': chat_id,
|
||||
'voice': voice}
|
||||
|
||||
if duration:
|
||||
data['duration'] = duration
|
||||
|
||||
return url, data
|
||||
|
||||
@log
|
||||
@message
|
||||
def sendLocation(self,
|
||||
chat_id,
|
||||
latitude,
|
||||
longitude,
|
||||
reply_to_message_id=None,
|
||||
reply_markup=None):
|
||||
**kwargs):
|
||||
"""Use this method to send point on the map.
|
||||
|
||||
Args:
|
||||
@@ -463,8 +571,8 @@ class Bot(TelegramObject):
|
||||
is about to receive:
|
||||
- ChatAction.TYPING for text messages,
|
||||
- ChatAction.UPLOAD_PHOTO for photos,
|
||||
- ChatAction.UPLOAD_VIDEO or upload_video for videos,
|
||||
- ChatAction.UPLOAD_AUDIO or upload_audio for audio files,
|
||||
- ChatAction.UPLOAD_VIDEO for videos,
|
||||
- ChatAction.UPLOAD_AUDIO for audio files,
|
||||
- ChatAction.UPLOAD_DOCUMENT for general files,
|
||||
- ChatAction.FIND_LOCATION for location data.
|
||||
"""
|
||||
@@ -506,16 +614,43 @@ class Bot(TelegramObject):
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
|
||||
json_data = self._requestUrl(url, 'POST', data=data)
|
||||
data = self._parseAndCheckTelegram(json_data)
|
||||
result = request.post(url, data)
|
||||
|
||||
return UserProfilePhotos.de_json(data)
|
||||
return UserProfilePhotos.de_json(result)
|
||||
|
||||
@log
|
||||
def getFile(self,
|
||||
file_id):
|
||||
"""Use this method to get basic info about a file and prepare it for
|
||||
downloading. For the moment, bots can download files of up to 20MB in
|
||||
size.
|
||||
|
||||
Args:
|
||||
file_id:
|
||||
File identifier to get info about.
|
||||
|
||||
Returns:
|
||||
Returns a telegram.File object
|
||||
"""
|
||||
|
||||
url = '%s/getFile' % self.base_url
|
||||
|
||||
data = {'file_id': file_id}
|
||||
|
||||
result = request.post(url, data)
|
||||
|
||||
if result.get('file_path'):
|
||||
result['file_path'] = '%s/%s' % (self.base_file_url,
|
||||
result['file_path'])
|
||||
|
||||
return File.de_json(result)
|
||||
|
||||
@log
|
||||
def getUpdates(self,
|
||||
offset=None,
|
||||
limit=100,
|
||||
timeout=0):
|
||||
timeout=0,
|
||||
network_delay=2.):
|
||||
"""Use this method to receive incoming updates using long polling.
|
||||
|
||||
Args:
|
||||
@@ -531,6 +666,11 @@ class Bot(TelegramObject):
|
||||
timeout:
|
||||
Timeout in seconds for long polling. Defaults to 0, i.e. usual
|
||||
short polling.
|
||||
network_delay:
|
||||
Additional timeout in seconds to allow the response from Telegram
|
||||
to take some time when using long polling. Defaults to 2, which
|
||||
should be enough for most connections. Increase it if it takes very
|
||||
long for data to be transmitted from and to the Telegram servers.
|
||||
|
||||
Returns:
|
||||
A list of telegram.Update objects are returned.
|
||||
@@ -546,20 +686,20 @@ class Bot(TelegramObject):
|
||||
if timeout:
|
||||
data['timeout'] = timeout
|
||||
|
||||
json_data = self._requestUrl(url, 'POST', data=data)
|
||||
data = self._parseAndCheckTelegram(json_data)
|
||||
result = request.post(url, data, network_delay=network_delay)
|
||||
|
||||
if data:
|
||||
self.log.info(
|
||||
'Getting updates: %s' % [u['update_id'] for u in data])
|
||||
if result:
|
||||
self.logger.info(
|
||||
'Getting updates: %s', [u['update_id'] for u in result])
|
||||
else:
|
||||
self.log.info('No new updates found.')
|
||||
self.logger.info('No new updates found.')
|
||||
|
||||
return [Update.de_json(x) for x in data]
|
||||
return [Update.de_json(x) for x in result]
|
||||
|
||||
@log
|
||||
def setWebhook(self,
|
||||
webhook_url):
|
||||
webhook_url=None,
|
||||
certificate=None):
|
||||
"""Use this method to specify a url and receive incoming updates via an
|
||||
outgoing webhook. Whenever there is an update for the bot, we will send
|
||||
an HTTPS POST request to the specified url, containing a
|
||||
@@ -576,89 +716,25 @@ class Bot(TelegramObject):
|
||||
"""
|
||||
url = '%s/setWebhook' % self.base_url
|
||||
|
||||
data = {'url': webhook_url}
|
||||
data = {}
|
||||
if webhook_url:
|
||||
data['url'] = webhook_url
|
||||
if certificate:
|
||||
data['certificate'] = certificate
|
||||
|
||||
json_data = self._requestUrl(url, 'POST', data=data)
|
||||
data = self._parseAndCheckTelegram(json_data)
|
||||
result = request.post(url, data)
|
||||
|
||||
return True
|
||||
return result
|
||||
|
||||
def _requestUrl(self,
|
||||
url,
|
||||
method,
|
||||
data=None):
|
||||
"""Request an URL.
|
||||
|
||||
Args:
|
||||
url:
|
||||
The web location we want to retrieve.
|
||||
method:
|
||||
Either POST or GET.
|
||||
data:
|
||||
A dict of (str, unicode) key/value pairs.
|
||||
|
||||
Returns:
|
||||
A JSON object.
|
||||
"""
|
||||
if method not in ('POST', 'GET'):
|
||||
raise ValueError(
|
||||
"Method '%s' is neither 'POST' nor 'GET'" % method)
|
||||
|
||||
if method == 'POST':
|
||||
try:
|
||||
if InputFile.is_inputfile(data):
|
||||
data = InputFile(data)
|
||||
|
||||
request = Request(
|
||||
url,
|
||||
data=data.to_form(),
|
||||
headers=data.headers
|
||||
)
|
||||
|
||||
return urlopen(request).read()
|
||||
else:
|
||||
return urlopen(
|
||||
url,
|
||||
urlencode(data).encode()
|
||||
).read()
|
||||
except IOError as e:
|
||||
raise TelegramError(str(e))
|
||||
except HTTPError as e:
|
||||
raise TelegramError(str(e))
|
||||
except URLError as e:
|
||||
raise TelegramError(str(e))
|
||||
|
||||
if method == 'GET':
|
||||
try:
|
||||
return urlopen(url).read()
|
||||
except URLError as e:
|
||||
raise TelegramError(str(e))
|
||||
|
||||
def _parseAndCheckTelegram(self,
|
||||
json_data):
|
||||
"""Try and parse the JSON returned from Telegram and return an empty
|
||||
dictionary if there is any error.
|
||||
|
||||
Args:
|
||||
json_data:
|
||||
JSON results from Telegram Bot API.
|
||||
|
||||
Returns:
|
||||
A JSON parsed as Python dict with results.
|
||||
"""
|
||||
|
||||
try:
|
||||
data = json.loads(json_data.decode())
|
||||
if not data['ok']:
|
||||
raise TelegramError(data['description'])
|
||||
except ValueError:
|
||||
if '<title>403 Forbidden</title>' in json_data:
|
||||
raise TelegramError({'message': 'API must be authenticated'})
|
||||
raise TelegramError({'message': 'JSON decoding'})
|
||||
|
||||
return data['result']
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
pass
|
||||
|
||||
def to_dict(self):
|
||||
"""
|
||||
Returns:
|
||||
dict:
|
||||
"""
|
||||
data = {'id': self.id,
|
||||
'username': self.username,
|
||||
'first_name': self.username}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
@@ -16,11 +17,17 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram ChatAction"""
|
||||
|
||||
|
||||
class ChatAction(object):
|
||||
"""This object represents a Telegram ChatAction."""
|
||||
|
||||
TYPING = 'typing'
|
||||
UPLOAD_PHOTO = 'upload_photo'
|
||||
RECORD_VIDEO = 'upload_video'
|
||||
RECORD_AUDIO = 'upload_audio'
|
||||
RECORD_VIDEO = 'record_video'
|
||||
UPLOAD_VIDEO = 'upload_video'
|
||||
RECORD_AUDIO = 'record_audio'
|
||||
UPLOAD_AUDIO = 'upload_audio'
|
||||
UPLOAD_DOCUMENT = 'upload_document'
|
||||
FIND_LOCATION = 'find_location'
|
||||
|
||||
+35
-17
@@ -16,33 +16,51 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Contact"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class Contact(TelegramObject):
|
||||
"""This object represents a Telegram Contact.
|
||||
|
||||
Attributes:
|
||||
phone_number (str):
|
||||
first_name (str):
|
||||
last_name (str):
|
||||
user_id (int):
|
||||
|
||||
Args:
|
||||
phone_number (str):
|
||||
first_name (str):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
last_name (Optional[str]):
|
||||
user_id (Optional[int]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
phone_number,
|
||||
first_name,
|
||||
last_name=None,
|
||||
user_id=None):
|
||||
self.phone_number = phone_number
|
||||
**kwargs):
|
||||
# Required
|
||||
self.phone_number = str(phone_number)
|
||||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.user_id = user_id
|
||||
# Optionals
|
||||
self.last_name = kwargs.get('last_name', '')
|
||||
self.user_id = int(kwargs.get('user_id', 0))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return Contact(phone_number=data.get('phone_number', None),
|
||||
first_name=data.get('first_name', None),
|
||||
last_name=data.get('last_name', None),
|
||||
user_id=data.get('user_id', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'phone_number': self.phone_number,
|
||||
'first_name': self.first_name}
|
||||
if self.last_name:
|
||||
data['last_name'] = self.last_name
|
||||
if self.user_id:
|
||||
data['user_id'] = self.user_id
|
||||
return data
|
||||
Returns:
|
||||
telegram.Contact:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return Contact(**data)
|
||||
|
||||
@@ -0,0 +1,593 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
This module contains the Dispatcher class.
|
||||
"""
|
||||
import logging
|
||||
from functools import wraps
|
||||
from inspect import getargspec
|
||||
from threading import Thread, BoundedSemaphore, Lock
|
||||
from re import match
|
||||
|
||||
from telegram import (TelegramError, Update, NullHandler)
|
||||
|
||||
H = NullHandler()
|
||||
logging.getLogger(__name__).addHandler(H)
|
||||
|
||||
semaphore = None
|
||||
running_async = 0
|
||||
async_lock = Lock()
|
||||
|
||||
|
||||
def run_async(func):
|
||||
"""
|
||||
Function decorator that will run the function in a new thread.
|
||||
|
||||
Args:
|
||||
func (function): The function to run in the thread.
|
||||
|
||||
Returns:
|
||||
function:
|
||||
"""
|
||||
|
||||
@wraps(func)
|
||||
def pooled(*args, **kwargs):
|
||||
"""
|
||||
A wrapper to run a thread in a thread pool
|
||||
"""
|
||||
global running_async, async_lock
|
||||
result = func(*args, **kwargs)
|
||||
semaphore.release()
|
||||
with async_lock:
|
||||
running_async -= 1
|
||||
return result
|
||||
|
||||
@wraps(func)
|
||||
def async_func(*args, **kwargs):
|
||||
"""
|
||||
A wrapper to run a function in a thread
|
||||
"""
|
||||
global running_async, async_lock
|
||||
thread = Thread(target=pooled, args=args, kwargs=kwargs)
|
||||
semaphore.acquire()
|
||||
with async_lock:
|
||||
running_async += 1
|
||||
thread.start()
|
||||
return thread
|
||||
|
||||
return 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:
|
||||
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
|
||||
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
|
||||
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
|
||||
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:
|
||||
|
||||
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.
|
||||
"""
|
||||
def __init__(self, bot, update_queue, workers=4):
|
||||
self.bot = bot
|
||||
self.update_queue = update_queue
|
||||
self.telegram_message_handlers = []
|
||||
self.telegram_command_handlers = {}
|
||||
self.telegram_regex_handlers = {}
|
||||
self.string_regex_handlers = {}
|
||||
self.string_command_handlers = {}
|
||||
self.type_handlers = {}
|
||||
self.unknown_telegram_command_handlers = []
|
||||
self.unknown_string_command_handlers = []
|
||||
self.error_handlers = []
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.running = False
|
||||
|
||||
global semaphore
|
||||
if not semaphore:
|
||||
semaphore = BoundedSemaphore(value=workers)
|
||||
else:
|
||||
self.logger.info("Semaphore already initialized, skipping.")
|
||||
|
||||
class _Stop(object):
|
||||
"""
|
||||
A class which objects can be passed into the update queue to stop the
|
||||
thread
|
||||
"""
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Thread target of thread 'dispatcher'. Runs in background and processes
|
||||
the update queue.
|
||||
"""
|
||||
|
||||
self.running = True
|
||||
self.logger.info('Dispatcher thread started')
|
||||
|
||||
while True:
|
||||
update = None
|
||||
|
||||
try:
|
||||
# Pop update from update queue.
|
||||
# Blocks if no updates are available.
|
||||
update = self.update_queue.get()
|
||||
|
||||
if type(update) is self._Stop:
|
||||
break
|
||||
|
||||
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)
|
||||
|
||||
self.logger.info('Dispatcher thread stopped')
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops the thread
|
||||
"""
|
||||
if self.running:
|
||||
self.running = False
|
||||
self.update_queue.put(self._Stop())
|
||||
|
||||
def processUpdate(self, update):
|
||||
"""
|
||||
Processes a single update.
|
||||
|
||||
Args:
|
||||
update (any):
|
||||
"""
|
||||
|
||||
handled = False
|
||||
|
||||
# Custom type handlers
|
||||
for t in self.type_handlers:
|
||||
if isinstance(update, t):
|
||||
self.dispatchType(update)
|
||||
handled = True
|
||||
|
||||
# string update
|
||||
if type(update) is str and update.startswith('/'):
|
||||
self.dispatchStringCommand(update)
|
||||
handled = True
|
||||
elif type(update) is str:
|
||||
self.dispatchStringRegex(update)
|
||||
handled = True
|
||||
|
||||
# An error happened while polling
|
||||
if isinstance(update, TelegramError):
|
||||
self.dispatchError(None, update)
|
||||
handled = True
|
||||
|
||||
# Telegram update (regex)
|
||||
if isinstance(update, Update):
|
||||
self.dispatchTelegramRegex(update)
|
||||
handled = True
|
||||
|
||||
# Telegram update (command)
|
||||
if isinstance(update, Update) \
|
||||
and update.message.text.startswith('/'):
|
||||
self.dispatchTelegramCommand(update)
|
||||
handled = True
|
||||
|
||||
# Telegram update (message)
|
||||
elif isinstance(update, Update):
|
||||
self.dispatchTelegramMessage(update)
|
||||
handled = True
|
||||
|
||||
# Update not recognized
|
||||
if not handled:
|
||||
self.dispatchError(update, TelegramError(
|
||||
"Received update of unknown type %s" % type(update)))
|
||||
|
||||
# Add Handlers
|
||||
def addTelegramMessageHandler(self, handler):
|
||||
"""
|
||||
Registers a message handler in the Dispatcher.
|
||||
|
||||
Args:
|
||||
handler (function): A function that takes (Bot, Update, *args) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
self.telegram_message_handlers.append(handler)
|
||||
|
||||
def addTelegramCommandHandler(self, command, handler):
|
||||
"""
|
||||
Registers a command handler in the Dispatcher.
|
||||
|
||||
Args:
|
||||
command (str): The command keyword that this handler should be
|
||||
listening to.
|
||||
handler (function): A function that takes (Bot, Update, *args) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
if command not in self.telegram_command_handlers:
|
||||
self.telegram_command_handlers[command] = []
|
||||
|
||||
self.telegram_command_handlers[command].append(handler)
|
||||
|
||||
def addTelegramRegexHandler(self, matcher, handler):
|
||||
"""
|
||||
Registers a regex handler in the Dispatcher. If handlers will be
|
||||
called if re.match(matcher, update.message.text) is True.
|
||||
|
||||
Args:
|
||||
matcher (str/__Regex): A regex string or compiled regex object that
|
||||
matches on messages that handler should be listening to
|
||||
handler (function): A function that takes (Bot, Update, *args) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
if matcher not in self.telegram_regex_handlers:
|
||||
self.telegram_regex_handlers[matcher] = []
|
||||
|
||||
self.telegram_regex_handlers[matcher].append(handler)
|
||||
|
||||
def addStringCommandHandler(self, command, handler):
|
||||
"""
|
||||
Registers a string-command handler in the Dispatcher.
|
||||
|
||||
Args:
|
||||
command (str): The command keyword that this handler should be
|
||||
listening to.
|
||||
handler (function): A function that takes (Bot, str, *args) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
if command not in self.string_command_handlers:
|
||||
self.string_command_handlers[command] = []
|
||||
|
||||
self.string_command_handlers[command].append(handler)
|
||||
|
||||
def addStringRegexHandler(self, matcher, handler):
|
||||
"""
|
||||
Registers a regex handler in the Dispatcher. If handlers will be
|
||||
called if re.match(matcher, string) is True.
|
||||
|
||||
Args:
|
||||
matcher (str/__Regex): A regex string or compiled regex object that
|
||||
matches on the string input that handler should be listening to
|
||||
handler (function): A function that takes (Bot, Update, *args) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
if matcher not in self.string_regex_handlers:
|
||||
self.string_regex_handlers[matcher] = []
|
||||
|
||||
self.string_regex_handlers[matcher].append(handler)
|
||||
|
||||
def addUnknownTelegramCommandHandler(self, handler):
|
||||
"""
|
||||
Registers a command handler in the Dispatcher, that will receive all
|
||||
commands that have no associated handler.
|
||||
|
||||
Args:
|
||||
handler (function): A function that takes (Bot, Update, *args) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
self.unknown_telegram_command_handlers.append(handler)
|
||||
|
||||
def addUnknownStringCommandHandler(self, handler):
|
||||
"""
|
||||
Registers a string-command handler in the Dispatcher, that will
|
||||
receive all commands that have no associated handler.
|
||||
|
||||
Args:
|
||||
handler (function): A function that takes (Bot, str, *args) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
self.unknown_string_command_handlers.append(handler)
|
||||
|
||||
def addErrorHandler(self, handler):
|
||||
"""
|
||||
Registers an error handler in the Dispatcher.
|
||||
|
||||
Args:
|
||||
handler (function): A function that takes (Bot, TelegramError) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
self.error_handlers.append(handler)
|
||||
|
||||
def addTypeHandler(self, the_type, handler):
|
||||
"""
|
||||
Registers a type handler in the Dispatcher. This allows you to send
|
||||
any type of object into the update queue.
|
||||
|
||||
Args:
|
||||
the_type (type): The type this handler should listen to
|
||||
handler (function): A function that takes (Bot, type, *args) as
|
||||
arguments.
|
||||
"""
|
||||
|
||||
if the_type not in self.type_handlers:
|
||||
self.type_handlers[the_type] = []
|
||||
|
||||
self.type_handlers[the_type].append(handler)
|
||||
|
||||
# Remove Handlers
|
||||
def removeTelegramMessageHandler(self, handler):
|
||||
"""
|
||||
De-registers a message handler.
|
||||
|
||||
Args:
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if handler in self.telegram_message_handlers:
|
||||
self.telegram_message_handlers.remove(handler)
|
||||
|
||||
def removeTelegramCommandHandler(self, command, handler):
|
||||
"""
|
||||
De-registers a command handler.
|
||||
|
||||
Args:
|
||||
command (str): The command
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if command in self.telegram_command_handlers \
|
||||
and handler in self.telegram_command_handlers[command]:
|
||||
self.telegram_command_handlers[command].remove(handler)
|
||||
|
||||
def removeTelegramRegexHandler(self, matcher, handler):
|
||||
"""
|
||||
De-registers a regex handler.
|
||||
|
||||
Args:
|
||||
matcher (str/__Regex): The regex matcher object or string
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if matcher in self.telegram_regex_handlers \
|
||||
and handler in self.telegram_regex_handlers[matcher]:
|
||||
self.telegram_regex_handlers[matcher].remove(handler)
|
||||
|
||||
def removeStringCommandHandler(self, command, handler):
|
||||
"""
|
||||
De-registers a string-command handler.
|
||||
|
||||
Args:
|
||||
command (str): The command
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if command in self.string_command_handlers \
|
||||
and handler in self.string_command_handlers[command]:
|
||||
self.string_command_handlers[command].remove(handler)
|
||||
|
||||
def removeStringRegexHandler(self, matcher, handler):
|
||||
"""
|
||||
De-registers a regex handler.
|
||||
|
||||
Args:
|
||||
matcher (str/__Regex): The regex matcher object or string
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if matcher in self.string_regex_handlers \
|
||||
and handler in self.string_regex_handlers[matcher]:
|
||||
self.string_regex_handlers[matcher].remove(handler)
|
||||
|
||||
def removeUnknownTelegramCommandHandler(self, handler):
|
||||
"""
|
||||
De-registers an unknown-command handler.
|
||||
|
||||
Args:
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if handler in self.unknown_telegram_command_handlers:
|
||||
self.unknown_telegram_command_handlers.remove(handler)
|
||||
|
||||
def removeUnknownStringCommandHandler(self, handler):
|
||||
"""
|
||||
De-registers an unknown-command handler.
|
||||
|
||||
Args:
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if handler in self.unknown_string_command_handlers:
|
||||
self.unknown_string_command_handlers.remove(handler)
|
||||
|
||||
def removeErrorHandler(self, handler):
|
||||
"""
|
||||
De-registers an error handler.
|
||||
|
||||
Args:
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if handler in self.error_handlers:
|
||||
self.error_handlers.remove(handler)
|
||||
|
||||
def removeTypeHandler(self, the_type, handler):
|
||||
"""
|
||||
De-registers a type handler.
|
||||
|
||||
Args:
|
||||
handler (any):
|
||||
"""
|
||||
|
||||
if the_type in self.type_handlers \
|
||||
and handler in self.type_handlers[the_type]:
|
||||
self.type_handlers[the_type].remove(handler)
|
||||
|
||||
def dispatchTelegramCommand(self, update):
|
||||
"""
|
||||
Dispatches an update that contains a command.
|
||||
|
||||
Args:
|
||||
command (str): The command keyword
|
||||
update (telegram.Update): The Telegram update that contains the
|
||||
command
|
||||
"""
|
||||
|
||||
command = update.message.text.split(' ')[0][1:].split('@')[0]
|
||||
|
||||
if command in self.telegram_command_handlers:
|
||||
self.dispatchTo(self.telegram_command_handlers[command], update)
|
||||
else:
|
||||
self.dispatchTo(self.unknown_telegram_command_handlers, update)
|
||||
|
||||
def dispatchTelegramRegex(self, update):
|
||||
"""
|
||||
Dispatches an update to all regex handlers that match the message
|
||||
string.
|
||||
|
||||
Args:
|
||||
command (str): The command keyword
|
||||
update (telegram.Update): The Telegram update that contains the
|
||||
command
|
||||
"""
|
||||
|
||||
matching_handlers = []
|
||||
|
||||
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)
|
||||
|
||||
def dispatchStringCommand(self, update):
|
||||
"""
|
||||
Dispatches a string-update that contains a command.
|
||||
|
||||
Args:
|
||||
update (str): The string input
|
||||
"""
|
||||
|
||||
command = update.split(' ')[0][1:]
|
||||
|
||||
if command in self.string_command_handlers:
|
||||
self.dispatchTo(self.string_command_handlers[command], update)
|
||||
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.
|
||||
|
||||
Args:
|
||||
update (any): The update
|
||||
"""
|
||||
|
||||
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):
|
||||
"""
|
||||
Dispatches an update that contains a regular message.
|
||||
|
||||
Args:
|
||||
update (telegram.Update): The Telegram update that contains the
|
||||
message.
|
||||
"""
|
||||
|
||||
self.dispatchTo(self.telegram_message_handlers, update)
|
||||
|
||||
def dispatchError(self, update, error):
|
||||
"""
|
||||
Dispatches an error.
|
||||
|
||||
Args:
|
||||
update (any): The pdate that caused the error
|
||||
error (telegram.TelegramError): The Telegram error that was raised.
|
||||
"""
|
||||
|
||||
for handler in self.error_handlers:
|
||||
handler(self.bot, update, error)
|
||||
|
||||
def dispatchTo(self, handlers, update):
|
||||
"""
|
||||
Dispatches an update to a list of handlers.
|
||||
|
||||
Args:
|
||||
handlers (list): A list of handler-functions.
|
||||
update (any): The update to be dispatched
|
||||
"""
|
||||
|
||||
for handler in handlers:
|
||||
self.call_handler(handler, update)
|
||||
|
||||
def call_handler(self, handler, update):
|
||||
"""
|
||||
Calls an update handler. Checks the handler for keyword arguments and
|
||||
fills them, if possible.
|
||||
|
||||
Args:
|
||||
handler (function): An update handler function
|
||||
update (any): An update
|
||||
"""
|
||||
kwargs = {}
|
||||
fargs = getargspec(handler).args
|
||||
|
||||
if 'update_queue' in fargs:
|
||||
kwargs['update_queue'] = self.update_queue
|
||||
|
||||
if 'args' in fargs:
|
||||
if isinstance(update, Update):
|
||||
args = update.message.text.split(' ')[1:]
|
||||
elif isinstance(update, str):
|
||||
args = update.split(' ')[1:]
|
||||
else:
|
||||
args = None
|
||||
|
||||
kwargs['args'] = args
|
||||
|
||||
handler(self.bot, update, **kwargs)
|
||||
+41
-31
@@ -16,45 +16,55 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Document"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
|
||||
|
||||
class Document(TelegramObject):
|
||||
"""This object represents a Telegram Document.
|
||||
|
||||
Attributes:
|
||||
file_id (str):
|
||||
thumb (:class:`telegram.PhotoSize`):
|
||||
file_name (str):
|
||||
mime_type (str):
|
||||
file_size (int):
|
||||
|
||||
Args:
|
||||
file_id (str):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
thumb (Optional[:class:`telegram.PhotoSize`]):
|
||||
file_name (Optional[str]):
|
||||
mime_type (Optional[str]):
|
||||
file_size (Optional[int]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
thumb=None,
|
||||
file_name=None,
|
||||
mime_type=None,
|
||||
file_size=None):
|
||||
self.file_id = file_id
|
||||
self.thumb = thumb
|
||||
self.file_name = file_name
|
||||
self.mime_type = mime_type
|
||||
self.file_size = file_size
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
# Optionals
|
||||
self.thumb = kwargs.get('thumb')
|
||||
self.file_name = kwargs.get('file_name', '')
|
||||
self.mime_type = str(kwargs.get('mime_type', ''))
|
||||
self.file_size = int(kwargs.get('file_size', 0))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
if 'thumb' in data:
|
||||
from telegram import PhotoSize
|
||||
thumb = PhotoSize.de_json(data['thumb'])
|
||||
else:
|
||||
thumb = None
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
return Document(file_id=data.get('file_id', None),
|
||||
thumb=thumb,
|
||||
file_name=data.get('file_name', None),
|
||||
mime_type=data.get('mime_type', None),
|
||||
file_size=data.get('file_size', None))
|
||||
Returns:
|
||||
telegram.Document:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
def to_dict(self):
|
||||
data = {'file_id': self.file_id}
|
||||
if self.thumb:
|
||||
data['thumb'] = self.thumb.to_dict()
|
||||
if self.file_name:
|
||||
data['file_name'] = self.file_name
|
||||
if self.mime_type:
|
||||
data['mime_type'] = self.mime_type
|
||||
if self.file_size:
|
||||
data['file_size'] = self.file_size
|
||||
return data
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'))
|
||||
|
||||
return Document(**data)
|
||||
|
||||
+859
-842
File diff suppressed because it is too large
Load Diff
+20
-5
@@ -16,11 +16,26 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Error"""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class TelegramError(Exception):
|
||||
"""Base class for Telegram errors."""
|
||||
"""This object represents a Telegram Error."""
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
'''Returns the first argument used to construct this error.'''
|
||||
return self.args[0]
|
||||
def __init__(self, message):
|
||||
"""
|
||||
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
|
||||
|
||||
def __str__(self):
|
||||
return '%s' % (self.message)
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram File"""
|
||||
|
||||
from os.path import basename
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram.utils.request import download as _download
|
||||
|
||||
|
||||
class File(TelegramObject):
|
||||
|
||||
"""This object represents a Telegram File.
|
||||
|
||||
Attributes:
|
||||
file_id (str):
|
||||
file_size (str):
|
||||
file_path (str):
|
||||
|
||||
Args:
|
||||
file_id (str):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
file_size (Optional[int]):
|
||||
file_path (Optional[str]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
# Optionals
|
||||
self.file_size = int(kwargs.get('file_size', 0))
|
||||
self.file_path = str(kwargs.get('file_path', ''))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
Returns:
|
||||
telegram.File:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return File(**data)
|
||||
|
||||
def download(self,
|
||||
custom_path=None):
|
||||
"""
|
||||
Args:
|
||||
custom_path (str):
|
||||
"""
|
||||
url = self.file_path
|
||||
|
||||
if custom_path:
|
||||
filename = basename(custom_path)
|
||||
else:
|
||||
filename = basename(url)
|
||||
|
||||
_download(url, filename)
|
||||
+30
-10
@@ -16,24 +16,44 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram ForceReply"""
|
||||
|
||||
from telegram import ReplyMarkup
|
||||
|
||||
|
||||
class ForceReply(ReplyMarkup):
|
||||
"""This object represents a Telegram ForceReply.
|
||||
|
||||
Attributes:
|
||||
force_reply (bool):
|
||||
selective (bool):
|
||||
|
||||
Args:
|
||||
force_reply (bool):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
selective (Optional[bool]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
force_reply=True,
|
||||
selective=None):
|
||||
self.force_reply = force_reply
|
||||
self.selective = selective
|
||||
**kwargs):
|
||||
# Required
|
||||
self.force_reply = bool(force_reply)
|
||||
# Optionals
|
||||
self.selective = bool(kwargs.get('selective', False))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return ForceReply(force_reply=data.get('force_reply', None),
|
||||
selective=data.get('selective', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'force_reply': self.force_reply}
|
||||
if self.selective:
|
||||
data['selective'] = self.selective
|
||||
return data
|
||||
Returns:
|
||||
telegram.ForceReply:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return ForceReply(**data)
|
||||
|
||||
+34
-8
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=C0103,W0622
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
@@ -16,23 +17,48 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram GroupChat"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class GroupChat(TelegramObject):
|
||||
"""This object represents a Telegram GroupChat.
|
||||
|
||||
Attributes:
|
||||
id (int):
|
||||
title (str):
|
||||
type (str):
|
||||
|
||||
Args:
|
||||
id (int):
|
||||
title (str):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
type (Optional[str]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
title):
|
||||
self.id = id
|
||||
title,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.id = int(id)
|
||||
self.title = title
|
||||
# Optionals
|
||||
self.type = kwargs.get('type', '')
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return GroupChat(id=data.get('id', None),
|
||||
title=data.get('title', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'id': self.id,
|
||||
'title': self.title}
|
||||
return data
|
||||
Returns:
|
||||
telegram.GroupChat:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return GroupChat(**data)
|
||||
|
||||
+49
-27
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=W0622,E0611
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
@@ -16,6 +17,7 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram InputFile"""
|
||||
|
||||
try:
|
||||
from email.generator import _make_boundary as choose_boundary
|
||||
@@ -26,10 +28,10 @@ except ImportError:
|
||||
from urllib2 import urlopen
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import imghdr
|
||||
|
||||
from .error import TelegramError
|
||||
from telegram import TelegramError
|
||||
|
||||
DEFAULT_MIME_TYPE = 'application/octet-stream'
|
||||
USER_AGENT = 'Python Telegram Bot' \
|
||||
@@ -37,6 +39,8 @@ USER_AGENT = 'Python Telegram Bot' \
|
||||
|
||||
|
||||
class InputFile(object):
|
||||
"""This object represents a Telegram InputFile."""
|
||||
|
||||
def __init__(self,
|
||||
data):
|
||||
self.data = data
|
||||
@@ -51,13 +55,25 @@ class InputFile(object):
|
||||
if 'photo' in data:
|
||||
self.input_name = 'photo'
|
||||
self.input_file = data.pop('photo')
|
||||
if 'sticker' in data:
|
||||
self.input_name = 'sticker'
|
||||
self.input_file = data.pop('sticker')
|
||||
if 'video' in data:
|
||||
self.input_name = 'video'
|
||||
self.input_file = data.pop('video')
|
||||
if 'voice' in data:
|
||||
self.input_name = 'voice'
|
||||
self.input_file = data.pop('voice')
|
||||
if 'certificate' in data:
|
||||
self.input_name = 'certificate'
|
||||
self.input_file = data.pop('certificate')
|
||||
|
||||
if isinstance(self.input_file, file):
|
||||
self.input_file_content = self.input_file.read()
|
||||
self.filename = os.path.basename(self.input_file.name)
|
||||
if 'filename' in data:
|
||||
self.filename = self.data.pop('filename')
|
||||
else:
|
||||
self.filename = os.path.basename(self.input_file.name)
|
||||
self.mimetype = mimetypes.guess_type(self.filename)[0] or \
|
||||
DEFAULT_MIME_TYPE
|
||||
|
||||
@@ -68,14 +84,26 @@ class InputFile(object):
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
"""
|
||||
Returns:
|
||||
str:
|
||||
"""
|
||||
return {'User-agent': USER_AGENT,
|
||||
'Content-type': self.content_type}
|
||||
|
||||
@property
|
||||
def content_type(self):
|
||||
"""
|
||||
Returns:
|
||||
str:
|
||||
"""
|
||||
return 'multipart/form-data; boundary=%s' % self.boundary
|
||||
|
||||
def to_form(self):
|
||||
"""
|
||||
Returns:
|
||||
str:
|
||||
"""
|
||||
form = []
|
||||
form_boundary = '--' + self.boundary
|
||||
|
||||
@@ -102,9 +130,14 @@ class InputFile(object):
|
||||
form.append('--' + self.boundary + '--')
|
||||
form.append('')
|
||||
|
||||
return self._parse(form)
|
||||
return InputFile._parse(form)
|
||||
|
||||
def _parse(self, form):
|
||||
@staticmethod
|
||||
def _parse(form):
|
||||
"""
|
||||
Returns:
|
||||
str:
|
||||
"""
|
||||
if sys.version_info > (3,):
|
||||
# on Python 3 form needs to be byte encoded
|
||||
encoded_form = []
|
||||
@@ -122,41 +155,30 @@ class InputFile(object):
|
||||
"""Check if the content file is an image by analyzing its headers.
|
||||
|
||||
Args:
|
||||
stream:
|
||||
A str representing the content of a file.
|
||||
stream (str): A str representing the content of a file.
|
||||
|
||||
Returns:
|
||||
The str mimetype of an image.
|
||||
str: The str mimetype of an image.
|
||||
"""
|
||||
try:
|
||||
header = stream[:10]
|
||||
image = imghdr.what(None, stream)
|
||||
if image:
|
||||
return 'image/%s' % image
|
||||
|
||||
if re.match(b'GIF8', header):
|
||||
return 'image/gif'
|
||||
|
||||
if re.match(b'\x89PNG', header):
|
||||
return 'image/png'
|
||||
|
||||
if re.match(b'\xff\xd8\xff\xe0\x00\x10JFIF', header) or \
|
||||
re.match(b'\xff\xd8\xff\xe1(.*){2}Exif', header):
|
||||
return 'image/jpeg'
|
||||
except IndexError as e:
|
||||
raise TelegramError(str(e))
|
||||
|
||||
raise TelegramError({'message': 'Could not parse file content'})
|
||||
raise TelegramError('Could not parse file content')
|
||||
|
||||
@staticmethod
|
||||
def is_inputfile(data):
|
||||
"""Check if the request is a file request
|
||||
"""Check if the request is a file request.
|
||||
|
||||
Args:
|
||||
data:
|
||||
A dict of (str, unicode) key/value pairs
|
||||
data (str): A dict of (str, unicode) key/value pairs
|
||||
|
||||
Returns:
|
||||
bool
|
||||
"""
|
||||
if data:
|
||||
file_types = ['audio', 'document', 'photo', 'video']
|
||||
file_types = ['audio', 'document', 'photo', 'sticker', 'video',
|
||||
'voice', 'certificate']
|
||||
file_type = [i for i in list(data.keys()) if i in file_types]
|
||||
|
||||
if file_type:
|
||||
|
||||
+25
-8
@@ -16,23 +16,40 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Location"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class Location(TelegramObject):
|
||||
"""This object represents a Telegram Sticker.
|
||||
|
||||
Attributes:
|
||||
longitude (float):
|
||||
latitude (float):
|
||||
|
||||
Args:
|
||||
longitude (float):
|
||||
latitude (float):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
longitude,
|
||||
latitude):
|
||||
self.longitude = longitude
|
||||
self.latitude = latitude
|
||||
# Required
|
||||
self.longitude = float(longitude)
|
||||
self.latitude = float(latitude)
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return Location(longitude=data.get('longitude', None),
|
||||
latitude=data.get('latitude', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'longitude': self.longitude,
|
||||
'latitude': self.latitude}
|
||||
return data
|
||||
Returns:
|
||||
telegram.Location:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return Location(**data)
|
||||
|
||||
+179
-195
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=R0902,R0912,R0913
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
@@ -16,232 +17,215 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Message"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from datetime import datetime
|
||||
from time import mktime
|
||||
|
||||
from telegram import (Audio, Contact, Document, GroupChat, Location, PhotoSize,
|
||||
Sticker, TelegramObject, User, Video, Voice)
|
||||
|
||||
|
||||
class Message(TelegramObject):
|
||||
"""This object represents a Telegram Message.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
|
||||
Attributes:
|
||||
message_id (int):
|
||||
from_user (:class:`telegram.User`):
|
||||
date (:class:`datetime.datetime`):
|
||||
forward_from (:class:`telegram.User`):
|
||||
forward_date (:class:`datetime.datetime`):
|
||||
reply_to_message (:class:`telegram.Message`):
|
||||
text (str):
|
||||
audio (:class:`telegram.Audio`):
|
||||
document (:class:`telegram.Document`):
|
||||
photo (List[:class:`telegram.PhotoSize`]):
|
||||
sticker (:class:`telegram.Sticker`):
|
||||
video (:class:`telegram.Video`):
|
||||
voice (:class:`telegram.Voice`):
|
||||
caption (str):
|
||||
contact (:class:`telegram.Contact`):
|
||||
location (:class:`telegram.Location`):
|
||||
new_chat_participant (:class:`telegram.User`):
|
||||
left_chat_participant (:class:`telegram.User`):
|
||||
new_chat_title (str):
|
||||
new_chat_photo (List[:class:`telegram.PhotoSize`]):
|
||||
delete_chat_photo (bool):
|
||||
group_chat_created (bool):
|
||||
|
||||
Args:
|
||||
message_id (int):
|
||||
from_user (:class:`telegram.User`):
|
||||
date (:class:`datetime.datetime`):
|
||||
chat (:class:`telegram.User` or :class:`telegram.GroupChat`):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
forward_from (Optional[:class:`telegram.User`]):
|
||||
forward_date (Optional[:class:`datetime.datetime`]):
|
||||
reply_to_message (Optional[:class:`telegram.Message`]):
|
||||
text (Optional[str]):
|
||||
audio (Optional[:class:`telegram.Audio`]):
|
||||
document (Optional[:class:`telegram.Document`]):
|
||||
photo (Optional[List[:class:`telegram.PhotoSize`]]):
|
||||
sticker (Optional[:class:`telegram.Sticker`]):
|
||||
video (Optional[:class:`telegram.Video`]):
|
||||
voice (Optional[:class:`telegram.Voice`]):
|
||||
caption (Optional[str]):
|
||||
contact (Optional[:class:`telegram.Contact`]):
|
||||
location (Optional[:class:`telegram.Location`]):
|
||||
new_chat_participant (Optional[:class:`telegram.User`]):
|
||||
left_chat_participant (Optional[:class:`telegram.User`]):
|
||||
new_chat_title (Optional[str]):
|
||||
new_chat_photo (Optional[List[:class:`telegram.PhotoSize`]):
|
||||
delete_chat_photo (Optional[bool]):
|
||||
group_chat_created (Optional[bool]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
message_id,
|
||||
from_user,
|
||||
date,
|
||||
chat,
|
||||
forward_from=None,
|
||||
forward_date=None,
|
||||
reply_to_message=None,
|
||||
text=None,
|
||||
audio=None,
|
||||
document=None,
|
||||
photo=None,
|
||||
sticker=None,
|
||||
video=None,
|
||||
caption=None,
|
||||
contact=None,
|
||||
location=None,
|
||||
new_chat_participant=None,
|
||||
left_chat_participant=None,
|
||||
new_chat_title=None,
|
||||
new_chat_photo=None,
|
||||
delete_chat_photo=None,
|
||||
group_chat_created=None):
|
||||
self.message_id = message_id
|
||||
**kwargs):
|
||||
# Required
|
||||
self.message_id = int(message_id)
|
||||
self.from_user = from_user
|
||||
self.date = date
|
||||
self.chat = chat
|
||||
self.forward_from = forward_from
|
||||
self.forward_date = forward_date
|
||||
self.reply_to_message = reply_to_message
|
||||
self.text = text
|
||||
self.audio = audio
|
||||
self.document = document
|
||||
self.photo = photo
|
||||
self.sticker = sticker
|
||||
self.video = video
|
||||
self.caption = caption
|
||||
self.contact = contact
|
||||
self.location = location
|
||||
self.new_chat_participant = new_chat_participant
|
||||
self.left_chat_participant = left_chat_participant
|
||||
self.new_chat_title = new_chat_title
|
||||
self.new_chat_photo = new_chat_photo
|
||||
self.delete_chat_photo = delete_chat_photo
|
||||
self.group_chat_created = group_chat_created
|
||||
# Optionals
|
||||
self.forward_from = kwargs.get('forward_from')
|
||||
self.forward_date = kwargs.get('forward_date')
|
||||
self.reply_to_message = kwargs.get('reply_to_message')
|
||||
self.text = kwargs.get('text', '')
|
||||
self.audio = kwargs.get('audio')
|
||||
self.document = kwargs.get('document')
|
||||
self.photo = kwargs.get('photo')
|
||||
self.sticker = kwargs.get('sticker')
|
||||
self.video = kwargs.get('video')
|
||||
self.voice = kwargs.get('voice')
|
||||
self.caption = kwargs.get('caption', '')
|
||||
self.contact = kwargs.get('contact')
|
||||
self.location = kwargs.get('location')
|
||||
self.new_chat_participant = kwargs.get('new_chat_participant')
|
||||
self.left_chat_participant = kwargs.get('left_chat_participant')
|
||||
self.new_chat_title = kwargs.get('new_chat_title', '')
|
||||
self.new_chat_photo = kwargs.get('new_chat_photo')
|
||||
self.delete_chat_photo = bool(kwargs.get('delete_chat_photo', False))
|
||||
self.group_chat_created = bool(kwargs.get('group_chat_created', False))
|
||||
|
||||
@property
|
||||
def chat_id(self):
|
||||
"""int: Short for :attr:`Message.chat.id`"""
|
||||
return self.chat.id
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
if 'from' in data: # from is a reserved word, use from_user instead.
|
||||
from telegram import User
|
||||
from_user = User.de_json(data['from'])
|
||||
else:
|
||||
from_user = None
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
if 'date' in data:
|
||||
date = datetime.fromtimestamp(data['date'])
|
||||
else:
|
||||
date = None
|
||||
Returns:
|
||||
telegram.Message:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
if 'chat' in data:
|
||||
if 'first_name' in data['chat']:
|
||||
from telegram import User
|
||||
chat = User.de_json(data['chat'])
|
||||
if 'title' in data['chat']:
|
||||
from telegram import GroupChat
|
||||
chat = GroupChat.de_json(data['chat'])
|
||||
else:
|
||||
chat = None
|
||||
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['forward_from'] = \
|
||||
User.de_json(data.get('forward_from'))
|
||||
data['forward_date'] = \
|
||||
Message._fromtimestamp(data.get('forward_date'))
|
||||
data['reply_to_message'] = \
|
||||
Message.de_json(data.get('reply_to_message'))
|
||||
data['audio'] = \
|
||||
Audio.de_json(data.get('audio'))
|
||||
data['document'] = \
|
||||
Document.de_json(data.get('document'))
|
||||
data['photo'] = \
|
||||
PhotoSize.de_list(data.get('photo'))
|
||||
data['sticker'] = \
|
||||
Sticker.de_json(data.get('sticker'))
|
||||
data['video'] = \
|
||||
Video.de_json(data.get('video'))
|
||||
data['voice'] = \
|
||||
Voice.de_json(data.get('voice'))
|
||||
data['contact'] = \
|
||||
Contact.de_json(data.get('contact'))
|
||||
data['location'] = \
|
||||
Location.de_json(data.get('location'))
|
||||
data['new_chat_participant'] = \
|
||||
User.de_json(data.get('new_chat_participant'))
|
||||
data['left_chat_participant'] = \
|
||||
User.de_json(data.get('left_chat_participant'))
|
||||
data['new_chat_photo'] = \
|
||||
PhotoSize.de_list(data.get('new_chat_photo'))
|
||||
|
||||
if 'forward_from' in data:
|
||||
from telegram import User
|
||||
forward_from = User.de_json(data['forward_from'])
|
||||
else:
|
||||
forward_from = None
|
||||
return Message(**data)
|
||||
|
||||
if 'forward_date' in data:
|
||||
forward_date = datetime.fromtimestamp(data['forward_date'])
|
||||
else:
|
||||
forward_date = None
|
||||
|
||||
if 'reply_to_message' in data:
|
||||
reply_to_message = Message.de_json(data['reply_to_message'])
|
||||
else:
|
||||
reply_to_message = None
|
||||
|
||||
if 'audio' in data:
|
||||
from telegram import Audio
|
||||
audio = Audio.de_json(data['audio'])
|
||||
else:
|
||||
audio = None
|
||||
|
||||
if 'document' in data:
|
||||
from telegram import Document
|
||||
document = Document.de_json(data['document'])
|
||||
else:
|
||||
document = None
|
||||
|
||||
if 'photo' in data:
|
||||
from telegram import PhotoSize
|
||||
photo = [PhotoSize.de_json(x) for x in data['photo']]
|
||||
else:
|
||||
photo = None
|
||||
|
||||
if 'sticker' in data:
|
||||
from telegram import Sticker
|
||||
sticker = Sticker.de_json(data['sticker'])
|
||||
else:
|
||||
sticker = None
|
||||
|
||||
if 'video' in data:
|
||||
from telegram import Video
|
||||
video = Video.de_json(data['video'])
|
||||
else:
|
||||
video = None
|
||||
|
||||
if 'contact' in data:
|
||||
from telegram import Contact
|
||||
contact = Contact.de_json(data['contact'])
|
||||
else:
|
||||
contact = None
|
||||
|
||||
if 'location' in data:
|
||||
from telegram import Location
|
||||
location = Location.de_json(data['location'])
|
||||
else:
|
||||
location = None
|
||||
|
||||
if 'new_chat_participant' in data:
|
||||
from telegram import User
|
||||
new_chat_participant = User.de_json(data['new_chat_participant'])
|
||||
else:
|
||||
new_chat_participant = None
|
||||
|
||||
if 'left_chat_participant' in data:
|
||||
from telegram import User
|
||||
left_chat_participant = User.de_json(data['left_chat_participant'])
|
||||
else:
|
||||
left_chat_participant = None
|
||||
|
||||
return Message(message_id=data.get('message_id', None),
|
||||
from_user=from_user,
|
||||
date=date,
|
||||
chat=chat,
|
||||
forward_from=forward_from,
|
||||
forward_date=forward_date,
|
||||
reply_to_message=reply_to_message,
|
||||
text=data.get('text', ''),
|
||||
audio=audio,
|
||||
document=document,
|
||||
photo=photo,
|
||||
sticker=sticker,
|
||||
video=video,
|
||||
caption=data.get('caption', ''),
|
||||
contact=contact,
|
||||
location=location,
|
||||
new_chat_participant=new_chat_participant,
|
||||
left_chat_participant=left_chat_participant,
|
||||
new_chat_title=data.get('new_chat_title', None),
|
||||
new_chat_photo=data.get('new_chat_photo', None),
|
||||
delete_chat_photo=data.get('delete_chat_photo', None),
|
||||
group_chat_created=data.get('group_chat_created', None))
|
||||
def __getitem__(self, item):
|
||||
if item in self.__dict__.keys():
|
||||
return self.__dict__[item]
|
||||
elif item == 'chat_id':
|
||||
return self.chat.id
|
||||
|
||||
def to_dict(self):
|
||||
data = {'message_id': self.message_id,
|
||||
'from': self.from_user.to_dict(),
|
||||
'chat': self.chat.to_dict()}
|
||||
try:
|
||||
# Python 3.3+ supports .timestamp()
|
||||
data['date'] = int(self.date.timestamp())
|
||||
"""
|
||||
Returns:
|
||||
dict:
|
||||
"""
|
||||
data = super(Message, self).to_dict()
|
||||
|
||||
if self.forward_date:
|
||||
data['forward_date'] = int(self.forward_date.timestamp())
|
||||
except AttributeError:
|
||||
# _totimestamp() for Python 3 (< 3.3) and Python 2
|
||||
data['date'] = self._totimestamp(self.date)
|
||||
|
||||
if self.forward_date:
|
||||
data['forward_date'] = self._totimestamp(self.forward_date)
|
||||
|
||||
if self.forward_from:
|
||||
data['forward_from'] = self.forward_from
|
||||
if self.reply_to_message:
|
||||
data['reply_to_message'] = self.reply_to_message
|
||||
if self.text:
|
||||
data['text'] = self.text
|
||||
if self.audio:
|
||||
data['audio'] = self.audio.to_dict()
|
||||
if self.document:
|
||||
data['document'] = self.document.to_dict()
|
||||
# Required
|
||||
data['from'] = data.pop('from_user', None)
|
||||
data['date'] = self._totimestamp(self.date)
|
||||
# Optionals
|
||||
if self.forward_date:
|
||||
data['forward_date'] = self._totimestamp(self.forward_date)
|
||||
if self.photo:
|
||||
data['photo'] = [p.to_dict() for p in self.photo]
|
||||
if self.sticker:
|
||||
data['sticker'] = self.sticker.to_dict()
|
||||
if self.video:
|
||||
data['video'] = self.video.to_dict()
|
||||
if self.caption:
|
||||
data['caption'] = self.caption
|
||||
if self.contact:
|
||||
data['contact'] = self.contact.to_dict()
|
||||
if self.location:
|
||||
data['location'] = self.location.to_dict()
|
||||
if self.new_chat_participant:
|
||||
data['new_chat_participant'] = self.new_chat_participant
|
||||
if self.left_chat_participant:
|
||||
data['left_chat_participant'] = self.left_chat_participant
|
||||
if self.new_chat_title:
|
||||
data['new_chat_title'] = self.new_chat_title
|
||||
if self.new_chat_photo:
|
||||
data['new_chat_photo'] = self.new_chat_photo
|
||||
if self.delete_chat_photo:
|
||||
data['delete_chat_photo'] = self.delete_chat_photo
|
||||
if self.group_chat_created:
|
||||
data['group_chat_created'] = self.group_chat_created
|
||||
data['new_chat_photo'] = [p.to_dict() for p in self.new_chat_photo]
|
||||
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def _totimestamp(dt):
|
||||
return int(mktime(dt.timetuple()))
|
||||
def _fromtimestamp(unixtime):
|
||||
"""
|
||||
Args:
|
||||
unixtime (int):
|
||||
|
||||
Returns:
|
||||
datetime.datetime:
|
||||
"""
|
||||
if not unixtime:
|
||||
return None
|
||||
|
||||
return datetime.fromtimestamp(unixtime)
|
||||
|
||||
@staticmethod
|
||||
def _totimestamp(dt_obj):
|
||||
"""
|
||||
Args:
|
||||
dt_obj (:class:`datetime.datetime`):
|
||||
|
||||
Returns:
|
||||
int:
|
||||
"""
|
||||
if not dt_obj:
|
||||
return None
|
||||
|
||||
try:
|
||||
# Python 3.3+
|
||||
return int(dt_obj.timestamp())
|
||||
except AttributeError:
|
||||
# Python 3 (< 3.3) and Python 2
|
||||
return int(mktime(dt_obj.timetuple()))
|
||||
|
||||
@@ -16,10 +16,17 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a logging NullHandler"""
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
"""This object represents a logging NullHandler."""
|
||||
|
||||
def emit(self, record):
|
||||
"""
|
||||
Args:
|
||||
record (str):
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
@@ -16,15 +17,11 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram
|
||||
Message Parse Modes"""
|
||||
|
||||
import logging
|
||||
import unittest
|
||||
from tests.test_bot import BotTest
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.DEBUG)
|
||||
testsuite = unittest.TestLoader().loadTestsFromTestCase(BotTest)
|
||||
unittest.TextTestRunner(verbosity=1).run(testsuite)
|
||||
class ParseMode(object):
|
||||
"""This object represents a Telegram Message Parse Modes."""
|
||||
|
||||
MARKDOWN = 'Markdown'
|
||||
+53
-15
@@ -16,32 +16,70 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram PhotoSize"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class PhotoSize(TelegramObject):
|
||||
"""This object represents a Telegram PhotoSize.
|
||||
|
||||
Attributes:
|
||||
file_id (str):
|
||||
width (int):
|
||||
height (int):
|
||||
file_size (int):
|
||||
|
||||
Args:
|
||||
file_id (str):
|
||||
width (int):
|
||||
height (int):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
file_size (Optional[int]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
width,
|
||||
height,
|
||||
file_size=None):
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = file_id
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.file_size = file_size
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
# Optionals
|
||||
self.file_size = int(kwargs.get('file_size', 0))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return PhotoSize(file_id=data.get('file_id', None),
|
||||
width=data.get('width', None),
|
||||
height=data.get('height', None),
|
||||
file_size=data.get('file_size', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'file_id': self.file_id,
|
||||
'width': self.width,
|
||||
'height': self.height}
|
||||
if self.file_size:
|
||||
data['file_size'] = self.file_size
|
||||
return data
|
||||
Returns:
|
||||
telegram.PhotoSize:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return PhotoSize(**data)
|
||||
|
||||
@staticmethod
|
||||
def de_list(data):
|
||||
"""
|
||||
Args:
|
||||
data (list):
|
||||
|
||||
Returns:
|
||||
List<telegram.PhotoSize>:
|
||||
"""
|
||||
if not data:
|
||||
return []
|
||||
|
||||
photos = list()
|
||||
for photo in data:
|
||||
photos.append(PhotoSize.de_json(photo))
|
||||
|
||||
return photos
|
||||
|
||||
@@ -16,24 +16,45 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram
|
||||
ReplyKeyboardHide"""
|
||||
|
||||
from telegram import ReplyMarkup
|
||||
|
||||
|
||||
class ReplyKeyboardHide(ReplyMarkup):
|
||||
"""This object represents a Telegram ReplyKeyboardHide.
|
||||
|
||||
Attributes:
|
||||
hide_keyboard (bool):
|
||||
selective (bool):
|
||||
|
||||
Args:
|
||||
hide_keyboard (bool):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
selective (Optional[bool]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
hide_keyboard=True,
|
||||
selective=None):
|
||||
self.hide_keyboard = hide_keyboard
|
||||
self.selective = selective
|
||||
**kwargs):
|
||||
# Required
|
||||
self.hide_keyboard = bool(hide_keyboard)
|
||||
# Optionals
|
||||
self.selective = bool(kwargs.get('selective', False))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return ReplyKeyboardHide(hide_keyboard=data.get('hide_keyboard', None),
|
||||
selective=data.get('selective', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'hide_keyboard': self.hide_keyboard}
|
||||
if self.selective:
|
||||
data['selective'] = self.selective
|
||||
return data
|
||||
Returns:
|
||||
telegram.ReplyKeyboardHide:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return ReplyKeyboardHide(**data)
|
||||
|
||||
@@ -16,38 +16,51 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram
|
||||
ReplyKeyboardMarkup"""
|
||||
|
||||
from telegram import ReplyMarkup
|
||||
|
||||
|
||||
class ReplyKeyboardMarkup(ReplyMarkup):
|
||||
"""This object represents a Telegram ReplyKeyboardMarkup.
|
||||
|
||||
Attributes:
|
||||
keyboard (List[List[str]]):
|
||||
resize_keyboard (bool):
|
||||
one_time_keyboard (bool):
|
||||
selective (bool):
|
||||
|
||||
Args:
|
||||
keyboard (List[List[str]]):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
resize_keyboard (Optional[bool]):
|
||||
one_time_keyboard (Optional[bool]):
|
||||
selective (Optional[bool]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
keyboard,
|
||||
resize_keyboard=None,
|
||||
one_time_keyboard=None,
|
||||
selective=None):
|
||||
**kwargs):
|
||||
# Required
|
||||
self.keyboard = keyboard
|
||||
self.resize_keyboard = resize_keyboard
|
||||
self.one_time_keyboard = one_time_keyboard
|
||||
self.selective = selective
|
||||
# Optionals
|
||||
self.resize_keyboard = bool(kwargs.get('resize_keyboard', False))
|
||||
self.one_time_keyboard = bool(kwargs.get('one_time_keyboard', False))
|
||||
self.selective = bool(kwargs.get('selective', False))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return ReplyKeyboardMarkup(keyboard=data.get('keyboard', None),
|
||||
resize_keyboard=data.get(
|
||||
'resize_keyboard', None
|
||||
),
|
||||
one_time_keyboard=data.get(
|
||||
'one_time_keyboard', None
|
||||
),
|
||||
selective=data.get('selective', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'keyboard': self.keyboard}
|
||||
if self.resize_keyboard:
|
||||
data['resize_keyboard'] = self.resize_keyboard
|
||||
if self.one_time_keyboard:
|
||||
data['one_time_keyboard'] = self.one_time_keyboard
|
||||
if self.selective:
|
||||
data['selective'] = self.selective
|
||||
return data
|
||||
Returns:
|
||||
telegram.ReplyKeyboardMarkup:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return ReplyKeyboardMarkup(**data)
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""Base class for Telegram ReplyMarkup Objects"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class ReplyMarkup(TelegramObject):
|
||||
pass
|
||||
"""Base class for Telegram ReplyMarkup Objects"""
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
pass
|
||||
|
||||
+41
-26
@@ -16,42 +16,57 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Sticker"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
|
||||
|
||||
class Sticker(TelegramObject):
|
||||
"""This object represents a Telegram Sticker.
|
||||
|
||||
Attributes:
|
||||
file_id (str):
|
||||
width (int):
|
||||
height (int):
|
||||
thumb (:class:`telegram.PhotoSize`):
|
||||
file_size (int):
|
||||
|
||||
Args:
|
||||
file_id (str):
|
||||
width (int):
|
||||
height (int):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
thumb (Optional[:class:`telegram.PhotoSize`]):
|
||||
file_size (Optional[int]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
width,
|
||||
height,
|
||||
thumb=None,
|
||||
file_size=None):
|
||||
self.file_id = file_id
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.thumb = thumb
|
||||
self.file_size = file_size
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
# Optionals
|
||||
self.thumb = kwargs.get('thumb')
|
||||
self.file_size = int(kwargs.get('file_size', 0))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
if 'thumb' in data:
|
||||
from telegram import PhotoSize
|
||||
thumb = PhotoSize.de_json(data['thumb'])
|
||||
else:
|
||||
thumb = None
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
return Sticker(file_id=data.get('file_id', None),
|
||||
width=data.get('width', None),
|
||||
height=data.get('height', None),
|
||||
thumb=thumb,
|
||||
file_size=data.get('file_size', None))
|
||||
Returns:
|
||||
telegram.Sticker:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
def to_dict(self):
|
||||
data = {'file_id': self.file_id,
|
||||
'width': self.width,
|
||||
'height': self.height,
|
||||
'thumb': self.thumb.to_dict()}
|
||||
if self.file_size:
|
||||
data['file_size'] = self.file_size
|
||||
return data
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'))
|
||||
|
||||
return Sticker(**data)
|
||||
|
||||
+31
-16
@@ -16,30 +16,45 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Update"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram import Message, TelegramObject
|
||||
|
||||
|
||||
class Update(TelegramObject):
|
||||
"""This object represents a Telegram Update.
|
||||
|
||||
Attributes:
|
||||
update_id (int):
|
||||
message (:class:`telegram.Message`):
|
||||
|
||||
Args:
|
||||
update_id (int):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
message (Optional[:class:`telegram.Message`]):
|
||||
"""
|
||||
def __init__(self,
|
||||
update_id,
|
||||
message=None):
|
||||
self.update_id = update_id
|
||||
self.message = message
|
||||
**kwargs):
|
||||
# Required
|
||||
self.update_id = int(update_id)
|
||||
# Optionals
|
||||
self.message = kwargs.get('message')
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
if 'message' in data:
|
||||
from telegram import Message
|
||||
message = Message.de_json(data['message'])
|
||||
else:
|
||||
message = None
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
return Update(update_id=data.get('update_id', None),
|
||||
message=message)
|
||||
Returns:
|
||||
telegram.Update:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
def to_dict(self):
|
||||
data = {'update_id': self.update_id}
|
||||
if self.message:
|
||||
data['message'] = self.message.to_dict()
|
||||
return data
|
||||
data['message'] = Message.de_json(data['message'])
|
||||
|
||||
return Update(**data)
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
This module contains the class Updater, which tries to make creating Telegram
|
||||
Bots intuitive!
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import ssl
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
import subprocess
|
||||
from signal import signal, SIGINT, SIGTERM, SIGABRT
|
||||
from telegram import (Bot, TelegramError, dispatcher, Dispatcher,
|
||||
NullHandler)
|
||||
from telegram.utils.webhookhandler import (WebhookServer, WebhookHandler)
|
||||
|
||||
# Adjust for differences in Python versions
|
||||
try:
|
||||
from Queue import Queue
|
||||
except ImportError:
|
||||
from queue import Queue
|
||||
|
||||
try:
|
||||
from urllib2 import URLError
|
||||
except ImportError:
|
||||
from urllib.error import URLError
|
||||
|
||||
H = NullHandler()
|
||||
logging.getLogger(__name__).addHandler(H)
|
||||
|
||||
|
||||
class Updater:
|
||||
"""
|
||||
This class, which employs the Dispatcher class, provides a frontend to
|
||||
telegram.Bot to the programmer, so they can focus on coding the bot. It's
|
||||
purpose is to receive the updates from Telegram and to deliver them to said
|
||||
dispatcher. It also runs in a separate thread, so the user can interact
|
||||
with the bot, for example on the command line. The dispatcher supports
|
||||
handlers for different kinds of data: Updates from Telegram, basic text
|
||||
commands and even arbitrary types.
|
||||
The updater can be started as a polling service or, for production, use a
|
||||
webhook to receive updates. This is achieved using the WebhookServer and
|
||||
WebhookHandler classes.
|
||||
|
||||
|
||||
Attributes:
|
||||
|
||||
Args:
|
||||
token (str): The bots 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
|
||||
"""
|
||||
|
||||
def __init__(self, token, base_url=None, workers=4):
|
||||
|
||||
self.bot = Bot(token, base_url)
|
||||
self.update_queue = Queue()
|
||||
self.dispatcher = Dispatcher(self.bot, self.update_queue,
|
||||
workers=workers)
|
||||
self.last_update_id = 0
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.running = False
|
||||
self.is_idle = False
|
||||
self.httpd = None
|
||||
|
||||
def start_polling(self, poll_interval=1.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
|
||||
timeout (Optional[float]): Passed to Bot.getUpdates
|
||||
network_delay (Optional[float]): Passed to Bot.getUpdates
|
||||
|
||||
Returns:
|
||||
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))
|
||||
|
||||
self.running = True
|
||||
|
||||
# Start threads
|
||||
dispatcher_thread.start()
|
||||
event_handler_thread.start()
|
||||
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
|
||||
def start_webhook(self,
|
||||
listen='127.0.0.1',
|
||||
port=80,
|
||||
url_path='',
|
||||
cert=None,
|
||||
key=None):
|
||||
"""
|
||||
Starts a small http server to listen for updates via webhook. If cert
|
||||
and key are not provided, the webhook will be started directly on
|
||||
http://listen:port/url_path, so SSL can be handled by another
|
||||
application. Else, the webhook will be started on
|
||||
https://listen:port/url_path
|
||||
|
||||
Args:
|
||||
listen (Optional[str]): IP-Address to listen on
|
||||
port (Optional[int]): Port the bot should be listening on
|
||||
url_path (Optional[str]): Path inside url
|
||||
cert (Optional[str]): Path to the SSL certificate file
|
||||
key (Optional[str]): Path to the SSL key file
|
||||
|
||||
Returns:
|
||||
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))
|
||||
|
||||
self.running = True
|
||||
|
||||
# Start threads
|
||||
dispatcher_thread.start()
|
||||
event_handler_thread.start()
|
||||
|
||||
# Return the update queue so the main thread can insert updates
|
||||
return self.update_queue
|
||||
|
||||
def _start_polling(self, poll_interval, timeout, network_delay):
|
||||
"""
|
||||
Thread target of thread 'updater'. Runs in background, pulls
|
||||
updates from Telegram and inserts them in the update queue of the
|
||||
Dispatcher.
|
||||
"""
|
||||
|
||||
current_interval = poll_interval
|
||||
self.logger.info('Updater thread started')
|
||||
|
||||
# Remove webhook
|
||||
self.bot.setWebhook(webhook_url=None)
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
updates = self.bot.getUpdates(self.last_update_id,
|
||||
timeout=timeout,
|
||||
network_delay=network_delay)
|
||||
if not self.running:
|
||||
if len(updates) > 0:
|
||||
self.logger.info('Updates ignored and will be pulled '
|
||||
'again on restart.')
|
||||
break
|
||||
|
||||
for update in updates:
|
||||
self.update_queue.put(update)
|
||||
self.last_update_id = update.update_id + 1
|
||||
current_interval = poll_interval
|
||||
|
||||
sleep(current_interval)
|
||||
except TelegramError as te:
|
||||
# Put the error into the update queue and let the Dispatcher
|
||||
# broadcast it
|
||||
self.update_queue.put(te)
|
||||
sleep(current_interval)
|
||||
|
||||
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:
|
||||
current_interval += current_interval / 2
|
||||
if current_interval > 30:
|
||||
current_interval = 30
|
||||
|
||||
self.logger.info('Updater thread stopped')
|
||||
|
||||
def _start_webhook(self, listen, port, url_path, cert, key):
|
||||
self.logger.info('Updater thread started')
|
||||
use_ssl = cert is not None and key is not None
|
||||
url_path = "/%s" % url_path
|
||||
|
||||
# Create and start server
|
||||
self.httpd = WebhookServer((listen, port), WebhookHandler,
|
||||
self.update_queue, url_path)
|
||||
|
||||
if use_ssl:
|
||||
# Check SSL-Certificate with openssl, if possible
|
||||
try:
|
||||
exit_code = subprocess.call(["openssl", "x509", "-text",
|
||||
"-noout", "-in", cert],
|
||||
stdout=open(os.devnull, 'wb'),
|
||||
stderr=subprocess.STDOUT)
|
||||
except OSError:
|
||||
exit_code = 0
|
||||
|
||||
if exit_code is 0:
|
||||
try:
|
||||
self.httpd.socket = ssl.wrap_socket(self.httpd.socket,
|
||||
certfile=cert,
|
||||
keyfile=key,
|
||||
server_side=True)
|
||||
except ssl.SSLError as error:
|
||||
raise TelegramError(str(error))
|
||||
else:
|
||||
raise TelegramError('SSL Certificate invalid')
|
||||
|
||||
self.httpd.serve_forever(poll_interval=1)
|
||||
self.logger.info('Updater thread stopped')
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops the polling/webhook thread and the dispatcher
|
||||
"""
|
||||
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.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
|
||||
self.stop()
|
||||
|
||||
def idle(self, stop_signals=(SIGINT, SIGTERM, SIGABRT)):
|
||||
"""
|
||||
Waits for the user to press Ctrl-C 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.
|
||||
"""
|
||||
for sig in stop_signals:
|
||||
signal(sig, self.signal_handler)
|
||||
|
||||
self.is_idle = True
|
||||
|
||||
while self.is_idle:
|
||||
sleep(1)
|
||||
+40
-17
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# pylint: disable=C0103,W0622
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
@@ -16,23 +17,47 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram User"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class User(TelegramObject):
|
||||
"""This object represents a Telegram User.
|
||||
|
||||
Attributes:
|
||||
id (int):
|
||||
first_name (str):
|
||||
last_name (str):
|
||||
username (str):
|
||||
type (str):
|
||||
|
||||
Args:
|
||||
id (int):
|
||||
first_name (str):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
type (Optional[str]):
|
||||
last_name (Optional[str]):
|
||||
username (Optional[str]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id,
|
||||
first_name,
|
||||
last_name=None,
|
||||
username=None):
|
||||
self.id = id
|
||||
**kwargs):
|
||||
# Required
|
||||
self.id = int(id)
|
||||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.username = username
|
||||
# Optionals
|
||||
self.type = kwargs.get('type', '')
|
||||
self.last_name = kwargs.get('last_name', '')
|
||||
self.username = kwargs.get('username', '')
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""str: """
|
||||
if self.username:
|
||||
return '@%s' % self.username
|
||||
if self.last_name:
|
||||
@@ -41,16 +66,14 @@ class User(TelegramObject):
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
return User(id=data.get('id', None),
|
||||
first_name=data.get('first_name', None),
|
||||
last_name=data.get('last_name', None),
|
||||
username=data.get('username', None))
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
def to_dict(self):
|
||||
data = {'id': self.id,
|
||||
'first_name': self.first_name}
|
||||
if self.last_name:
|
||||
data['last_name'] = self.last_name
|
||||
if self.username:
|
||||
data['username'] = self.username
|
||||
return data
|
||||
Returns:
|
||||
telegram.User:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return User(**data)
|
||||
|
||||
@@ -16,36 +16,56 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram
|
||||
UserProfilePhotos"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
|
||||
|
||||
class UserProfilePhotos(TelegramObject):
|
||||
"""This object represents a Telegram UserProfilePhotos.
|
||||
|
||||
Attributes:
|
||||
total_count (int):
|
||||
photos (List[List[:class:`telegram.PhotoSize`]]):
|
||||
|
||||
Args:
|
||||
total_count (int):
|
||||
photos (List[List[:class:`telegram.PhotoSize`]]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
total_count,
|
||||
photos):
|
||||
self.total_count = total_count
|
||||
# Required
|
||||
self.total_count = int(total_count)
|
||||
self.photos = photos
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
if 'photos' in data:
|
||||
from telegram import PhotoSize
|
||||
photos = []
|
||||
for photo in data['photos']:
|
||||
photos.append([PhotoSize.de_json(x) for x in photo])
|
||||
else:
|
||||
photos = None
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
return UserProfilePhotos(total_count=data.get('total_count', None),
|
||||
photos=photos)
|
||||
Returns:
|
||||
telegram.UserProfilePhotos:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data['photos'] = [PhotoSize.de_list(photo) for photo in data['photos']]
|
||||
|
||||
return UserProfilePhotos(**data)
|
||||
|
||||
def to_dict(self):
|
||||
data = {}
|
||||
if self.total_count:
|
||||
data['total_count'] = self.total_count
|
||||
if self.photos:
|
||||
data['photos'] = []
|
||||
for photo in self.photos:
|
||||
data['photos'].append([x.to_dict() for x in photo])
|
||||
"""
|
||||
Returns:
|
||||
dict:
|
||||
"""
|
||||
data = super(UserProfilePhotos, self).to_dict()
|
||||
|
||||
data['photos'] = []
|
||||
for photo in self.photos:
|
||||
data['photos'].append([x.to_dict() for x in photo])
|
||||
|
||||
return data
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env python
|
||||
# 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>
|
||||
#
|
||||
# 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 methods to make POST and GET requests"""
|
||||
|
||||
import json
|
||||
import socket
|
||||
from ssl import SSLError
|
||||
|
||||
try:
|
||||
from urllib.request import urlopen, urlretrieve, Request
|
||||
from urllib.error import HTTPError
|
||||
except ImportError:
|
||||
from urllib import urlretrieve
|
||||
from urllib2 import urlopen, Request
|
||||
from urllib2 import HTTPError
|
||||
|
||||
from telegram import (InputFile, TelegramError)
|
||||
|
||||
|
||||
def _parse(json_data):
|
||||
"""Try and parse the JSON returned from Telegram and return an empty
|
||||
dictionary if there is any error.
|
||||
|
||||
Args:
|
||||
url:
|
||||
urllib.urlopen object
|
||||
|
||||
Returns:
|
||||
A JSON parsed as Python dict with results.
|
||||
"""
|
||||
data = json.loads(json_data.decode())
|
||||
|
||||
if not data.get('ok') and data.get('description'):
|
||||
return data['description']
|
||||
|
||||
return data['result']
|
||||
|
||||
|
||||
def get(url):
|
||||
"""Request an URL.
|
||||
Args:
|
||||
url:
|
||||
The web location we want to retrieve.
|
||||
|
||||
Returns:
|
||||
A JSON object.
|
||||
"""
|
||||
result = urlopen(url).read()
|
||||
|
||||
return _parse(result)
|
||||
|
||||
|
||||
def post(url,
|
||||
data,
|
||||
network_delay=2.):
|
||||
"""Request an URL.
|
||||
Args:
|
||||
url:
|
||||
The web location we want to retrieve.
|
||||
data:
|
||||
A dict of (str, unicode) key/value pairs.
|
||||
network_delay:
|
||||
Additional timeout in seconds to allow the response from Telegram to
|
||||
take some time.
|
||||
|
||||
Returns:
|
||||
A JSON object.
|
||||
"""
|
||||
|
||||
# Add time to the timeout of urlopen to allow data to be transferred over
|
||||
# the network.
|
||||
if 'timeout' in data:
|
||||
timeout = data['timeout'] + network_delay
|
||||
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'})
|
||||
|
||||
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))
|
||||
return _parse(result)
|
||||
|
||||
|
||||
def download(url,
|
||||
filename):
|
||||
"""Download a file by its URL.
|
||||
Args:
|
||||
url:
|
||||
The web location we want to retrieve.
|
||||
|
||||
filename:
|
||||
The filename wihtin the path to download the file.
|
||||
"""
|
||||
|
||||
urlretrieve(url, filename)
|
||||
@@ -0,0 +1,85 @@
|
||||
import logging
|
||||
|
||||
from telegram import Update, NullHandler
|
||||
from future.utils import bytes_to_native_str as n
|
||||
from threading import Lock
|
||||
import json
|
||||
try:
|
||||
import BaseHTTPServer
|
||||
except ImportError:
|
||||
import http.server as BaseHTTPServer
|
||||
|
||||
|
||||
H = NullHandler()
|
||||
logging.getLogger(__name__).addHandler(H)
|
||||
|
||||
|
||||
class WebhookServer(BaseHTTPServer.HTTPServer, object):
|
||||
def __init__(self, server_address, RequestHandlerClass, update_queue,
|
||||
webhook_path):
|
||||
super(WebhookServer, self).__init__(server_address,
|
||||
RequestHandlerClass)
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.update_queue = update_queue
|
||||
self.webhook_path = webhook_path
|
||||
self.is_running = False
|
||||
self.server_lock = Lock()
|
||||
self.shutdown_lock = Lock()
|
||||
|
||||
def serve_forever(self, poll_interval=0.5):
|
||||
with self.server_lock:
|
||||
self.is_running = True
|
||||
self.logger.info("Webhook Server started.")
|
||||
super(WebhookServer, self).serve_forever(poll_interval)
|
||||
self.logger.info("Webhook Server stopped.")
|
||||
|
||||
def shutdown(self):
|
||||
with self.shutdown_lock:
|
||||
if not self.is_running:
|
||||
self.logger.warn("Webhook Server already stopped.")
|
||||
return
|
||||
else:
|
||||
super(WebhookServer, self).shutdown()
|
||||
self.is_running = False
|
||||
|
||||
|
||||
# WebhookHandler, process webhook calls
|
||||
# Based on: https://github.com/eternnoir/pyTelegramBotAPI/blob/master/
|
||||
# examples/webhook_examples/webhook_cpython_echo_bot.py
|
||||
class WebhookHandler(BaseHTTPServer.BaseHTTPRequestHandler, object):
|
||||
server_version = "WebhookHandler/1.0"
|
||||
|
||||
def __init__(self, request, client_address, server):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
super(WebhookHandler, self).__init__(request, client_address, server)
|
||||
|
||||
def do_HEAD(self):
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
def do_POST(self):
|
||||
self.logger.debug("Webhook triggered")
|
||||
if self.path == self.server.webhook_path and \
|
||||
'content-type' in self.headers and \
|
||||
'content-length' in self.headers and \
|
||||
self.headers['content-type'] == 'application/json':
|
||||
json_string = \
|
||||
n(self.rfile.read(int(self.headers['content-length'])))
|
||||
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
self.logger.debug("Webhook received data: " + json_string)
|
||||
|
||||
update = Update.de_json(json.loads(json_string))
|
||||
self.logger.info("Received Update with ID %d on Webhook" %
|
||||
update.update_id)
|
||||
self.server.update_queue.put(update)
|
||||
|
||||
else:
|
||||
self.send_error(403)
|
||||
self.end_headers()
|
||||
+47
-35
@@ -16,52 +16,64 @@
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Video"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram import PhotoSize, TelegramObject
|
||||
|
||||
|
||||
class Video(TelegramObject):
|
||||
"""This object represents a Telegram Video.
|
||||
|
||||
Attributes:
|
||||
file_id (str):
|
||||
width (int):
|
||||
height (int):
|
||||
duration (int):
|
||||
thumb (:class:`telegram.PhotoSize`):
|
||||
mime_type (str):
|
||||
file_size (int):
|
||||
|
||||
Args:
|
||||
file_id (str):
|
||||
width (int):
|
||||
height (int):
|
||||
duration (int):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
thumb (Optional[:class:`telegram.PhotoSize`]):
|
||||
mime_type (Optional[str]):
|
||||
file_size (Optional[int]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
width,
|
||||
height,
|
||||
duration,
|
||||
thumb=None,
|
||||
mime_type=None,
|
||||
file_size=None):
|
||||
self.file_id = file_id
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.duration = duration
|
||||
self.thumb = thumb
|
||||
self.mime_type = mime_type
|
||||
self.file_size = file_size
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
self.duration = int(duration)
|
||||
# Optionals
|
||||
self.thumb = kwargs.get('thumb')
|
||||
self.mime_type = str(kwargs.get('mime_type', ''))
|
||||
self.file_size = int(kwargs.get('file_size', 0))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
if 'thumb' in data:
|
||||
from telegram import PhotoSize
|
||||
thumb = PhotoSize.de_json(data['thumb'])
|
||||
else:
|
||||
thumb = None
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
return Video(file_id=data.get('file_id', None),
|
||||
width=data.get('width', None),
|
||||
height=data.get('height', None),
|
||||
duration=data.get('duration', None),
|
||||
thumb=thumb,
|
||||
mime_type=data.get('mime_type', None),
|
||||
file_size=data.get('file_size', None))
|
||||
Returns:
|
||||
telegram.Video:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
def to_dict(self):
|
||||
data = {'file_id': self.file_id,
|
||||
'width': self.width,
|
||||
'height': self.height,
|
||||
'duration': self.duration}
|
||||
if self.thumb:
|
||||
data['thumb'] = self.thumb.to_dict()
|
||||
if self.mime_type:
|
||||
data['mime_type'] = self.mime_type
|
||||
if self.file_size:
|
||||
data['file_size'] = self.file_size
|
||||
return data
|
||||
data['thumb'] = PhotoSize.de_json(data.get('thumb'))
|
||||
|
||||
return Video(**data)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
"""This module contains a object that represents a Telegram Voice"""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class Voice(TelegramObject):
|
||||
"""This object represents a Telegram Voice.
|
||||
|
||||
Attributes:
|
||||
file_id (str):
|
||||
duration (int):
|
||||
mime_type (str):
|
||||
file_size (int):
|
||||
|
||||
Args:
|
||||
file_id (str):
|
||||
**kwargs: Arbitrary keyword arguments.
|
||||
|
||||
Keyword Args:
|
||||
duration (Optional[int]):
|
||||
mime_type (Optional[str]):
|
||||
file_size (Optional[int]):
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
# Optionals
|
||||
self.duration = int(kwargs.get('duration', 0))
|
||||
self.mime_type = str(kwargs.get('mime_type', ''))
|
||||
self.file_size = int(kwargs.get('file_size', 0))
|
||||
|
||||
@staticmethod
|
||||
def de_json(data):
|
||||
"""
|
||||
Args:
|
||||
data (str):
|
||||
|
||||
Returns:
|
||||
telegram.Voice:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return Voice(**data)
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 a Base class for tests"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import json
|
||||
import telegram
|
||||
|
||||
|
||||
class BaseTest(object):
|
||||
"""This object represents a Base test and its sets of functions."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BaseTest, self).__init__(*args, **kwargs)
|
||||
|
||||
bot = telegram.Bot(os.environ.get('TOKEN'))
|
||||
chat_id = os.environ.get('CHAT_ID')
|
||||
|
||||
self._bot = bot
|
||||
self._chat_id = chat_id
|
||||
|
||||
@staticmethod
|
||||
def is_json(string):
|
||||
try:
|
||||
json.loads(string)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def is_dict(dictionary):
|
||||
if isinstance(dictionary, dict):
|
||||
return True
|
||||
|
||||
return False
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Audio"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class AudioTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Audio."""
|
||||
|
||||
def setUp(self):
|
||||
self.audio_file = open('tests/data/telegram.mp3', 'rb')
|
||||
self.audio_file_id = 'BQADAQADDwADHyP1B6PSPq2HjX8kAg'
|
||||
self.duration = 4
|
||||
self.performer = 'Leandro Toledo'
|
||||
self.title = 'Teste'
|
||||
self.mime_type = 'audio/mpeg'
|
||||
self.file_size = 28232
|
||||
|
||||
self.json_dict = {
|
||||
'file_id': self.audio_file_id,
|
||||
'duration': self.duration,
|
||||
'performer': self.performer,
|
||||
'title': self.title,
|
||||
'mime_type': self.mime_type,
|
||||
'file_size': self.file_size
|
||||
}
|
||||
|
||||
def test_send_audio_required_args_only(self):
|
||||
"""Test telegram.Bot sendAudio method"""
|
||||
print('Testing bot.sendAudio - With required arguments only')
|
||||
|
||||
message = self._bot.sendAudio(self._chat_id,
|
||||
self.audio_file)
|
||||
|
||||
audio = message.audio
|
||||
|
||||
self.assertTrue(isinstance(audio.file_id, str))
|
||||
self.assertNotEqual(audio.file_id, '')
|
||||
self.assertEqual(audio.duration, 4)
|
||||
self.assertEqual(audio.performer, '')
|
||||
self.assertEqual(audio.title, '')
|
||||
self.assertEqual(audio.mime_type, self.mime_type)
|
||||
self.assertEqual(audio.file_size, self.file_size)
|
||||
|
||||
def test_send_audio_all_args(self):
|
||||
"""Test telegram.Bot sendAudio method"""
|
||||
print('Testing bot.sendAudio - With all arguments')
|
||||
|
||||
message = self._bot.sendAudio(self._chat_id,
|
||||
self.audio_file,
|
||||
duration=self.duration,
|
||||
performer=self.performer,
|
||||
title=self.title,
|
||||
mime_type=self.mime_type,
|
||||
file_size=self.file_size)
|
||||
|
||||
audio = message.audio
|
||||
|
||||
self.assertTrue(isinstance(audio.file_id, str))
|
||||
self.assertNotEqual(audio.file_id, '')
|
||||
self.assertEqual(audio.duration, self.duration)
|
||||
self.assertEqual(audio.performer, self.performer)
|
||||
self.assertEqual(audio.title, self.title)
|
||||
self.assertEqual(audio.mime_type, self.mime_type)
|
||||
self.assertEqual(audio.file_size, self.file_size)
|
||||
|
||||
def test_send_audio_mp3_file(self):
|
||||
"""Test telegram.Bot sendAudio method"""
|
||||
print('Testing bot.sendAudio - MP3 File')
|
||||
|
||||
message = self._bot.sendAudio(chat_id=self._chat_id,
|
||||
audio=self.audio_file,
|
||||
duration=self.duration,
|
||||
performer=self.performer,
|
||||
title=self.title)
|
||||
|
||||
audio = message.audio
|
||||
|
||||
self.assertTrue(isinstance(audio.file_id, str))
|
||||
self.assertNotEqual(audio.file_id, '')
|
||||
self.assertEqual(audio.duration, self.duration)
|
||||
self.assertEqual(audio.performer, self.performer)
|
||||
self.assertEqual(audio.title, self.title)
|
||||
self.assertEqual(audio.mime_type, self.mime_type)
|
||||
self.assertEqual(audio.file_size, self.file_size)
|
||||
|
||||
def test_send_audio_mp3_file_custom_filename(self):
|
||||
"""Test telegram.Bot sendAudio method"""
|
||||
print('Testing bot.sendAudio - MP3 File with custom filename')
|
||||
|
||||
message = self._bot.sendAudio(chat_id=self._chat_id,
|
||||
audio=self.audio_file,
|
||||
duration=self.duration,
|
||||
performer=self.performer,
|
||||
title=self.title,
|
||||
filename='telegram_custom.mp3')
|
||||
|
||||
audio = message.audio
|
||||
|
||||
self.assertTrue(isinstance(audio.file_id, str))
|
||||
self.assertNotEqual(audio.file_id, '')
|
||||
self.assertEqual(audio.duration, self.duration)
|
||||
self.assertEqual(audio.performer, self.performer)
|
||||
self.assertEqual(audio.title, self.title)
|
||||
self.assertEqual(audio.mime_type, self.mime_type)
|
||||
self.assertEqual(audio.file_size, self.file_size)
|
||||
|
||||
def test_send_audio_resend(self):
|
||||
"""Test telegram.Bot sendAudio method"""
|
||||
print('Testing bot.sendAudio - Resend by file_id')
|
||||
|
||||
message = self._bot.sendAudio(chat_id=self._chat_id,
|
||||
audio=self.audio_file_id,
|
||||
duration=self.duration,
|
||||
performer=self.performer,
|
||||
title=self.title)
|
||||
|
||||
audio = message.audio
|
||||
|
||||
self.assertEqual(audio.file_id, self.audio_file_id)
|
||||
self.assertEqual(audio.duration, self.duration)
|
||||
self.assertEqual(audio.performer, self.performer)
|
||||
self.assertEqual(audio.title, self.title)
|
||||
self.assertEqual(audio.mime_type, self.mime_type)
|
||||
|
||||
def test_audio_de_json(self):
|
||||
"""Test Audio.de_json() method"""
|
||||
print('Testing Audio.de_json()')
|
||||
|
||||
audio = telegram.Audio.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(audio.file_id, self.audio_file_id)
|
||||
self.assertEqual(audio.duration, self.duration)
|
||||
self.assertEqual(audio.performer, self.performer)
|
||||
self.assertEqual(audio.title, self.title)
|
||||
self.assertEqual(audio.mime_type, self.mime_type)
|
||||
self.assertEqual(audio.file_size, self.file_size)
|
||||
|
||||
def test_audio_to_json(self):
|
||||
"""Test Audio.to_json() method"""
|
||||
print('Testing Audio.to_json()')
|
||||
|
||||
audio = telegram.Audio.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(audio.to_json()))
|
||||
|
||||
def test_audio_to_dict(self):
|
||||
"""Test Audio.to_dict() method"""
|
||||
print('Testing Audio.to_dict()')
|
||||
|
||||
audio = telegram.Audio.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(audio.to_dict()))
|
||||
self.assertEqual(audio['file_id'], self.audio_file_id)
|
||||
self.assertEqual(audio['duration'], self.duration)
|
||||
self.assertEqual(audio['performer'], self.performer)
|
||||
self.assertEqual(audio['title'], self.title)
|
||||
self.assertEqual(audio['mime_type'], self.mime_type)
|
||||
self.assertEqual(audio['file_size'], self.file_size)
|
||||
|
||||
def test_error_send_audio_empty_file(self):
|
||||
print('Testing bot.sendAudio - Null file')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['audio'] = open(os.devnull, 'rb')
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendAudio(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_send_audio_empty_file_id(self):
|
||||
print('Testing bot.sendAudio - Empty file_id')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['audio'] = ''
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendAudio(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_audio_without_required_args(self):
|
||||
print('Testing bot.sendAudio - Without required arguments')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
del(json_dict['duration'])
|
||||
|
||||
self.assertRaises(TypeError,
|
||||
lambda: self._bot.sendAudio(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
+72
-90
@@ -17,143 +17,125 @@
|
||||
# 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 Bot"""
|
||||
|
||||
import os
|
||||
import telegram
|
||||
import unittest
|
||||
from datetime import datetime
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class BotTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
bot = telegram.Bot(token=os.environ.get('TOKEN'))
|
||||
self._bot = bot
|
||||
print('Testing the Bot API class')
|
||||
class BotTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Bot."""
|
||||
|
||||
def testGetMe(self):
|
||||
'''Test the telegram.Bot getMe method'''
|
||||
print('Testing getMe')
|
||||
bot = self._bot.getMe()
|
||||
self.assertEqual(120405045, bot.id)
|
||||
self.assertEqual('Toledo\'s Palace Bot', bot.first_name)
|
||||
self.assertEqual(None, bot.last_name)
|
||||
self.assertEqual('ToledosPalaceBot', bot.username)
|
||||
|
||||
self.assertTrue(self.is_json(bot.to_json()))
|
||||
self.assertEqual(bot.id, 133505823)
|
||||
self.assertEqual(bot.first_name, 'PythonTelegramBot')
|
||||
self.assertEqual(bot.last_name, '')
|
||||
self.assertEqual(bot.username, 'PythonTelegramBot')
|
||||
self.assertEqual(bot.name, '@PythonTelegramBot')
|
||||
|
||||
def testSendMessage(self):
|
||||
'''Test the telegram.Bot sendMessage method'''
|
||||
print('Testing sendMessage')
|
||||
message = self._bot.sendMessage(chat_id=12173560,
|
||||
message = self._bot.sendMessage(chat_id=self._chat_id,
|
||||
text='Моё судно на воздушной подушке полно угрей')
|
||||
self.assertEqual(u'Моё судно на воздушной подушке полно угрей', message.text)
|
||||
self.assertIsInstance(message.date, datetime)
|
||||
|
||||
self.assertTrue(self.is_json(message.to_json()))
|
||||
self.assertEqual(message.text, u'Моё судно на воздушной подушке полно угрей')
|
||||
self.assertTrue(isinstance(message.date, datetime))
|
||||
|
||||
def testGetUpdates(self):
|
||||
'''Test the telegram.Bot getUpdates method'''
|
||||
print('Testing getUpdates')
|
||||
updates = self._bot.getUpdates()
|
||||
self.assertIsInstance(updates[0], telegram.Update)
|
||||
|
||||
if updates:
|
||||
self.assertTrue(self.is_json(updates[0].to_json()))
|
||||
self.assertTrue(isinstance(updates[0], telegram.Update))
|
||||
|
||||
def testForwardMessage(self):
|
||||
'''Test the telegram.Bot forwardMessage method'''
|
||||
print('Testing forwardMessage')
|
||||
message = self._bot.forwardMessage(chat_id=12173560,
|
||||
from_chat_id=12173560,
|
||||
message_id=138)
|
||||
self.assertEqual('Oi', message.text)
|
||||
self.assertEqual('leandrotoledo', message.forward_from.username)
|
||||
self.assertIsInstance(message.forward_date, datetime)
|
||||
message = self._bot.forwardMessage(chat_id=self._chat_id,
|
||||
from_chat_id=self._chat_id,
|
||||
message_id=2398)
|
||||
|
||||
self.assertTrue(self.is_json(message.to_json()))
|
||||
self.assertEqual(message.text, 'teste')
|
||||
self.assertEqual(message.forward_from.username, 'leandrotoledo')
|
||||
self.assertTrue(isinstance(message.forward_date, datetime))
|
||||
|
||||
def testSendPhoto(self):
|
||||
'''Test the telegram.Bot sendPhoto method'''
|
||||
print('Testing sendPhoto - File')
|
||||
message = self._bot.sendPhoto(photo=open('tests/telegram.png', 'rb'),
|
||||
message = self._bot.sendPhoto(photo=open('tests/data/telegram.png', 'rb'),
|
||||
caption='testSendPhoto',
|
||||
chat_id=12173560)
|
||||
self.assertEqual(1451, message.photo[0].file_size)
|
||||
self.assertEqual('testSendPhoto', message.caption)
|
||||
chat_id=self._chat_id)
|
||||
|
||||
self.assertTrue(self.is_json(message.to_json()))
|
||||
self.assertEqual(message.photo[0].file_size, 1451)
|
||||
self.assertEqual(message.caption, 'testSendPhoto')
|
||||
|
||||
def testResendPhoto(self):
|
||||
'''Test the telegram.Bot sendPhoto method'''
|
||||
print('Testing sendPhoto - Resend')
|
||||
message = self._bot.sendPhoto(photo=str('AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI'),
|
||||
chat_id=12173560)
|
||||
self.assertEqual('AgADAQADr6cxGzU8LQe6q0dMJD2rHYkP2ykABFymiQqJgjxRGGMAAgI', message.photo[0].file_id)
|
||||
message = self._bot.sendPhoto(photo='AgADAQADyKcxGx8j9Qdp6d-gpUsw4Gja1i8ABEVJsVqQk8LfJ3wAAgI',
|
||||
chat_id=self._chat_id)
|
||||
|
||||
def testSendURLPhoto(self):
|
||||
self.assertTrue(self.is_json(message.to_json()))
|
||||
self.assertEqual(message.photo[0].file_id, 'AgADAQADyKcxGx8j9Qdp6d-gpUsw4Gja1i8ABEVJsVqQk8LfJ3wAAgI')
|
||||
|
||||
def testSendJPGURLPhoto(self):
|
||||
'''Test the telegram.Bot sendPhoto method'''
|
||||
print('Testing sendPhoto - URL')
|
||||
message = self._bot.sendPhoto(photo=str('http://dummyimage.com/600x400/000/fff.jpg&text=telegram'),
|
||||
chat_id=12173560)
|
||||
self.assertEqual(822, message.photo[0].file_size)
|
||||
print('Testing testSendJPGURLPhoto - URL')
|
||||
message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.jpg&text=telegram',
|
||||
chat_id=self._chat_id)
|
||||
|
||||
def testSendAudio(self):
|
||||
'''Test the telegram.Bot sendAudio method'''
|
||||
print('Testing sendAudio - File')
|
||||
message = self._bot.sendAudio(audio=open('tests/telegram.ogg', 'rb'),
|
||||
chat_id=12173560)
|
||||
self.assertEqual(9199, message.audio.file_size)
|
||||
self.assertTrue(self.is_json(message.to_json()))
|
||||
self.assertEqual(message.photo[0].file_size, 822)
|
||||
|
||||
def testResendAudio(self):
|
||||
'''Test the telegram.Bot sendAudio method'''
|
||||
print('Testing sendAudio - Resend')
|
||||
message = self._bot.sendAudio(audio=str('AwADAQADIQEAAvjAuQABSAXg_GhkhZcC'),
|
||||
chat_id=12173560)
|
||||
self.assertEqual('AwADAQADIQEAAvjAuQABSAXg_GhkhZcC', message.audio.file_id)
|
||||
def testSendPNGURLPhoto(self):
|
||||
'''Test the telegram.Bot sendPhoto method'''
|
||||
print('Testing testSendPNGURLPhoto - URL')
|
||||
message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.png&text=telegram',
|
||||
chat_id=self._chat_id)
|
||||
|
||||
def testSendDocument(self):
|
||||
'''Test the telegram.Bot sendDocument method'''
|
||||
print('Testing sendDocument - File')
|
||||
message = self._bot.sendDocument(document=open('tests/telegram.png', 'rb'),
|
||||
chat_id=12173560)
|
||||
self.assertEqual(12948, message.document.file_size)
|
||||
self.assertTrue(self.is_json(message.to_json()))
|
||||
self.assertEqual(message.photo[0].file_size, 684)
|
||||
|
||||
def testResendDocument(self):
|
||||
'''Test the telegram.Bot sendDocument method'''
|
||||
print('Testing sendDocument - Resend')
|
||||
message = self._bot.sendDocument(document=str('BQADAQADHAADNTwtBxZxUGKyxYbYAg'),
|
||||
chat_id=12173560)
|
||||
self.assertEqual('BQADAQADHAADNTwtBxZxUGKyxYbYAg', message.document.file_id)
|
||||
def testSendGIFURLPhoto(self):
|
||||
'''Test the telegram.Bot sendPhoto method'''
|
||||
print('Testing testSendGIFURLPhoto - URL')
|
||||
message = self._bot.sendPhoto(photo='http://dummyimage.com/600x400/000/fff.gif&text=telegram',
|
||||
chat_id=self._chat_id)
|
||||
|
||||
def testSendVideo(self):
|
||||
'''Test the telegram.Bot sendVideo method'''
|
||||
print('Testing sendVideo - File')
|
||||
message = self._bot.sendVideo(video=open('tests/telegram.mp4', 'rb'),
|
||||
caption='testSendVideo',
|
||||
chat_id=12173560)
|
||||
self.assertEqual(326534, message.video.file_size)
|
||||
self.assertEqual('testSendVideo', message.caption)
|
||||
|
||||
def testResendVideo(self):
|
||||
'''Test the telegram.Bot sendVideo method'''
|
||||
print('Testing sendVideo - Resend')
|
||||
message = self._bot.sendVideo(video=str('BAADAQADIgEAAvjAuQABOuTB937fPTgC'),
|
||||
chat_id=12173560)
|
||||
self.assertEqual(4, message.video.duration)
|
||||
|
||||
def testResendSticker(self):
|
||||
'''Test the telegram.Bot sendSticker method'''
|
||||
print('Testing sendSticker - Resend')
|
||||
message = self._bot.sendSticker(sticker=str('BQADAQADHAADyIsGAAFZfq1bphjqlgI'),
|
||||
chat_id=12173560)
|
||||
self.assertEqual(39518, message.sticker.file_size)
|
||||
|
||||
def testSendLocation(self):
|
||||
'''Test the telegram.Bot sendLocation method'''
|
||||
print('Testing sendLocation')
|
||||
message = self._bot.sendLocation(latitude=-23.558873,
|
||||
longitude=-46.659732,
|
||||
chat_id=12173560)
|
||||
self.assertEqual(-23.558873, message.location.latitude)
|
||||
self.assertEqual(-46.659732, message.location.longitude)
|
||||
self.assertTrue(self.is_json(message.to_json()))
|
||||
self.assertEqual(message.photo[0].file_size, 684)
|
||||
|
||||
def testSendChatAction(self):
|
||||
'''Test the telegram.Bot sendChatAction method'''
|
||||
print('Testing sendChatAction - ChatAction.TYPING')
|
||||
|
||||
self._bot.sendChatAction(action=telegram.ChatAction.TYPING,
|
||||
chat_id=12173560)
|
||||
chat_id=self._chat_id)
|
||||
|
||||
def testGetUserProfilePhotos(self):
|
||||
'''Test the telegram.Bot getUserProfilePhotos method'''
|
||||
print('Testing getUserProfilePhotos')
|
||||
upf = self._bot.getUserProfilePhotos(user_id=12173560)
|
||||
self.assertEqual(6547, upf.photos[0][0].file_size)
|
||||
upf = self._bot.getUserProfilePhotos(user_id=self._chat_id)
|
||||
|
||||
self.assertTrue(self.is_json(upf.to_json()))
|
||||
self.assertEqual(upf.photos[0][0].file_size, 12421)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Contact"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class ContactTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Contact."""
|
||||
|
||||
def setUp(self):
|
||||
self.phone_number = '+11234567890'
|
||||
self.first_name = 'Leandro Toledo'
|
||||
self.last_name = ''
|
||||
self.user_id = 0
|
||||
|
||||
self.json_dict = {
|
||||
'phone_number': self.phone_number,
|
||||
'first_name': self.first_name,
|
||||
'last_name': self.last_name,
|
||||
'user_id': self.user_id
|
||||
}
|
||||
|
||||
def test_contact_de_json(self):
|
||||
"""Test Contact.de_json() method"""
|
||||
print('Testing Contact.de_json()')
|
||||
|
||||
contact = telegram.Contact.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(contact.phone_number, self.phone_number)
|
||||
self.assertEqual(contact.first_name, self.first_name)
|
||||
self.assertEqual(contact.last_name, self.last_name)
|
||||
self.assertEqual(contact.user_id, self.user_id)
|
||||
|
||||
def test_contact_to_json(self):
|
||||
"""Test Contact.to_json() method"""
|
||||
print('Testing Contact.to_json()')
|
||||
|
||||
contact = telegram.Contact.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(contact.to_json()))
|
||||
|
||||
def test_contact_to_dict(self):
|
||||
"""Test Contact.to_dict() method"""
|
||||
print('Testing Contact.to_dict()')
|
||||
|
||||
contact = telegram.Contact.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(contact.to_dict()))
|
||||
self.assertEqual(contact['phone_number'], self.phone_number)
|
||||
self.assertEqual(contact['first_name'], self.first_name)
|
||||
self.assertEqual(contact['last_name'], self.last_name)
|
||||
self.assertEqual(contact['user_id'], self.user_id)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Document"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class DocumentTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Document."""
|
||||
|
||||
def setUp(self):
|
||||
self.document_file = open('tests/data/telegram.png', 'rb')
|
||||
self.document_file_id = 'BQADAQADpAADHyP1B04ipZxJTe2BAg'
|
||||
self.document_file_url = 'http://dummyimage.com/600x400/000/fff.gif&text=telegram'
|
||||
self.thumb = {'width': 90,
|
||||
'height': 90,
|
||||
'file_id': 'BQADAQADoQADHyP1B0mzJMVyzcB0Ag',
|
||||
'file_size': 2364}
|
||||
self.file_name = 'telegram.png'
|
||||
self.mime_type = 'image/png'
|
||||
self.file_size = 12948
|
||||
|
||||
self.json_dict = {
|
||||
'file_id': self.document_file_id,
|
||||
'thumb': self.thumb,
|
||||
'file_name': self.file_name,
|
||||
'mime_type': self.mime_type,
|
||||
'file_size': self.file_size
|
||||
}
|
||||
|
||||
def test_send_document_png_file(self):
|
||||
"""Test telegram.Bot sendDocument method"""
|
||||
print('Testing bot.sendDocument - PNG File')
|
||||
|
||||
message = self._bot.sendDocument(self._chat_id,
|
||||
self.document_file)
|
||||
|
||||
document = message.document
|
||||
|
||||
self.assertTrue(isinstance(document.file_id, str))
|
||||
self.assertNotEqual(document.file_id, '')
|
||||
self.assertTrue(isinstance(document.thumb, telegram.PhotoSize))
|
||||
self.assertEqual(document.file_name, self.file_name)
|
||||
self.assertEqual(document.mime_type, self.mime_type)
|
||||
self.assertEqual(document.file_size, self.file_size)
|
||||
|
||||
def test_send_document_png_file_with_custom_file_name(self):
|
||||
"""Test telegram.Bot sendDocument method"""
|
||||
print('Testing bot.sendDocument - PNG File with custom filename')
|
||||
|
||||
message = self._bot.sendDocument(self._chat_id,
|
||||
self.document_file,
|
||||
filename='telegram_custom.png')
|
||||
|
||||
document = message.document
|
||||
|
||||
self.assertTrue(isinstance(document.file_id, str))
|
||||
self.assertNotEqual(document.file_id, '')
|
||||
self.assertTrue(isinstance(document.thumb, telegram.PhotoSize))
|
||||
self.assertEqual(document.file_name, 'telegram_custom.png')
|
||||
self.assertEqual(document.mime_type, self.mime_type)
|
||||
self.assertEqual(document.file_size, self.file_size)
|
||||
|
||||
def test_send_document_url_gif_file(self):
|
||||
"""Test telegram.Bot sendDocument method"""
|
||||
print('Testing bot.sendDocument - GIF File by URL')
|
||||
|
||||
message = self._bot.sendDocument(self._chat_id,
|
||||
self.document_file_url)
|
||||
|
||||
document = message.document
|
||||
|
||||
self.assertTrue(isinstance(document.file_id, str))
|
||||
self.assertNotEqual(document.file_id, '')
|
||||
self.assertTrue(isinstance(document.thumb, telegram.PhotoSize))
|
||||
self.assertEqual(document.file_name, 'image.gif')
|
||||
self.assertEqual(document.mime_type, 'image/gif')
|
||||
self.assertEqual(document.file_size, 3878)
|
||||
|
||||
def test_send_document_resend(self):
|
||||
"""Test telegram.Bot sendDocument method"""
|
||||
print('Testing bot.sendDocument - Resend by file_id')
|
||||
|
||||
message = self._bot.sendDocument(chat_id=self._chat_id,
|
||||
document=self.document_file_id)
|
||||
|
||||
document = message.document
|
||||
|
||||
self.assertEqual(document.file_id, self.document_file_id)
|
||||
self.assertTrue(isinstance(document.thumb, telegram.PhotoSize))
|
||||
self.assertEqual(document.file_name, self.file_name)
|
||||
self.assertEqual(document.mime_type, self.mime_type)
|
||||
|
||||
def test_document_de_json(self):
|
||||
"""Test Document.de_json() method"""
|
||||
print('Testing Document.de_json()')
|
||||
|
||||
document = telegram.Document.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(document.file_id, self.document_file_id)
|
||||
self.assertTrue(isinstance(document.thumb, telegram.PhotoSize))
|
||||
self.assertEqual(document.file_name, self.file_name)
|
||||
self.assertEqual(document.mime_type, self.mime_type)
|
||||
self.assertEqual(document.file_size, self.file_size)
|
||||
|
||||
def test_document_to_json(self):
|
||||
"""Test Document.to_json() method"""
|
||||
print('Testing Document.to_json()')
|
||||
|
||||
document = telegram.Document.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(document.to_json()))
|
||||
|
||||
def test_document_to_dict(self):
|
||||
"""Test Document.to_dict() method"""
|
||||
print('Testing Document.to_dict()')
|
||||
|
||||
document = telegram.Document.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(document.to_dict()))
|
||||
self.assertEqual(document['file_id'], self.document_file_id)
|
||||
self.assertTrue(isinstance(document['thumb'], telegram.PhotoSize))
|
||||
self.assertEqual(document['file_name'], self.file_name)
|
||||
self.assertEqual(document['mime_type'], self.mime_type)
|
||||
self.assertEqual(document['file_size'], self.file_size)
|
||||
|
||||
def test_error_send_document_empty_file(self):
|
||||
print('Testing bot.sendDocument - Null file')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['document'] = open(os.devnull, 'rb')
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendDocument(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_send_document_empty_file_id(self):
|
||||
print('Testing bot.sendDocument - Empty file_id')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['document'] = ''
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendDocument(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_document_without_required_args(self):
|
||||
print('Testing bot.sendDocument - Without required arguments')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
|
||||
self.assertRaises(TypeError,
|
||||
lambda: self._bot.sendDocument(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Emoji"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from telegram.emoji import Emoji
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class EmojiTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Emoji."""
|
||||
|
||||
def test_emoji(self):
|
||||
"""Test Emoji class"""
|
||||
print('Testing Emoji class')
|
||||
|
||||
for attr in dir(Emoji):
|
||||
if attr[0] != '_': # TODO: dirty way to filter out functions
|
||||
self.assertTrue(type(getattr(Emoji, attr)) is str)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram File"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class FileTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram File."""
|
||||
|
||||
def setUp(self):
|
||||
self.audio_file_id = 'BQADAQADDwADHyP1B6PSPq2HjX8kAg'
|
||||
self.document_file_id = 'BQADAQADpAADHyP1B04ipZxJTe2BAg'
|
||||
self.sticker_file_id = 'BQADAQADHAADyIsGAAFZfq1bphjqlgI'
|
||||
self.video_file_id = 'BAADAQADXwADHyP1BwJFTcmY2RYCAg'
|
||||
self.voice_file_id = 'AwADAQADTgADHyP1B_mbw34svXPHAg'
|
||||
|
||||
|
||||
self.json_dict = {
|
||||
'file_id': self.audio_file_id,
|
||||
'file_path': 'https://api.telegram.org/file/bot133505823:AAHZFMHno3mzVLErU5b5jJvaeG--qUyLyG0/document/file_3',
|
||||
'file_size': 28232
|
||||
}
|
||||
|
||||
def test_get_and_download_file_audio(self):
|
||||
"""Test telegram.Bot getFile method - Audio"""
|
||||
print('Testing bot.getFile - With Audio.file_id')
|
||||
|
||||
newFile = self._bot.getFile(self.audio_file_id)
|
||||
|
||||
self.assertEqual(newFile.file_size, 28232)
|
||||
self.assertEqual(newFile.file_id, self.audio_file_id)
|
||||
self.assertTrue(newFile.file_path.startswith('https://'))
|
||||
|
||||
newFile.download('telegram.mp3')
|
||||
|
||||
self.assertTrue(os.path.isfile('telegram.mp3'))
|
||||
|
||||
def test_get_and_download_file_document(self):
|
||||
"""Test telegram.Bot getFile method - Document"""
|
||||
print('Testing bot.getFile - With Document.file_id')
|
||||
|
||||
newFile = self._bot.getFile(self.document_file_id)
|
||||
|
||||
self.assertEqual(newFile.file_size, 12948)
|
||||
self.assertEqual(newFile.file_id, self.document_file_id)
|
||||
self.assertTrue(newFile.file_path.startswith('https://'))
|
||||
|
||||
newFile.download('telegram.png')
|
||||
|
||||
self.assertTrue(os.path.isfile('telegram.png'))
|
||||
|
||||
def test_get_and_download_file_sticker(self):
|
||||
"""Test telegram.Bot getFile method - Sticker"""
|
||||
print('Testing bot.getFile - With Sticker.file_id')
|
||||
|
||||
newFile = self._bot.getFile(self.sticker_file_id)
|
||||
|
||||
self.assertEqual(newFile.file_size, 39518)
|
||||
self.assertEqual(newFile.file_id, self.sticker_file_id)
|
||||
self.assertTrue(newFile.file_path.startswith('https://'))
|
||||
|
||||
newFile.download('telegram.webp')
|
||||
|
||||
self.assertTrue(os.path.isfile('telegram.webp'))
|
||||
|
||||
def test_get_and_download_file_video(self):
|
||||
"""Test telegram.Bot getFile method - Video"""
|
||||
print('Testing bot.getFile - With Video.file_id')
|
||||
|
||||
newFile = self._bot.getFile(self.video_file_id)
|
||||
|
||||
self.assertEqual(newFile.file_size, 326534)
|
||||
self.assertEqual(newFile.file_id, self.video_file_id)
|
||||
self.assertTrue(newFile.file_path.startswith('https://'))
|
||||
|
||||
newFile.download('telegram.mp4')
|
||||
|
||||
self.assertTrue(os.path.isfile('telegram.mp4'))
|
||||
|
||||
def test_get_and_download_file_voice(self):
|
||||
"""Test telegram.Bot getFile method - Voice"""
|
||||
print('Testing bot.getFile - With Voice.file_id')
|
||||
|
||||
newFile = self._bot.getFile(self.voice_file_id)
|
||||
|
||||
self.assertEqual(newFile.file_size, 9199)
|
||||
self.assertEqual(newFile.file_id, self.voice_file_id)
|
||||
self.assertTrue(newFile.file_path.startswith('https://'))
|
||||
|
||||
newFile.download('telegram.ogg')
|
||||
|
||||
self.assertTrue(os.path.isfile('telegram.ogg'))
|
||||
|
||||
def test_file_de_json(self):
|
||||
"""Test File.de_json() method"""
|
||||
print('Testing File.de_json()')
|
||||
|
||||
newFile = telegram.File.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(newFile.file_id, self.json_dict['file_id'])
|
||||
self.assertEqual(newFile.file_path, self.json_dict['file_path'])
|
||||
self.assertEqual(newFile.file_size, self.json_dict['file_size'])
|
||||
|
||||
def test_file_to_json(self):
|
||||
"""Test File.to_json() method"""
|
||||
print('Testing File.to_json()')
|
||||
|
||||
newFile = telegram.File.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(newFile.to_json()))
|
||||
|
||||
def test_file_to_dict(self):
|
||||
"""Test File.to_dict() method"""
|
||||
print('Testing File.to_dict()')
|
||||
|
||||
newFile = telegram.File.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(newFile.to_dict()))
|
||||
self.assertEqual(newFile['file_id'], self.json_dict['file_id'])
|
||||
self.assertEqual(newFile['file_path'], self.json_dict['file_path'])
|
||||
self.assertEqual(newFile['file_size'], self.json_dict['file_size'])
|
||||
|
||||
def test_error_get_empty_file_id(self):
|
||||
print('Testing bot.getFile - Null file_id')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
json_dict['file_id'] = ''
|
||||
del(json_dict['file_path'])
|
||||
del(json_dict['file_size'])
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.getFile(**json_dict))
|
||||
|
||||
def test_error_file_without_required_args(self):
|
||||
print('Testing bot.getFile - Without required arguments')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
del(json_dict['file_path'])
|
||||
del(json_dict['file_size'])
|
||||
|
||||
self.assertRaises(TypeError,
|
||||
lambda: self._bot.getFile(**json_dict))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram GroupChat"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class GroupChatTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram GroupChat."""
|
||||
|
||||
def setUp(self):
|
||||
self.id = -28767330
|
||||
self.title = 'ToledosPalaceBot - Group'
|
||||
self.type = 'group'
|
||||
|
||||
self.json_dict = {
|
||||
'id': self.id,
|
||||
'title': self.title,
|
||||
'type': self.type
|
||||
}
|
||||
|
||||
def test_group_chat_de_json_empty_json(self):
|
||||
"""Test GroupChat.de_json() method"""
|
||||
print('Testing GroupChat.de_json() - Empty JSON')
|
||||
|
||||
group_chat = telegram.GroupChat.de_json({})
|
||||
|
||||
self.assertEqual(group_chat, None)
|
||||
|
||||
def test_group_chat_de_json(self):
|
||||
"""Test GroupChat.de_json() method"""
|
||||
print('Testing GroupChat.de_json()')
|
||||
|
||||
group_chat = telegram.GroupChat.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()')
|
||||
|
||||
group_chat = telegram.GroupChat.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()')
|
||||
|
||||
group_chat = telegram.GroupChat.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(group_chat.to_dict()))
|
||||
self.assertEqual(group_chat['id'], self.id)
|
||||
self.assertEqual(group_chat['title'], self.title)
|
||||
self.assertEqual(group_chat['type'], self.type)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Location"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class LocationTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Location."""
|
||||
|
||||
def setUp(self):
|
||||
self.latitude = -23.691288
|
||||
self.longitude = -46.788279
|
||||
|
||||
self.json_dict = {
|
||||
'latitude': self.latitude,
|
||||
'longitude': self.longitude
|
||||
}
|
||||
|
||||
def test_send_location_implicit_args(self):
|
||||
"""Test telegram.Bot sendLocation method"""
|
||||
print('Testing bot.sendLocation - Implicit arguments')
|
||||
|
||||
message = self._bot.sendLocation(self._chat_id,
|
||||
self.latitude,
|
||||
self.longitude)
|
||||
|
||||
location = message.location
|
||||
|
||||
self.assertEqual(location.latitude, self.latitude)
|
||||
self.assertEqual(location.longitude, self.longitude)
|
||||
|
||||
def test_send_location_explicit_args(self):
|
||||
"""Test telegram.Bot sendLocation method"""
|
||||
print('Testing bot.sendLocation - Explicit arguments')
|
||||
|
||||
message = self._bot.sendLocation(chat_id=self._chat_id,
|
||||
latitude=self.latitude,
|
||||
longitude=self.longitude)
|
||||
|
||||
location = message.location
|
||||
|
||||
self.assertEqual(location.latitude, self.latitude)
|
||||
self.assertEqual(location.longitude, self.longitude)
|
||||
|
||||
def test_location_de_json(self):
|
||||
"""Test Location.de_json() method"""
|
||||
print('Testing Location.de_json()')
|
||||
|
||||
location = telegram.Location.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(location.latitude, self.latitude)
|
||||
self.assertEqual(location.longitude, self.longitude)
|
||||
|
||||
def test_location_to_json(self):
|
||||
"""Test Location.to_json() method"""
|
||||
print('Testing Location.to_json()')
|
||||
|
||||
location = telegram.Location.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(location.to_json()))
|
||||
|
||||
def test_location_to_dict(self):
|
||||
"""Test Location.to_dict() method"""
|
||||
print('Testing Location.to_dict()')
|
||||
|
||||
location = telegram.Location.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(location['latitude'], self.latitude)
|
||||
self.assertEqual(location['longitude'], self.longitude)
|
||||
|
||||
def test_error_send_location_empty_args(self):
|
||||
print('Testing bot.sendLocation - Empty arguments')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
json_dict['latitude'] = ''
|
||||
json_dict['longitude'] = ''
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendLocation(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_location_without_required_args(self):
|
||||
print('Testing bot.sendLocation - Without required arguments')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['latitude'])
|
||||
del(json_dict['longitude'])
|
||||
|
||||
self.assertRaises(TypeError,
|
||||
lambda: self._bot.sendLocation(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Sticker"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class StickerTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Sticker."""
|
||||
|
||||
def setUp(self):
|
||||
self.sticker_file_id = 'BQADAQADHAADyIsGAAFZfq1bphjqlgI'
|
||||
self.width = 510
|
||||
self.height = 512
|
||||
self.thumb = {'width': 90,
|
||||
'height': 90,
|
||||
'file_id': 'BQADAQADoQADHyP1B0mzJMVyzcB0Ag',
|
||||
'file_size': 2364}
|
||||
self.file_size = 39518
|
||||
|
||||
self.json_dict = {
|
||||
'file_id': self.sticker_file_id,
|
||||
'width': self.width,
|
||||
'height': self.height,
|
||||
'thumb': self.thumb,
|
||||
'file_size': self.file_size
|
||||
}
|
||||
|
||||
def test_send_sticker_file(self):
|
||||
pass
|
||||
|
||||
def test_send_sticker_resend(self):
|
||||
"""Test telegram.Bot sendSticker method"""
|
||||
print('Testing bot.sendSticker - Resend by file_id')
|
||||
|
||||
message = self._bot.sendSticker(chat_id=self._chat_id,
|
||||
sticker=self.sticker_file_id)
|
||||
|
||||
sticker = message.sticker
|
||||
|
||||
self.assertEqual(sticker.file_id, self.sticker_file_id)
|
||||
self.assertEqual(sticker.width, self.width)
|
||||
self.assertEqual(sticker.height, self.height)
|
||||
self.assertTrue(isinstance(sticker.thumb, telegram.PhotoSize))
|
||||
self.assertEqual(sticker.file_size, self.file_size)
|
||||
|
||||
def test_sticker_de_json(self):
|
||||
"""Test Sticker.de_json() method"""
|
||||
print('Testing Sticker.de_json()')
|
||||
|
||||
sticker = telegram.Sticker.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(sticker.file_id, self.sticker_file_id)
|
||||
self.assertEqual(sticker.width, self.width)
|
||||
self.assertEqual(sticker.height, self.height)
|
||||
self.assertTrue(isinstance(sticker.thumb, telegram.PhotoSize))
|
||||
self.assertEqual(sticker.file_size, self.file_size)
|
||||
|
||||
def test_sticker_to_json(self):
|
||||
"""Test Sticker.to_json() method"""
|
||||
print('Testing Sticker.to_json()')
|
||||
|
||||
sticker = telegram.Sticker.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(sticker.to_json()))
|
||||
|
||||
def test_sticker_to_dict(self):
|
||||
"""Test Sticker.to_dict() method"""
|
||||
print('Testing Sticker.to_dict()')
|
||||
|
||||
sticker = telegram.Sticker.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(sticker['file_id'], self.sticker_file_id)
|
||||
self.assertEqual(sticker['width'], self.width)
|
||||
self.assertEqual(sticker['height'], self.height)
|
||||
self.assertTrue(isinstance(sticker['thumb'], telegram.PhotoSize))
|
||||
self.assertEqual(sticker['file_size'], self.file_size)
|
||||
|
||||
def test_error_send_sticker_empty_file(self):
|
||||
print('Testing bot.sendSticker - Null file')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['sticker'] = open(os.devnull, 'rb')
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendSticker(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_send_sticker_empty_file_id(self):
|
||||
print('Testing bot.sendSticker - Empty file_id')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['sticker'] = ''
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendSticker(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_sticker_without_required_args(self):
|
||||
print('Testing bot.sendSticker - Without required arguments')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
|
||||
self.assertRaises(TypeError,
|
||||
lambda: self._bot.sendSticker(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Update"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class UpdateTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Update."""
|
||||
|
||||
def setUp(self):
|
||||
self.update_id = 868573637
|
||||
self.message = {'message_id': 319,
|
||||
'from': {'id': 12173560,
|
||||
'first_name': "Leandro",
|
||||
'last_name': "S.",
|
||||
'username': "leandrotoledo"},
|
||||
'chat': {'id': 12173560,
|
||||
'first_name': "Leandro",
|
||||
'last_name': "S.",
|
||||
'username': "leandrotoledo"},
|
||||
'date': 1441644592,
|
||||
'text': "Update Test"}
|
||||
|
||||
self.json_dict = {
|
||||
'update_id': self.update_id,
|
||||
'message': self.message
|
||||
}
|
||||
|
||||
def test_update_de_json(self):
|
||||
"""Test Update.de_json() method"""
|
||||
print('Testing Update.de_json()')
|
||||
|
||||
update = telegram.Update.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(update.update_id, self.update_id)
|
||||
self.assertTrue(isinstance(update.message, telegram.Message))
|
||||
|
||||
def test_update_to_json(self):
|
||||
"""Test Update.to_json() method"""
|
||||
print('Testing Update.to_json()')
|
||||
|
||||
update = telegram.Update.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(update.to_json()))
|
||||
|
||||
def test_update_to_dict(self):
|
||||
"""Test Update.to_dict() method"""
|
||||
print('Testing Update.to_dict()')
|
||||
|
||||
update = telegram.Update.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(update.to_dict()))
|
||||
self.assertEqual(update['update_id'], self.update_id)
|
||||
self.assertTrue(isinstance(update['message'], telegram.Message))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,496 @@
|
||||
#!/usr/bin/env python
|
||||
# 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>
|
||||
#
|
||||
# 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 Updater, Dispatcher,
|
||||
WebhookServer and WebhookHandler
|
||||
"""
|
||||
import logging
|
||||
import unittest
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
import signal
|
||||
from random import randrange
|
||||
from time import sleep
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
from urllib2 import urlopen, Request
|
||||
except ImportError:
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
sys.path.append('.')
|
||||
|
||||
from telegram import Update, Message, TelegramError, User, GroupChat, Updater
|
||||
from telegram.dispatcher import run_async
|
||||
from tests.base import BaseTest
|
||||
from threading import Lock, Thread
|
||||
|
||||
# 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 UpdaterTest(BaseTest, unittest.TestCase):
|
||||
"""
|
||||
This object represents Tests for Updater, Dispatcher, WebhookServer and
|
||||
WebhookHandler
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.updater = Updater('', workers=2)
|
||||
|
||||
self.received_message = None
|
||||
self.message_count = 0
|
||||
self.lock = Lock()
|
||||
|
||||
def tearDown(self):
|
||||
self.updater.stop()
|
||||
|
||||
def reset(self):
|
||||
self.message_count = 0
|
||||
self.received_message = None
|
||||
|
||||
def telegramHandlerTest(self, bot, update):
|
||||
self.received_message = update.message.text
|
||||
self.message_count += 1
|
||||
|
||||
@run_async
|
||||
def asyncHandlerTest(self, bot, update):
|
||||
sleep(1)
|
||||
with self.lock:
|
||||
self.received_message = update.message.text
|
||||
self.message_count += 1
|
||||
|
||||
def stringHandlerTest(self, bot, update):
|
||||
self.received_message = update
|
||||
self.message_count += 1
|
||||
|
||||
def additionalArgsTest(self, bot, update, update_queue, args):
|
||||
self.received_message = update
|
||||
self.message_count += 1
|
||||
if args[0] == 'resend':
|
||||
update_queue.put('/test5 noresend')
|
||||
elif args[0] == 'noresend':
|
||||
pass
|
||||
|
||||
def errorRaisingHandlerTest(self, bot, update):
|
||||
raise TelegramError(update)
|
||||
|
||||
def errorHandlerTest(self, bot, update, error):
|
||||
self.received_message = error.message
|
||||
self.message_count += 1
|
||||
|
||||
def test_addRemoveTelegramMessageHandler(self):
|
||||
print('Testing add/removeTelegramMessageHandler')
|
||||
bot = MockBot('Test')
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.telegramHandlerTest)
|
||||
self.updater.start_polling(0.01)
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, 'Test')
|
||||
|
||||
# Remove handler
|
||||
d.removeTelegramMessageHandler(self.telegramHandlerTest)
|
||||
self.reset()
|
||||
|
||||
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.updater.dispatcher.addTelegramMessageHandler(
|
||||
self.telegramHandlerTest)
|
||||
self.updater.start_polling(0.0)
|
||||
sleep(2)
|
||||
self.assertEqual(self.received_message, 'Multiple')
|
||||
self.assertEqual(self.message_count, 100)
|
||||
|
||||
def test_addRemoveTelegramRegexHandler(self):
|
||||
print('Testing add/removeStringRegexHandler')
|
||||
bot = MockBot('Test2')
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
regobj = re.compile('Te.*')
|
||||
self.updater.dispatcher.addTelegramRegexHandler(regobj,
|
||||
self.telegramHandlerTest)
|
||||
self.updater.start_polling(0.01)
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, 'Test2')
|
||||
|
||||
# Remove handler
|
||||
d.removeTelegramRegexHandler(regobj, self.telegramHandlerTest)
|
||||
self.reset()
|
||||
|
||||
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
|
||||
d = self.updater.dispatcher
|
||||
self.updater.dispatcher.addTelegramCommandHandler(
|
||||
'test', self.telegramHandlerTest)
|
||||
self.updater.start_polling(0.01)
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, '/test')
|
||||
|
||||
# Remove handler
|
||||
d.removeTelegramCommandHandler('test', self.telegramHandlerTest)
|
||||
self.reset()
|
||||
|
||||
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
|
||||
d = self.updater.dispatcher
|
||||
self.updater.dispatcher.addUnknownTelegramCommandHandler(
|
||||
self.telegramHandlerTest)
|
||||
self.updater.start_polling(0.01)
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, '/test2')
|
||||
|
||||
# Remove handler
|
||||
d.removeUnknownTelegramCommandHandler(self.telegramHandlerTest)
|
||||
self.reset()
|
||||
|
||||
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
|
||||
d = self.updater.dispatcher
|
||||
d.addStringRegexHandler('Te.*', self.stringHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
queue.put('Test3')
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, 'Test3')
|
||||
|
||||
# Remove handler
|
||||
d.removeStringRegexHandler('Te.*', self.stringHandlerTest)
|
||||
self.reset()
|
||||
|
||||
queue.put('Test3')
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_addRemoveStringCommandHandler(self):
|
||||
print('Testing add/removeStringCommandHandler')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addStringCommandHandler(
|
||||
'test3', self.stringHandlerTest)
|
||||
|
||||
queue = self.updater.start_polling(0.01)
|
||||
queue.put('/test3')
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, '/test3')
|
||||
|
||||
# Remove handler
|
||||
d.removeStringCommandHandler('test3', self.stringHandlerTest)
|
||||
self.reset()
|
||||
|
||||
queue.put('/test3')
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_addRemoveUnknownStringCommandHandler(self):
|
||||
print('Testing add/removeUnknownStringCommandHandler')
|
||||
bot = MockBot('/test')
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addUnknownStringCommandHandler(
|
||||
self.stringHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
queue.put('/test4')
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, '/test4')
|
||||
|
||||
# Remove handler
|
||||
d.removeUnknownStringCommandHandler(self.stringHandlerTest)
|
||||
self.reset()
|
||||
|
||||
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
|
||||
d = self.updater.dispatcher
|
||||
d.addErrorHandler(self.errorHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
error = TelegramError("Unauthorized.")
|
||||
queue.put(error)
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, "Unauthorized.")
|
||||
|
||||
# Remove handler
|
||||
d.removeErrorHandler(self.errorHandlerTest)
|
||||
self.reset()
|
||||
|
||||
queue.put(error)
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_errorInHandler(self):
|
||||
print('Testing error in Handler')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addStringRegexHandler('.*',
|
||||
self.errorRaisingHandlerTest)
|
||||
self.updater.dispatcher.addErrorHandler(self.errorHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
|
||||
queue.put('Test Error 1')
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, 'Test Error 1')
|
||||
|
||||
def test_errorOnGetUpdates(self):
|
||||
print('Testing error on getUpdates')
|
||||
bot = MockBot('', raise_error=True)
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addErrorHandler(self.errorHandlerTest)
|
||||
self.updater.start_polling(0.01)
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, "Test Error 2")
|
||||
|
||||
def test_addRemoveTypeHandler(self):
|
||||
print('Testing add/removeTypeHandler')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addTypeHandler(dict, self.stringHandlerTest)
|
||||
queue = self.updater.start_polling(0.01)
|
||||
payload = {"Test": 42}
|
||||
queue.put(payload)
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, payload)
|
||||
|
||||
# Remove handler
|
||||
d.removeTypeHandler(dict, self.stringHandlerTest)
|
||||
self.reset()
|
||||
|
||||
queue.put(payload)
|
||||
sleep(.1)
|
||||
self.assertTrue(None is self.received_message)
|
||||
|
||||
def test_runAsync(self):
|
||||
print('Testing @run_async')
|
||||
bot = MockBot('Test5', messages=2)
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.asyncHandlerTest)
|
||||
self.updater.start_polling(0.01)
|
||||
sleep(1.2)
|
||||
self.assertEqual(self.received_message, 'Test5')
|
||||
self.assertEqual(self.message_count, 2)
|
||||
|
||||
def test_additionalArgs(self):
|
||||
print('Testing additional arguments for handlers')
|
||||
self.updater.bot = MockBot('', messages=0)
|
||||
self.updater.dispatcher.addStringCommandHandler(
|
||||
'test5', self.additionalArgsTest)
|
||||
|
||||
queue = self.updater.start_polling(0.01)
|
||||
queue.put('/test5 resend')
|
||||
sleep(.1)
|
||||
self.assertEqual(self.received_message, '/test5 noresend')
|
||||
self.assertEqual(self.message_count, 2)
|
||||
|
||||
def test_webhook(self):
|
||||
print('Testing Webhook')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.telegramHandlerTest)
|
||||
|
||||
# Select random port for travis
|
||||
port = randrange(1024, 49152)
|
||||
self.updater.start_webhook('127.0.0.1', port,
|
||||
url_path='TOKEN',
|
||||
cert='./tests/test_updater.py',
|
||||
key='./tests/test_updater.py')
|
||||
sleep(0.5)
|
||||
# SSL-Wrapping will fail, so we start the server without SSL
|
||||
Thread(target=self.updater.httpd.serve_forever).start()
|
||||
|
||||
# Now, we send an update to the server via urlopen
|
||||
message = Message(1, User(1, "Tester"), datetime.now(),
|
||||
GroupChat(1, "Test Group"))
|
||||
|
||||
message.text = "Webhook Test"
|
||||
update = Update(1)
|
||||
update.message = message
|
||||
|
||||
try:
|
||||
payload = bytes(update.to_json(), encoding='utf-8')
|
||||
except TypeError:
|
||||
payload = bytes(update.to_json())
|
||||
|
||||
header = {
|
||||
'content-type': 'application/json',
|
||||
'content-length': str(len(payload))
|
||||
}
|
||||
|
||||
r = Request('http://127.0.0.1:%d/TOKEN' % port,
|
||||
data=payload,
|
||||
headers=header)
|
||||
|
||||
urlopen(r)
|
||||
|
||||
sleep(1)
|
||||
self.assertEqual(self.received_message, 'Webhook Test')
|
||||
|
||||
print("Test other webhook server functionalities...")
|
||||
request = Request('http://localhost:%d/webookhandler.py' % port)
|
||||
response = urlopen(request)
|
||||
self.assertEqual(b'', response.read())
|
||||
self.assertEqual(200, response.code)
|
||||
|
||||
request.get_method = lambda: 'HEAD'
|
||||
|
||||
response = urlopen(request)
|
||||
self.assertEqual(b'', response.read())
|
||||
self.assertEqual(200, response.code)
|
||||
|
||||
# Test multiple shutdown() calls
|
||||
self.updater.httpd.shutdown()
|
||||
self.updater.httpd.shutdown()
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_webhook_no_ssl(self):
|
||||
print('Testing Webhook without SSL')
|
||||
bot = MockBot('', messages=0)
|
||||
self.updater.bot = bot
|
||||
d = self.updater.dispatcher
|
||||
d.addTelegramMessageHandler(
|
||||
self.telegramHandlerTest)
|
||||
|
||||
# Select random port for travis
|
||||
port = randrange(1024, 49152)
|
||||
self.updater.start_webhook('127.0.0.1', port)
|
||||
sleep(0.5)
|
||||
|
||||
# Now, we send an update to the server via urlopen
|
||||
message = Message(1, User(1, "Tester 2"), datetime.now(),
|
||||
GroupChat(1, "Test Group 2"))
|
||||
|
||||
message.text = "Webhook Test 2"
|
||||
update = Update(1)
|
||||
update.message = message
|
||||
|
||||
try:
|
||||
payload = bytes(update.to_json(), encoding='utf-8')
|
||||
except TypeError:
|
||||
payload = bytes(update.to_json())
|
||||
|
||||
header = {
|
||||
'content-type': 'application/json',
|
||||
'content-length': str(len(payload))
|
||||
}
|
||||
|
||||
r = Request('http://127.0.0.1:%d/' % port,
|
||||
data=payload,
|
||||
headers=header)
|
||||
|
||||
urlopen(r)
|
||||
sleep(1)
|
||||
self.assertEqual(self.received_message, 'Webhook Test 2')
|
||||
|
||||
def signalsender(self):
|
||||
sleep(0.5)
|
||||
os.kill(os.getpid(), signal.SIGTERM)
|
||||
|
||||
def test_idle(self):
|
||||
print('Testing idle')
|
||||
self.updater.bot = MockBot('Test6', messages=0)
|
||||
self.updater.start_polling(poll_interval=0.01)
|
||||
Thread(target=self.signalsender).start()
|
||||
self.updater.idle()
|
||||
# If we get this far, idle() ran through
|
||||
sleep(1)
|
||||
self.updater.running = False
|
||||
|
||||
|
||||
class MockBot:
|
||||
|
||||
def __init__(self, text, messages=1, raise_error=False):
|
||||
self.text = text
|
||||
self.send_messages = messages
|
||||
self.raise_error = raise_error
|
||||
self.token = "TOKEN"
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def mockUpdate(text):
|
||||
message = Message(0, None, None, None)
|
||||
message.text = text
|
||||
update = Update(0)
|
||||
update.message = message
|
||||
return update
|
||||
|
||||
def setWebhook(self, webhook_url=None, certificate=None):
|
||||
pass
|
||||
|
||||
def getUpdates(self,
|
||||
offset=None,
|
||||
limit=100,
|
||||
timeout=0,
|
||||
network_delay=2.):
|
||||
|
||||
if self.raise_error:
|
||||
raise TelegramError('Test Error 2')
|
||||
elif self.send_messages >= 2:
|
||||
self.send_messages -= 2
|
||||
return self.mockUpdate(self.text), self.mockUpdate(self.text)
|
||||
elif self.send_messages == 1:
|
||||
self.send_messages -= 1
|
||||
return self.mockUpdate(self.text),
|
||||
else:
|
||||
return []
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram User"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class UserTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram User."""
|
||||
|
||||
def setUp(self):
|
||||
self.id = 12173560
|
||||
self.first_name = "Leandro"
|
||||
self.last_name = "S."
|
||||
self.username = "leandrotoledo"
|
||||
self.type = "private"
|
||||
|
||||
self.json_dict = {
|
||||
'id': self.id,
|
||||
'first_name': self.first_name,
|
||||
'last_name': self.last_name,
|
||||
'username': self.username,
|
||||
'type': self.type
|
||||
}
|
||||
|
||||
def test_user_de_json(self):
|
||||
"""Test User.de_json() method"""
|
||||
print('Testing User.de_json()')
|
||||
|
||||
user = telegram.User.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(user.id, self.id)
|
||||
self.assertEqual(user.first_name, self.first_name)
|
||||
self.assertEqual(user.last_name, self.last_name)
|
||||
self.assertEqual(user.username, self.username)
|
||||
self.assertEqual(user.type, self.type)
|
||||
|
||||
self.assertEqual(user.name, '@leandrotoledo')
|
||||
|
||||
def test_user_de_json_without_username(self):
|
||||
"""Test User.de_json() method"""
|
||||
print('Testing User.de_json() - Without username')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['username'])
|
||||
|
||||
user = telegram.User.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(user.id, self.id)
|
||||
self.assertEqual(user.first_name, self.first_name)
|
||||
self.assertEqual(user.last_name, self.last_name)
|
||||
self.assertEqual(user.type, self.type)
|
||||
|
||||
self.assertEqual(user.name, '%s %s' % (self.first_name, self.last_name))
|
||||
|
||||
|
||||
def test_user_de_json_without_username_and_lastname(self):
|
||||
"""Test User.de_json() method"""
|
||||
print('Testing User.de_json() - Without username and last_name')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['username'])
|
||||
del(json_dict['last_name'])
|
||||
|
||||
user = telegram.User.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(user.id, self.id)
|
||||
self.assertEqual(user.first_name, self.first_name)
|
||||
|
||||
self.assertEqual(user.name, self.first_name)
|
||||
|
||||
def test_user_to_json(self):
|
||||
"""Test User.to_json() method"""
|
||||
print('Testing User.to_json()')
|
||||
|
||||
user = telegram.User.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(user.to_json()))
|
||||
|
||||
def test_user_to_dict(self):
|
||||
"""Test User.to_dict() method"""
|
||||
print('Testing User.to_dict()')
|
||||
|
||||
user = telegram.User.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(user.to_dict()))
|
||||
self.assertEqual(user['id'], self.id)
|
||||
self.assertEqual(user['first_name'], self.first_name)
|
||||
self.assertEqual(user['last_name'], self.last_name)
|
||||
self.assertEqual(user['username'], self.username)
|
||||
self.assertEqual(user['type'], self.type)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Video"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class VideoTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Video."""
|
||||
|
||||
def setUp(self):
|
||||
self.video_file = open('tests/data/telegram.mp4', 'rb')
|
||||
self.video_file_id = 'BAADAQADXwADHyP1BwJFTcmY2RYCAg'
|
||||
self.width = 360
|
||||
self.height = 640
|
||||
self.duration = 4
|
||||
self.thumb = telegram.PhotoSize.de_json({})
|
||||
self.mime_type = 'video/mp4'
|
||||
self.file_size = 326534
|
||||
|
||||
# caption is part of sendVideo method but not Video object
|
||||
self.caption = u'VideoTest - Caption'
|
||||
|
||||
self.json_dict = {
|
||||
'file_id': self.video_file_id,
|
||||
'width': self.width,
|
||||
'height': self.height,
|
||||
'duration': self.duration,
|
||||
'thumb': self.thumb,
|
||||
'mime_type': self.mime_type,
|
||||
'file_size': self.file_size
|
||||
}
|
||||
|
||||
def test_send_video_required_args_only(self):
|
||||
"""Test telegram.Bot sendVideo method"""
|
||||
print('Testing bot.sendVideo - With required arguments only')
|
||||
|
||||
message = self._bot.sendVideo(self._chat_id,
|
||||
self.video_file)
|
||||
|
||||
video = message.video
|
||||
|
||||
self.assertTrue(isinstance(video.file_id, str))
|
||||
self.assertNotEqual(video.file_id, '')
|
||||
self.assertEqual(video.width, 0)
|
||||
self.assertEqual(video.height, 0)
|
||||
self.assertEqual(video.duration, 0)
|
||||
self.assertEqual(video.thumb, None)
|
||||
self.assertEqual(video.mime_type, '')
|
||||
self.assertEqual(video.file_size, self.file_size)
|
||||
|
||||
def test_send_video_all_args(self):
|
||||
"""Test telegram.Bot sendAudio method"""
|
||||
print('Testing bot.sendVideo - With all arguments')
|
||||
|
||||
message = self._bot.sendVideo(self._chat_id,
|
||||
self.video_file,
|
||||
duration=self.duration,
|
||||
caption=self.caption)
|
||||
|
||||
video = message.video
|
||||
|
||||
self.assertTrue(isinstance(video.file_id, str))
|
||||
self.assertNotEqual(video.file_id, '')
|
||||
self.assertEqual(video.width, 0)
|
||||
self.assertEqual(video.height, 0)
|
||||
self.assertEqual(video.duration, self.duration)
|
||||
self.assertEqual(video.thumb, None)
|
||||
self.assertEqual(video.mime_type, '')
|
||||
self.assertEqual(video.file_size, self.file_size)
|
||||
|
||||
self.assertEqual(message.caption, self.caption)
|
||||
|
||||
def test_send_video_mp4_file(self):
|
||||
"""Test telegram.Bot sendVideo method"""
|
||||
print('Testing bot.sendVideo - MP4 File')
|
||||
|
||||
message = self._bot.sendVideo(chat_id=self._chat_id,
|
||||
video=self.video_file,
|
||||
duration=self.duration,
|
||||
caption=self.caption)
|
||||
|
||||
video = message.video
|
||||
|
||||
self.assertTrue(isinstance(video.file_id, str))
|
||||
self.assertNotEqual(video.file_id, '')
|
||||
self.assertEqual(video.width, 0)
|
||||
self.assertEqual(video.height, 0)
|
||||
self.assertEqual(video.duration, self.duration)
|
||||
self.assertEqual(video.thumb, None)
|
||||
self.assertEqual(video.mime_type, '')
|
||||
self.assertEqual(video.file_size, self.file_size)
|
||||
|
||||
self.assertEqual(message.caption, self.caption)
|
||||
|
||||
def test_send_video_mp4_file_with_custom_filename(self):
|
||||
"""Test telegram.Bot sendVideo method"""
|
||||
print('Testing bot.sendVideo - MP4 File with custom filename')
|
||||
|
||||
message = self._bot.sendVideo(chat_id=self._chat_id,
|
||||
video=self.video_file,
|
||||
duration=self.duration,
|
||||
caption=self.caption,
|
||||
filename='telegram_custom.mp4')
|
||||
|
||||
video = message.video
|
||||
|
||||
self.assertTrue(isinstance(video.file_id, str))
|
||||
self.assertNotEqual(video.file_id, '')
|
||||
self.assertEqual(video.width, 0)
|
||||
self.assertEqual(video.height, 0)
|
||||
self.assertEqual(video.duration, self.duration)
|
||||
self.assertEqual(video.thumb, None)
|
||||
self.assertEqual(video.mime_type, '')
|
||||
self.assertEqual(video.file_size, self.file_size)
|
||||
|
||||
self.assertEqual(message.caption, self.caption)
|
||||
|
||||
def test_send_video_resend(self):
|
||||
"""Test telegram.Bot sendVideo method"""
|
||||
print('Testing bot.sendVideo - Resend by file_id')
|
||||
|
||||
message = self._bot.sendVideo(chat_id=self._chat_id,
|
||||
video=self.video_file_id,
|
||||
duration=self.duration,
|
||||
caption=self.caption)
|
||||
|
||||
video = message.video
|
||||
|
||||
self.assertEqual(video.file_id, self.video_file_id)
|
||||
self.assertEqual(video.duration, 0)
|
||||
self.assertEqual(video.thumb, None)
|
||||
self.assertEqual(video.mime_type, '')
|
||||
|
||||
self.assertEqual(message.caption, self.caption)
|
||||
|
||||
def test_video_de_json(self):
|
||||
"""Test Video.de_json() method"""
|
||||
print('Testing Video.de_json()')
|
||||
|
||||
video = telegram.Video.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(video.file_id, self.video_file_id)
|
||||
self.assertEqual(video.width, self.width)
|
||||
self.assertEqual(video.height, self.height)
|
||||
self.assertEqual(video.duration, self.duration)
|
||||
self.assertEqual(video.thumb, None)
|
||||
self.assertEqual(video.mime_type, self.mime_type)
|
||||
self.assertEqual(video.file_size, self.file_size)
|
||||
|
||||
def test_video_to_json(self):
|
||||
"""Test Video.to_json() method"""
|
||||
print('Testing Video.to_json()')
|
||||
|
||||
video = telegram.Video.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(video.to_json()))
|
||||
|
||||
def test_video_to_dict(self):
|
||||
"""Test Video.to_dict() method"""
|
||||
print('Testing Video.to_dict()')
|
||||
|
||||
video = telegram.Video.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(video.to_dict()))
|
||||
self.assertEqual(video['file_id'], self.video_file_id)
|
||||
self.assertEqual(video['width'], self.width)
|
||||
self.assertEqual(video['height'], self.height)
|
||||
self.assertEqual(video['duration'], self.duration)
|
||||
self.assertEqual(video['mime_type'], self.mime_type)
|
||||
self.assertEqual(video['file_size'], self.file_size)
|
||||
|
||||
def test_error_send_video_empty_file(self):
|
||||
print('Testing bot.sendVideo - Null file')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['video'] = open(os.devnull, 'rb')
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendVideo(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_send_video_empty_file_id(self):
|
||||
print('Testing bot.sendVideo - Empty file_id')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['video'] = ''
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendVideo(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_video_without_required_args(self):
|
||||
print('Testing bot.sendVideo - Without required arguments')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
del(json_dict['duration'])
|
||||
|
||||
self.assertRaises(TypeError,
|
||||
lambda: self._bot.sendVideo(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU 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 Telegram Voice"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('.')
|
||||
|
||||
import telegram
|
||||
from tests.base import BaseTest
|
||||
|
||||
|
||||
class VoiceTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Voice."""
|
||||
|
||||
def setUp(self):
|
||||
self.voice_file = open('tests/data/telegram.ogg', 'rb')
|
||||
self.voice_file_id = 'AwADAQADTgADHyP1B_mbw34svXPHAg'
|
||||
self.duration = 0
|
||||
self.mime_type = 'audio/ogg'
|
||||
self.file_size = 9199
|
||||
|
||||
self.json_dict = {
|
||||
'file_id': self.voice_file_id,
|
||||
'duration': self.duration,
|
||||
'mime_type': self.mime_type,
|
||||
'file_size': self.file_size
|
||||
}
|
||||
|
||||
def test_send_voice_required_args_only(self):
|
||||
"""Test telegram.Bot sendVoice method"""
|
||||
print('Testing bot.sendVoice - With required arguments only')
|
||||
|
||||
message = self._bot.sendVoice(self._chat_id,
|
||||
self.voice_file)
|
||||
|
||||
voice = message.voice
|
||||
|
||||
self.assertTrue(isinstance(voice.file_id, str))
|
||||
self.assertNotEqual(voice.file_id, '')
|
||||
self.assertEqual(voice.duration, self.duration)
|
||||
self.assertEqual(voice.mime_type, self.mime_type)
|
||||
self.assertEqual(voice.file_size, self.file_size)
|
||||
|
||||
def test_send_voice_all_args(self):
|
||||
"""Test telegram.Bot sendAudio method"""
|
||||
print('Testing bot.sendVoice - With all arguments')
|
||||
|
||||
message = self._bot.sendVoice(self._chat_id,
|
||||
self.voice_file,
|
||||
self.duration,
|
||||
mime_type=self.mime_type,
|
||||
file_size=self.file_size)
|
||||
|
||||
voice = message.voice
|
||||
|
||||
self.assertTrue(isinstance(voice.file_id, str))
|
||||
self.assertNotEqual(voice.file_id, '')
|
||||
self.assertEqual(voice.duration, self.duration)
|
||||
self.assertEqual(voice.mime_type, self.mime_type)
|
||||
self.assertEqual(voice.file_size, self.file_size)
|
||||
|
||||
def test_send_voice_ogg_file(self):
|
||||
"""Test telegram.Bot sendVoice method"""
|
||||
print('Testing bot.sendVoice - Ogg File')
|
||||
|
||||
message = self._bot.sendVoice(chat_id=self._chat_id,
|
||||
voice=self.voice_file,
|
||||
duration=self.duration)
|
||||
|
||||
voice = message.voice
|
||||
|
||||
self.assertTrue(isinstance(voice.file_id, str))
|
||||
self.assertNotEqual(voice.file_id, '')
|
||||
self.assertEqual(voice.duration, self.duration)
|
||||
self.assertEqual(voice.mime_type, self.mime_type)
|
||||
self.assertEqual(voice.file_size, self.file_size)
|
||||
|
||||
def test_send_voice_ogg_file_with_custom_filename(self):
|
||||
"""Test telegram.Bot sendVoice method"""
|
||||
print('Testing bot.sendVoice - Ogg File with custom filename')
|
||||
|
||||
message = self._bot.sendVoice(chat_id=self._chat_id,
|
||||
voice=self.voice_file,
|
||||
duration=self.duration,
|
||||
filename='telegram_custom.ogg')
|
||||
|
||||
voice = message.voice
|
||||
|
||||
self.assertTrue(isinstance(voice.file_id, str))
|
||||
self.assertNotEqual(voice.file_id, '')
|
||||
self.assertEqual(voice.duration, self.duration)
|
||||
self.assertEqual(voice.mime_type, self.mime_type)
|
||||
self.assertEqual(voice.file_size, self.file_size)
|
||||
|
||||
def test_send_voice_resend(self):
|
||||
"""Test telegram.Bot sendVoice method"""
|
||||
print('Testing bot.sendVoice - Resend by file_id')
|
||||
|
||||
message = self._bot.sendVoice(chat_id=self._chat_id,
|
||||
voice=self.voice_file_id,
|
||||
duration=self.duration)
|
||||
|
||||
voice = message.voice
|
||||
|
||||
self.assertEqual(voice.file_id, self.voice_file_id)
|
||||
self.assertEqual(voice.duration, self.duration)
|
||||
self.assertEqual(voice.mime_type, self.mime_type)
|
||||
|
||||
def test_voice_de_json(self):
|
||||
"""Test Voice.de_json() method"""
|
||||
print('Testing Voice.de_json()')
|
||||
|
||||
voice = telegram.Voice.de_json(self.json_dict)
|
||||
|
||||
self.assertEqual(voice.file_id, self.voice_file_id)
|
||||
self.assertEqual(voice.duration, self.duration)
|
||||
self.assertEqual(voice.mime_type, self.mime_type)
|
||||
self.assertEqual(voice.file_size, self.file_size)
|
||||
|
||||
def test_voice_to_json(self):
|
||||
"""Test Voice.to_json() method"""
|
||||
print('Testing Voice.to_json()')
|
||||
|
||||
voice = telegram.Voice.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_json(voice.to_json()))
|
||||
|
||||
def test_voice_to_dict(self):
|
||||
"""Test Voice.to_dict() method"""
|
||||
print('Testing Voice.to_dict()')
|
||||
|
||||
voice = telegram.Voice.de_json(self.json_dict)
|
||||
|
||||
self.assertTrue(self.is_dict(voice.to_dict()))
|
||||
self.assertEqual(voice['file_id'], self.voice_file_id)
|
||||
self.assertEqual(voice['duration'], self.duration)
|
||||
self.assertEqual(voice['mime_type'], self.mime_type)
|
||||
self.assertEqual(voice['file_size'], self.file_size)
|
||||
|
||||
def test_error_send_voice_empty_file(self):
|
||||
print('Testing bot.sendVoice - Null file')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['voice'] = open(os.devnull, 'rb')
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendVoice(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_send_voice_empty_file_id(self):
|
||||
print('Testing bot.sendVoice - Empty file_id')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
json_dict['voice'] = ''
|
||||
|
||||
self.assertRaises(telegram.TelegramError,
|
||||
lambda: self._bot.sendVoice(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
def test_error_voice_without_required_args(self):
|
||||
print('Testing bot.sendVoice - Without required arguments')
|
||||
|
||||
json_dict = self.json_dict
|
||||
|
||||
del(json_dict['file_id'])
|
||||
del(json_dict['duration'])
|
||||
|
||||
self.assertRaises(TypeError,
|
||||
lambda: self._bot.sendVoice(chat_id=self._chat_id,
|
||||
**json_dict))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user