Compare commits

...

213 Commits

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

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

* Add test for "reply" filter

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

refs #468

* setGameScore() changes

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

refs #468

* New field forward_from_message_id for Message.

refs #468

* New parameter cache_time for answerCallbackQuery

refs #468

* replykeyboardhide renamed to replykeyboardremove

refs #468

* Unitests for updated setGameScore semantics

refs #468

* Backward compatibility for ReplyKeyboardHide

refs #468

* Fix docstrings of wrapper methods in Message

* Unitest new field forward_from_message_id of Message

refs #468

* Fix testMaxCaptionLength

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

* MessageHandler: Added support for channel posts

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

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

* Change exception to InvalidToken in test and request util

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

* Adding tests

* Changed the file permission back to 644.

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

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

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

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

* Removed some old docstrings refering to the TimeUnits enum.

* Removed the old TimeUnits import.

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

* Writing the error message directly in the exception.

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

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

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

* Adding error handling for the method .

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

* Excluding .exrc file.

* Removing \ at EOF of ValueError.

* Replacing Enums with plain new-style classes.

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

* Fixing typo, number -> Number.

* Changed lower_case Days attributes to UPPER_CASE.

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

* Removed redundant function get_days.

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

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

* Changed docstring for interval.

* Removed debug print.

* Changing some docstrings.

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

* fix docstrings and sphinx sources to get rid of warnings

* add telegram.contrib.rst
2016-11-01 06:53:51 +01:00
Jannes Höke b22c3cc5c0 [ci skip] add state diagrams for conversation handler examples 2016-10-28 08:26:02 +02:00
Jannes Höke 2786252a51 Bump version to v5.2.0 2016-10-25 20:10:36 +02:00
Jannes Höke 3f30f74024 update examples to use bitwise filters 2016-10-25 19:51:56 +02:00
Jannes Höke 79fc3be9cd Update README.md 2016-10-25 19:37:19 +02:00
Jannes Höke 71c73bdc74 Update README.md 2016-10-25 19:36:57 +02:00
neutronnnate 761547e71d Issue 422: Fixed start_polling with clean=True can cause 'Too Many Requests' error from Telegram. (#437) 2016-10-25 19:30:05 +02:00
Jannes Höke 10bdf8212c Add pass_user_data and pass_chat_data to Handler (#436)
* initial commit for user_data

* add chat_data and use defaultdict

* fix chat_data copy-paste error

* add test for user_data and chat_data

* fix case where chat is None

* remove braces from import line
2016-10-25 19:28:34 +02:00
Kristofer Kirss 45936c9982 Remove deprecated argument from Updater docstring (#444)
Argument (job_queue_tick_interval) was removed with commit 3aedd78 but the docstring in updater.py wasn't.
2016-10-23 00:31:44 +03:00
Jannes Höke fae1896232 Switch to readthedocs (#443)
* replace pythonhosted by readthedocs

* fix rtd links in examples/README
2016-10-19 18:00:33 +02:00
Jacob Bom 2518ddac22 Update comtributing guide with explicit kwargs 2016-10-19 13:07:20 +02:00
Jacob Bom 61fe438a8b Merge pull request #431 from python-telegram-bot/october3
Add api changes as of october 3
2016-10-19 12:59:00 +02:00
Jacob Bom 960862ccb1 Merge branch 'master' into october3
# Conflicts:
#	telegram/bot.py
#	telegram/callbackquery.py
#	telegram/chat.py
#	telegram/ext/messagehandler.py
#	telegram/inlinekeyboardbutton.py
#	telegram/inlinequeryresultcachedaudio.py
#	telegram/message.py
#	tests/test_filters.py
2016-10-19 12:35:50 +02:00
Jacob Bom 4e5f4582dd Merge pull request #411 from python-telegram-bot/bitwise-filters
Make filters and/or-able using bitwise operators.
2016-10-19 11:40:35 +02:00
Jacob Bom 225bc24c2a Merge pull request #442 from python-telegram-bot/explicit-kwargs
Use explicit kwargs and change/add a bunch of documentation.
2016-10-19 11:36:19 +02:00
Noam Meltzer a5f9aa3171 more documentation 2016-10-17 23:44:40 +03:00
Noam Meltzer 78088f4f6a Fix grammer: 'a object' -> 'an object' 2016-10-17 01:22:40 +03:00
Noam Meltzer 59fa717023 Documentation improvements + small style fixes 2016-10-17 01:11:20 +03:00
Noam Meltzer 31cab0d1b4 editMessageCaption & editMessageReplyMarkup: more validation on input 2016-10-17 01:09:44 +03:00
Jacob Bom 7fafaa1ea3 Update support date in readme. 2016-10-16 16:54:08 +02:00
Jacob Bom e367b8519d Use explicit kwargs for all class inits in pure api.
While not stickily necessary for most classes (since user isn't directly creating them) it still unifies our approach.
However for some like ReplyKeyboardHide where users are making the classes themselves it should improve IDE autocomplete support.
2016-10-16 16:24:13 +02:00
Jacob Bom b610316667 Use explicit kwargs for all bot methods.
This improves support for many IDEs' autocompletion.
2016-10-16 15:54:48 +02:00
Jacob Bom 39832d2f6b __str__ behaves differntly on py2 apparently. 2016-10-16 13:19:42 +02:00
Jacob Bom 5408c23e33 assertRegexMatches still exists for now. Use it. 2016-10-16 12:48:45 +02:00
Jacob Bom 62dd3a33e6 Better kwargs defaults. 2016-10-16 12:41:12 +02:00
Jacob Bom 3754cdafb2 send_game has differnt kwargs. 2016-10-16 12:41:12 +02:00
Jacob Bom 305ff93018 set_game_score might return True 2016-10-16 12:41:12 +02:00
Jacob Bom 29e0cc64e9 Fix py2 compat 2016-10-15 23:29:46 +02:00
Jacob Bom a5671a8fb1 Merge pull request #423 from python-telegram-bot/edit-class-method
Add edit_* class methods
2016-10-15 23:03:43 +02:00
Jacob Bom f99b2f8f3b Inprove coverage 2016-10-15 22:59:41 +02:00
Jacob Bom c626044a30 Add "all" filter
Since and empty list cannot (in the future, currently only deprecated) be used.
2016-10-15 22:58:55 +02:00
Noam Meltzer a68cf8d464 Respect RetryAfter with polling Updater 2016-10-15 23:39:50 +03:00
Jacob Bom de96cc87ea Only build master branch and PRs on travis. Yapf only on py3.5. 2016-10-14 11:24:00 +02:00
Jacob Bom ca5e3146c6 Fix docstring according to Jannes' commentns. 2016-10-14 10:32:12 +02:00
Noam Meltzer 53a574bbbb Improve unitests coverage 2016-10-13 22:52:53 +03:00
Noam Meltzer 5b8efe0c14 upgrade yapf to ver 0.12.2 2016-10-12 23:56:57 +03:00
Noam Meltzer d07a1c3f67 yapf: use our own mirror of yapf & update to version 0.12.2 2016-10-12 23:51:46 +03:00
Noam Meltzer 32a78722ae yapf fixes 2016-10-12 23:33:52 +03:00
Jacob Bom 04feeeff55 Update test cases
Needs proper animation file_id and size.
Also assertEqual can't test if two objects have the same data, so we just check the file_id instead.
2016-10-12 20:30:34 +02:00
Jannes Höke a1495956aa temporary fix for documentation builds on readthedocs 2016-10-10 12:51:12 +02:00
Patrick Hofmann 8dc10fc7b2 fixes broken test cases with PhotoSize, Game and Animation classes (#435)
* fixes broken test with PhotoSize, Game and Animation

However:
testSendGame and test_set_game_score both produces *BadRequest: u'Wrong file identifier/HTTP URL specified'*.

* fixes test_set_game_score

* adds to_dict method to Game to prevent extra collection type checks in base.TelegramObject
2016-10-10 11:44:40 +02:00
Jacob Bom 7ad92dcc65 Add test for set_game_score 2016-10-09 12:39:05 +02:00
Jacob Bom d1ddfaddf0 Add tests for Game, Animation and sendGame.
Still need setGameScore (I'm thinking we can set it to the ever increasing
envvar 'TRAVIS_BUILD_NUMBER') and getGameHighScores.
The tests currently don't work... Since I don't really understand how
PhotoSize works... Please halp :P
2016-10-07 23:57:10 +02:00
Jacob Bom b7c7612b3f Add game filter 2016-10-07 22:37:29 +02:00
Jacob Bom ade89772f4 Fix tests
Data is an optional kwargs in CallbackQuery according to Telegram
2016-10-07 22:32:54 +02:00
Jacob Bom 67b98e3190 Merge pull request #433 from PH89/october3
small fix for game related parts
2016-10-07 22:25:52 +02:00
Patrick Hofmann e672625a41 add myself to AUTHORS.rst 2016-10-06 18:17:42 +02:00
Patrick Hofmann 8cab735342 small fix for game related parts
* bot.py fix copy paste error in url
* callbackquery.py make data field optional
* message.py introduce optional game field
2016-10-06 17:52:53 +02:00
Noam Meltzer bfb4c63d60 add unitest for getWebhookInfo 2016-10-06 00:11:28 +03:00
Noam Meltzer 01a5a1c5b3 small documentation fix 2016-10-05 23:22:55 +03:00
Noam Meltzer 1db1b76a7c fix test_video unitest 2016-10-05 23:19:17 +03:00
Jacob Bom 976f34082f Add possibly good-enough test for all_members_are_admin
Should be good enough... If we /really/ wanted to we could get two different chats from telegram and check them, but it really shouldn't be necessary.
2016-10-05 17:55:00 +02:00
Jacob Bom 6b7788570c Add tests for captions in audio and voice 2016-10-05 17:50:48 +02:00
Noam Meltzer 1f9d3163dd Game: use explicit keyword args + added docmentation 2016-10-04 02:17:12 +03:00
Noam Meltzer 837e9d2964 Animation: use explicit keyword args + added documentation 2016-10-04 02:16:33 +03:00
Noam Meltzer fab97df58a GameHighScore: added attributes documentation 2016-10-04 02:06:22 +03:00
Noam Meltzer d70fc48e94 getGameHighScores(): added documentation + fixed copy-paste errors 2016-10-04 01:57:19 +03:00
Noam Meltzer 36192912c2 setGameScore: fixes
- fix copy/paste errors
 - return Message object
2016-10-04 01:56:05 +03:00
Noam Meltzer 34748ec228 callbackgame: small documentation fix 2016-10-04 01:50:34 +03:00
Noam Meltzer d5567cd9cd sendGame(): mall fixes 2016-10-04 01:37:44 +03:00
Noam Meltzer 2463b4b9c8 New exception: RetryAfter
Also, small fix to the description text of ChatMigrated
2016-10-04 01:27:45 +03:00
Noam Meltzer 7cf5009517 small documentation fixes 2016-10-04 01:10:30 +03:00
Noam Meltzer 9b74625d4a answerCallbackQuery: fix copy/paste: show_alert -> url 2016-10-04 00:55:29 +03:00
Noam Meltzer 4180c069b3 InputFile: use self instead of explicit class name 2016-10-04 00:25:32 +03:00
Noam Meltzer 3a0f219783 inputfile: define the file types as constant and use iterator 2016-10-04 00:25:05 +03:00
Noam Meltzer 3c889655c1 Allow http url as a file_id
N.B. test_send_video_mp4_file_url() is still failing, probably because
of telegram servers bug. Will contact telegram bot support about that.
2016-10-04 00:20:17 +03:00
Jacob Bom c2b8c4bf95 Fix regexGroupHandlerCallbackQuery test 2016-10-03 21:29:30 +02:00
Jacob Bom 8234321a20 Fix tests for Inline Voice Queries 2016-10-03 21:28:35 +02:00
Jacob Bom 5e2d96b47d Make tests actually run at all 2016-10-03 21:07:41 +02:00
Jacob Bom 551f6c556c Add game parameters in various places
Also chat_instance in CallbackQuery which will break a lot of tests probably
2016-10-03 21:01:38 +02:00
Jacob Bom ae17eb3272 Add InlineQueryResultGame 2016-10-03 20:55:21 +02:00
Jacob Bom 358dd795c7 Add the rest of game_ methods to bot. 2016-10-03 20:43:02 +02:00
Jacob Bom 151a441af7 Add send_game 2016-10-03 20:40:17 +02:00
Noam Meltzer 1f67623615 Fix import order 2016-10-03 21:34:08 +03:00
Noam Meltzer 8737b5de63 fix syntax error by some weird char 2016-10-03 21:17:04 +03:00
Jacob Bom f3b8a3a5e9 Merge remote-tracking branch 'origin/october3' into october3 2016-10-03 20:10:14 +02:00
Jacob Bom 9e9309eb90 Add all new Game related classes
Missing docstrings for now though, wanna add everything first
2016-10-03 20:09:57 +02:00
Noam Meltzer e8a34d8eef cosmetic fixes and documentation for getWebhookInfo 2016-10-03 20:43:10 +03:00
Jacob Bom 34c62a633b Add url to answerCallbackQuery 2016-10-03 15:25:07 +02:00
Jacob Bom 868d9217bc Add WebhookInfo and getWebhookInfo
Still needs tests though
2016-10-03 15:16:43 +02:00
Jacob Bom f7ede4baea Add caption fields to voice and audio
Or at least the methods/classes for sending.
2016-10-03 15:05:49 +02:00
Jacob Bom c3e07b1056 Add switch_inline_query_current_chat 2016-10-03 14:52:58 +02:00
Jacob Bom 79bdfe4c5d Allow filters to be passed without list.
Also deprecates actually using a list.
2016-09-29 19:10:22 +02:00
Michael Elovskikh 46657afa95 Start additional threads only when necessary (#415)
* Start all additional threads only when necessary.

* Deprecate prevent_autostart in the c'tor of JobQueue.
2016-09-27 10:21:35 +03:00
Jacob Bom 79e065a730 Add __str__ and __repr__ to MergedFilter. 2016-09-25 16:31:06 +02:00
Jacob Bom 9928a1eefc Add test for edit_text 2016-09-25 16:11:19 +02:00
Jacob Bom 0e2c3666c0 Add edit_* family of methods to CallbackQuery.
Either edits the message attribute, or the message associated with the inline_message_id.
2016-09-25 16:03:06 +02:00
Jacob Bom a996e8873f Add edit_* family of methods to Message. 2016-09-25 15:50:58 +02:00
Jacob Bom 3244417f61 Add docs for filters. 2016-09-25 00:30:04 +02:00
Jacob Bom 61596400e1 __call__ should return the result
Also add tests with both & and |.
2016-09-24 18:56:54 +02:00
Jacob Bom be0f5bc519 Merge branch 'master' into bitwise-filters
# Conflicts:
#	telegram/ext/messagehandler.py
#	tests/test_filters.py
2016-09-24 18:30:58 +02:00
Jacob Bom 921fbae2f3 Merge branch 'master' into bitwise-filters 2016-09-24 18:21:06 +02:00
Jacob Bom 2161681131 Use filter method instead of __call__
__call__ is scary looking for users wanted to create their own filters.
Also allows us to put additional logic in __call__ if we want in the future.
2016-09-24 18:20:32 +02:00
Jannes Höke 9d0e0386d9 Link echobot2 example from master 2016-09-24 16:30:39 +02:00
Rahiel Kasim dc7a459511 README: formatting (adding a newline) 2016-09-24 15:46:02 +02:00
Jannes Höke be675f0118 update all examples to use instance methods (#421) 2016-09-24 15:32:22 +02:00
Jannes Höke c49058dbb4 Bump version to v5.1 2016-09-24 15:29:23 +02:00
Jannes Höke 8e80a8d273 comment out test_reply_contact 2016-09-24 14:25:31 +02:00
Jannes Höke cbe057083f fix test_send_photo_resend 2016-09-24 14:16:04 +02:00
Jacob Bom 5f6138b06b Merge pull request #409 from python-telegram-bot/entities-filter
Add entities filter
2016-09-24 14:02:01 +02:00
Jacob Bom 1b99caa2f9 Merge remote-tracking branch 'origin/master' into entities-filter 2016-09-24 13:46:55 +02:00
Jacob Bom e16c1da6b1 Change entities filter to be singular.
Also remove the faulty example completely since it should be no longer needed.
2016-09-24 13:38:56 +02:00
Jannes Höke e1242b3b4a message.py: add quote keyword argument to reply_x methods (#420) 2016-09-23 17:44:09 +02:00
Gareth Dwyer 93dde1ac1d Add install from source instructions to readme (#419) 2016-09-23 17:13:32 +02:00
Jannes Höke 05fb9d161a Link echobot2 example from tag v5.0 2016-09-23 17:13:06 +02:00
Eli Gao a91fe5f8f6 Properly split and handle arguments in CommandHandler (#414)
* Properly split and handle arguments in CommandHandler

* Update the docstring for pass_args in CommandHandler

* Properly split and handle arguments in StringCommandHandler
2016-09-20 06:38:49 +02:00
Jannes Höke 5116a77221 Class methods (#362)
* bot.py: add create_references method

* create bot reference in webhook handler, use create_references on new updates

* message.py: implement reply_text

* echobot2.py: use Message.reply_text

* fix create_references in webhook handler

* add some more instance methods

* Chat.kick_member and unban_member

* bot.py: Create bot references in outgoing messages

* add tests for everything testable

* test_updater.py: add create_references method to MockBot

* remove Bot.create_references and refactor TelegramObject.de_json to take the additional parameter bot

* List bot as named kwarg where used

* file.py: Use Bot.request property instead of Bot._request attr
2016-09-20 06:36:55 +02:00
Jannes Höke 1f597c6b4a Merge branch 'LiaungYip-master' 2016-09-20 05:07:00 +02:00
Jannes Höke 1efd330e59 ConversationHandler: Fix #373 2016-09-20 05:00:39 +02:00
Jannes Höke af3e8c6440 Merge branch 'master' of https://github.com/LiaungYip/python-telegram-bot into LiaungYip-master 2016-09-20 04:10:39 +02:00
Jacob Bom f34c09dd72 Fix image sizes in tests. 2016-09-14 19:58:30 +02:00
Jacob Bom 71e74da0a2 Make filters and/or-able using bitwise operators.
See associated PR for more info.
2016-09-14 19:29:15 +02:00
Jacob Bom 97bb04cd38 Faulty example was faulty. 2016-09-13 20:50:25 +02:00
Jacob Bom 7ab007d8d4 Add Filters.entities test. 2016-09-13 20:47:43 +02:00
Jacob Bom f7b497c1b4 Fix in keyword ordering
We're testing for a string in list, not the other way around :P
2016-09-13 20:45:42 +02:00
Jacob Bom 4e60008086 Add entities filter
Should ideally superseed #375.
2016-09-13 20:09:46 +02:00
Rahiel Kasim 5285f63e4a Merge pull request #388 from python-telegram-bot/emoji
deprecate telegram.Emoji
2016-09-13 19:25:58 +02:00
Jacob Bom 6647ae3c25 Add methods to parse entities in Message
Should close #400.

* Add parse_entity

* Add parse_entities

* Add MessageEntity types as constants to MessageEntity.

* Add MAX_MESSAGE_ENTITIES to constants.py
Note: the value has been found by experimentation as opposed to extracted from the api docs.

* Add tests for parse_entity and parse_entities
2016-09-07 08:49:09 +02:00
Noam Meltzer e4a132c0e4 Reusable dispatcher (#402)
* Create a Request class which maintains its own connection pool
* When creating a Bot instance a new Request instance will be created if one wasn't supplied.
* Updater is responsible for creating a Request instance if a Bot instance wasn't provided.
* Dispatcher: add method to run async functions without decorator
* Dispatcher can now run as a singleton (allowing run_async decorator to work) as it always did and as multiple instances (where run_async decorator will raise RuntimeError)
2016-09-06 16:38:07 +03:00
Rahiel Kasim ca81a75f29 Merge pull request #396 from python-telegram-bot/json
use ujson as JSON en/decoder if available
2016-08-26 11:42:28 +02:00
Rahiel Kasim da87d4ba78 fix yapf 2016-08-26 11:17:05 +02:00
Rahiel Kasim 4753d27bd5 bump yapf to 0.11.0 2016-08-26 10:55:41 +02:00
Rahiel Kasim eabfc0b06b set ujson as optional dependency, test CPython builds with ujson 2016-08-26 10:23:17 +02:00
Rahiel Kasim fcda567f8c use ujson as JSON en/decoder if available 2016-08-26 09:40:46 +02:00
Li-aung 'Lewis' Yip 1c36ff46ad Add myself to AUTHORS.rst 2016-08-24 09:37:23 +08:00
Jacob Bom ffff0938f4 Add forwarded filter (#392) 2016-08-23 16:55:50 +02:00
Li-aung 'Lewis' Yip ab2d6eb494 Fix "key not found" exception if the very first message handler in a ConversationHandler returns the state ConversationHandler.END. 2016-08-22 05:49:37 +08:00
Rahiel Kasim fe14000515 remove tests for telegram.Emoji 2016-08-21 11:58:00 +02:00
Rahiel Kasim 5d27059631 deprecate telegram.Emoji 2016-08-21 11:50:22 +02:00
Rahiel Kasim 00bba73673 drop Python 2.6 support (closes #245) (#386)
* drop Python 2.6 support (closes #245)

* fix NullHandler import

* README: explicitly mention Py3 and PyPy compatibility
2016-08-20 22:01:07 +02:00
eugenio412 e9c5ee7ad6 unset but (#383)
solved the bug that prevented the unset to work
2016-08-16 21:13:31 +02:00
MWeesenaar f2f62423ba Merge pull request #379 from bomjacob/master
Fix #376: Execfile not in python 3. Take #2
2016-08-11 14:58:24 +02:00
Mikki Weesenaar 26a0a173f4 Manual merge 2016-08-11 14:38:55 +02:00
Jacob Bom b736e1e855 Move the exec out of function, since that's a whole other scope... 2016-08-11 13:08:28 +02:00
Jacob Bom bd3fa3bb64 Fix #376: Execfile does not exist in python 3 (#377)
* Add execfile function since it's missing in python 3.

* Remove extra space.
2016-08-10 21:39:14 +02:00
Jacob Bom c252042ddf Remove extra space. 2016-08-10 21:00:01 +02:00
Jacob Bom 8475c322af Add execfile function since it's missing in python 3. 2016-08-10 20:59:11 +02:00
Ilya Strukov dd4c0f0f1d Add missing return statement in timerbot example (#368) 2016-08-07 17:59:58 +02:00
Jannes Höke 555e36ee80 tests 2016-08-06 14:47:45 +02:00
Jannes Höke 5134f71380 Merge branch 'more-regex-handlers' of https://github.com/bomjacob/python-telegram-bot into bomjacob-more-regex-handlers 2016-08-06 14:32:05 +02:00
Jacob Bom 32268597d9 Wrap long lines 2016-08-06 14:19:41 +02:00
Jacob Bom 4feb2553ff Add self to Authors.rst 2016-08-06 13:45:43 +02:00
Jacob Bom cd2f956e56 Also fix linebreak ^^ 2016-08-06 13:35:58 +02:00
Jacob Bom 18fdb5ed13 Fix weird indent. 2016-08-06 13:35:06 +02:00
Jacob Bom 8c698caa12 Add Regex handling to CallbackQueryHandler and InlineQueryHandler.
Mostly a copy-paste from RegexHandler.
Not fully tested! Also needs yapf - sorry.
2016-08-06 13:33:38 +02:00
Jannes Höke 587908457e move version string to telegram/version.py (#361) 2016-07-29 15:40:11 +00:00
Noam Meltzer 4375820863 fixup! updated issue template 2016-07-25 22:31:23 +03:00
Noam Meltzer 171c70b4c2 updated issue template
[ci skip]
2016-07-25 22:29:55 +03:00
overquota f1ee54fa73 ChatMigrated exception (#353)
* ChatMigrated exception
2016-07-25 21:50:33 +03:00
Jannes Höke 90913724ca Update README.rst 2016-07-24 02:42:55 +02:00
Jannes Höke 9d4691e50d Create README.md 2016-07-24 02:35:01 +02:00
Rahiel Kasim c4928229d6 README: link to website 2016-07-24 01:21:35 +02:00
Jannes Höke 2f2337cac1 update motto in readme 2016-07-24 01:16:57 +02:00
Jannes Höke f5c57cd6c6 new inlinekeyboard example (#355) 2016-07-20 00:15:03 +02:00
Rahiel Kasim c51c2224da README: update link to new conversationbot example 2016-07-15 12:36:37 +02:00
Jannes Höke 834bf192b9 Bump version to v5.0.0 2016-07-15 01:48:11 +02:00
Jannes Höke d5486433e5 use job context for timerbot example 2016-07-15 01:46:27 +02:00
Jannes Höke c9ec436d68 remove old state machine example 2016-07-15 01:45:43 +02:00
Jannes Höke ad3eec2af8 ConversationHandler (#331)
* initial commit for conversationhandler and example

* implement simple Promise for run_async/conversationhandler

* refactor Promise._done to done

* add handling for timed out Promises

* correctly handle promises with None results

* fix handling tuple states

* update comments on example

* Added a first test on the ConversationHandler.

* Fixed a small typo.

* Yapf'd.

* add sphinx doc for conversation handler

* fix title for callbackqueryhandler sphinx docs
2016-07-15 01:30:54 +02:00
leandrotoledo e3fe1d2632 Merge branch 'master' of https://github.com/python-telegram-bot/python-telegram-bot 2016-07-14 17:19:13 -03:00
leandrotoledo 52bd3daa39 Bumping version of pre-commit [ci skip] 2016-07-14 17:18:29 -03:00
Leandro Toledo b4e8209f2c Update CONTRIBUTING.rst
Adding a bullet on "assertEqual method's arguments should be in ('actual', 'expected') order"
2016-07-14 17:16:25 -03:00
Valentijn f5f95ef8c9 Documentation (#350)
* Small fixes to documentation and add myself to AUTHORS.

* Rework CONTRIBUTIONS.rst

Use code-blocks instead of literals, change headings for portability and use a relative link to AUTHORS instead of linking to a specific copy.
2016-07-14 16:56:05 -03:00
Rahiel Kasim 04a871aff5 introduce constants module (#342) 2016-07-14 21:48:31 +02:00
Jannes Höke 81a755a7d8 Merge branch 'urllib3_fix_proxy_auth' 2016-07-13 15:09:23 +02:00
Noam Meltzer 6016aca0ba Bump version to v4.3.4 2016-07-12 23:34:49 +03:00
Noam Meltzer 7c908db901 urllib3: can now connect through proxies which require auth
fixes #343
2016-07-12 23:31:38 +03:00
Noam Meltzer d192b385ea dispatcher: add comment to describe the reason for conpool size 2016-07-12 21:58:27 +03:00
Jannes Höke f0b2028e3f Merge pull request #344 from python-telegram-bot/silence-webhook-logging
Move webhook handler logs to logging at DEBUG level
2016-07-12 14:35:14 +02:00
Mikki Weesenaar f443003408 Small change in the documentation. 2016-07-12 13:45:37 +02:00
Jannes Höke afc36a235b move webhook handler logs to logging at DEBUG level 2016-07-11 23:44:40 +02:00
Noam Meltzer b76337de87 __main__.py: assist with creating issues on github
usage:
python -m telegram

and copy/paste the output
2016-07-09 14:40:53 +03:00
Noam Meltzer 6afee6e0bd Merge pull request #340 from python-telegram-bot/v4.3.x
urllib3: now supports proxy
2016-07-08 23:53:56 +03:00
Jannes Höke 27e57bbf58 Bump version to v4.3.3 2016-07-08 22:13:46 +02:00
Noam Meltzer 4990d664bb Merge pull request #339 from python-telegram-bot/urllib3_fix_proxy
urllib3: now supports proxy
2016-07-08 23:00:02 +03:00
Noam Meltzer b3e42c3e20 urllib3: now supports proxy
fixes #336
2016-07-08 22:33:37 +03:00
Jannes Höke c2cce40299 Merge branch 'use-timeout' 2016-07-04 21:56:26 +02:00
Jannes Höke 9fd298a393 Merge pull request #307 from python-telegram-bot/jobqueue-rework
Make job queue API similar to the dispatcher, add new functionality
2016-06-29 16:20:43 +02:00
Jannes Höke 31073101a3 yapf 2016-06-24 19:22:49 +02:00
Noam Meltzer 1e0ebe89f3 JobQueue: minimize the amount of places changing self.__tick state
- start the jobqueue (by default) during __init__() instead of during
   put()
 - protect self._next_peek and self.__tick with a Lock
 - rename self._start() to self._main_loop()
 - stop() is now blocking until the event loop thread exits
2016-06-24 19:35:54 +03:00
Noam Meltzer 35872d7a8b test_jobqueue: fix test_jobs_tuple()
this test was based on timing and assumed that the JobQueue did not have
time to start processing the queue before checking the assert.
what we really should do is make sure JobQueue does not process anything
2016-06-24 19:13:40 +03:00
Noam Meltzer f65b6911ea JobQueue: use class name for the logger name 2016-06-24 19:13:40 +03:00
Noam Meltzer 02af1ea803 jobqueue: cosmetic fixes 2016-06-24 19:13:40 +03:00
Jannes Höke c4a8ee5175 Merge branch 'master' into jobqueue-rework
Conflicts:
	tests/test_jobqueue.py
2016-06-20 05:32:15 +02:00
Jannes Höke 738e3213a7 Merge branch 'master' into jobqueue-rework 2016-06-20 00:49:01 +02:00
Jannes Höke b08d41d0ff formatting 2016-05-31 15:35:40 +02:00
Jannes Höke de2d732135 Merge branch 'master' into jobqueue-rework
Conflicts:
	README.rst
	telegram/ext/commandhandler.py
	telegram/ext/messagehandler.py
2016-05-31 15:34:36 +02:00
Jannes Höke d40f0a8309 update update_queue and job_queue docstrings on all handlers 2016-05-28 16:04:19 +02:00
Jannes Höke 783f9c375c move job_queue kwarg to end 2016-05-28 14:21:39 +02:00
Jannes Höke 406303d6bb refactor: running -> _running, next_peek -> _next_peek 2016-05-28 13:48:30 +02:00
Jannes Höke 2534e0df9b allow jobs to be ran outside of jobqueue 2016-05-28 13:41:23 +02:00
Jannes Höke e7f4a07b7a update timerbot example with pass_job_queue 2016-05-26 14:48:50 +02:00
Jannes Höke bb165b6acf add pass_job_queue parameter to all handler classes 2016-05-26 14:39:11 +02:00
Jannes Höke 20067ff178 add test for context parameter 2016-05-26 14:07:44 +02:00
Jannes Höke 41daccce07 minor comments and formatting 2016-05-26 14:02:52 +02:00
Jannes Höke 786216305c Add context parameter in Job class #281 2016-05-26 13:55:56 +02:00
Jannes Höke b3142d2974 yapf 2016-05-25 23:57:29 +02:00
Jannes Höke 8278779a23 Merge branch 'jobqueue-rework' of github.com:python-telegram-bot/python-telegram-bot into jobqueue-rework 2016-05-25 23:37:10 +02:00
Jannes Höke 3aedd78e29 make job queue API similar to the dispatcher, add new functionality 2016-05-25 23:36:41 +02:00
Jannes Höke 6b90ac9f1c make job queue API similar to the dispatcher, add new functionality 2016-05-25 22:51:13 +02:00
227 changed files with 6867 additions and 2797 deletions
+67 -52
View File
@@ -1,34 +1,41 @@
How To Contribute
=================
===================
Every open source project lives from the generous help by contributors that sacrifice their time and ``python-telegram-bot`` is no different. To make participation as pleasant as possible, this project adheres to the `Code of Conduct`_ by the Python Software Foundation.
Setting things up
-----------------
-------------------
1. Fork the ``python-telegram-bot`` repository to your GitHub account.
2. Clone your forked repository of ``python-telegram-bot`` to your computer:
``$ git clone https://github.com/<your username>/python-telegram-bot``
.. code-block:: bash
``$ cd python-telegram-bot``
$ git clone https://github.com/<your username>/python-telegram-bot
$ cd python-telegram-bot
3. Add a track to the original repository:
``$ git remote add upstream https://github.com/python-telegram-bot/python-telegram-bot``
.. code-block:: bash
$ git remote add upstream https://github.com/python-telegram-bot/python-telegram-bot
4. Install dependencies:
``$ pip install -r requirements.txt -r requirements-dev.txt``
.. code-block:: bash
$ sudo pip install -r requirements.txt -r requirements-dev.txt
5. Install pre-commit hooks:
``$ pre-commit install``
.. code-block:: bash
$ pre-commit install
Finding something to do
-----------------------
###################
If you already know what you'd like to work on, you can skip this section.
@@ -37,7 +44,7 @@ If you have an idea for something to do, first check if it's already been filed
Another great way to start contributing is by writing tests. Tests are really important because they help prevent developers from accidentally breaking existing code, allowing them to build cool things faster. If you're interested in helping out, let the development team know by posting to the `developers' mailing list`_, and we'll help you get started.
Instructions for making a code change
-------------------------------------
####################
The central development branch is ``master``, which should be clean and ready for release at any time. In general, all changes should be done as feature branches based off of ``master``.
@@ -47,13 +54,12 @@ Here's how to make a one-off code change.
2. **Create a new branch with this name, starting from** ``master``. In other words, run:
``$ git fetch upstream``
.. code-block:: bash
``$ git checkout master``
``$ git merge upstream/master``
``$ git checkout -b your-branch-name``
$ git fetch upstream
$ git checkout master
$ git merge upstream/master
$ git checkout -b your-branch-name
3. **Make a commit to your feature branch**. Each commit should be self-contained and have a descriptive commit message that helps other developers understand why the changes were made.
@@ -75,19 +81,27 @@ Here's how to make a one-off code change.
- Before making a commit ensure that all automated tests still pass:
``$ make test``
.. code-block::
$ make test
- To actually make the commit (this will trigger tests for yapf, lint and pep8 automatically):
``$ git add your-file-changed.py``
.. code-block:: bash
- yapf may change code formatting, make sure to re-add them to your commit.
$ git add your-file-changed.py
``$ git commit -a -m "your-commit-message-here"``
- yapf may change code formatting, make sure to re-add them to your commit.
.. code-block:: bash
$ git commit -a -m "your-commit-message-here"
- Finally, push it to your GitHub fork, run:
``$ git push origin your-branch-name``
.. code-block:: bash
$ git push origin your-branch-name
4. **When your feature is ready to merge, create a pull request.**
@@ -107,70 +121,71 @@ Here's how to make a one-off code change.
- Resolve any merge conflicts that arise. To resolve conflicts between 'your-branch-name' (in your fork) and 'master' (in the ``python-telegram-bot`` repository), run:
``$ git checkout your-branch-name``
.. code-block:: bash
``$ git fetch upstream``
``$ git merge upstream/master``
``$ ...[fix the conflicts]...``
``$ ...[make sure the tests pass before committing]...``
``$ git commit -a``
``$ git push origin your-branch-name``
$ git checkout your-branch-name
$ git fetch upstream
$ git merge upstream/master
$ ...[fix the conflicts]...
$ ...[make sure the tests pass before committing]...
$ git commit -a
$ git push origin your-branch-name
- At the end, the reviewer will merge the pull request.
6. **Tidy up!** Delete the feature branch from both your local clone and the GitHub repository:
``$ git branch -D your-branch-name``
.. code-block:: bash
``$ git push origin --delete your-branch-name``
$ git branch -D your-branch-name
$ git push origin --delete your-branch-name
7. **Celebrate.** Congratulations, you have contributed to ``python-telegram-bot``!
Style commandments
==================
---------------------
Specific commandments
---------------------
#####################
- Avoid using "double quotes" where you can reasonably use 'single quotes'.
AssertEqual argument order
--------------------------
######################
assertEqual method's arguments should be in ('actual', 'expected') order.
- assertEqual method's arguments should be in ('actual', 'expected') order.
Properly calling callables
--------------------------
#######################
Methods, functions and classes can specify optional parameters (with default
values) using Python's keyword arg syntax. When providing a value to such a
callable we prefer that the call also uses keyword arg syntax. For example::
callable we prefer that the call also uses keyword arg syntax. For example:
# GOOD
f(0, optional=True)
.. code-block:: python
# BAD
f(0, True)
# GOOD
f(0, optional=True)
# BAD
f(0, True)
This gives us the flexibility to re-order arguments and more importantly
to add new required arguments. It's also more explicit and easier to read.
Properly defining optional arguments
------------------------------------
########################
It's always good to not initialize optional arguments at class creation,
instead use ``**kwargs`` to get them. It's well known Telegram API can
change without notice, in that case if a new argument is added it won't
break the API classes. For example::
It's always good to not initialize optional arguments at class creation,
instead use ``**kwargs`` to get them. It's well known Telegram API can
change without notice, in that case if a new argument is added it won't
break the API classes. For example:
.. code-block:: python
# GOOD
def __init__(self, id, name, **kwargs):
self.last_name = kwargs.get('last_name', '')
def __init__(self, id, name, last_name='', **kwargs):
self.last_name = last_name
# BAD
def __init__(self, id, name, last_name=''):
@@ -183,4 +198,4 @@ break the API classes. For example::
.. _`PEP 8 Style Guide`: https://www.python.org/dev/peps/pep-0008/
.. _`Google Python Style Guide`: https://google-styleguide.googlecode.com/svn/trunk/pyguide.html
.. _`Google Python Style Docstrings`: http://sphinx-doc.org/latest/ext/example_google.html
.. _AUTHORS.rst: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/AUTHORS.rst
.. _AUTHORS.rst: ../AUTHORS.rst
+6 -6
View File
@@ -1,6 +1,10 @@
<!--
Thanks for reporting issues of python-telegram-bot!
To make it easier for us to help you please enter detailed information below.
Please note, we only support the latest version of python-telegram-bot and
master branch. Please make sure to upgrade & recreate the issue on the latest
version prior to opening an issue.
-->
### Steps to reproduce
1.
@@ -19,13 +23,9 @@ Tell us what happens instead
**Operating System:**
**Version of Python:**
**Version of Python, python-telegram-bot & dependencies:**
``$ python -V``
**Version of python-telegram-bot:**
``$ python -c 'import telegram; print(telegram.__version__)'``
``$ python -m telegram``
### Logs
Insert logs here (if necessary)
+6
View File
@@ -68,3 +68,9 @@ telegram.mp4
telegram.ogg
telegram.png
telegram.webp
# original files from merges
*.orig
# Exclude .exrc file for Vim
.exrc
+4 -4
View File
@@ -1,15 +1,15 @@
- repo: git://github.com/pre-commit/mirrors-yapf
sha: 316b795b2f32cbe80047aff7e842b72368d5a2c1
- repo: git://github.com/python-telegram-bot/mirrors-yapf
sha: v0.12.2
hooks:
- id: yapf
files: ^(telegram|tests)/.*\.py$
- repo: git://github.com/pre-commit/pre-commit-hooks
sha: 6dfcb89af3c9b4d172cc2e5a8a2fa0f54615a338
sha: 18d7035de5388cc7775be57f529c154bf541aab9
hooks:
- id: flake8
files: ^telegram/.*\.py$
- repo: git://github.com/pre-commit/mirrors-pylint
sha: 4de6c8dfadef1a271a814561ce05b8bc1c446d22
sha: v1.5.5
hooks:
- id: pylint
files: ^telegram/.*\.py$
+5 -2
View File
@@ -1,18 +1,21 @@
language: python
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
- "3.5"
- "pypy"
- "pypy3"
branches:
only:
- master
install:
- pip install coveralls
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
- if [[ $TRAVIS_PYTHON_VERSION != 'pypy'* ]]; then pip install ujson; fi
script:
- nosetests -v --with-flaky --no-flaky-report --with-coverage --cover-package=telegram/
- 'if [ $TRAVIS_PYTHON_VERSION != 2.6 ] && [ $TRAVIS_PYTHON_VERSION != 3.3 ] && [ $TRAVIS_PYTHON_VERSION != pypy3 ]; then pre-commit run --all-files; fi'
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 ]]; then pre-commit run --all-files; fi
after_success:
coveralls
+10
View File
@@ -11,20 +11,30 @@ The following wonderful people contributed directly or indirectly to this projec
- `Avanatiker <https://github.com/Avanatiker>`_
- `Balduro <https://github.com/Balduro>`_
- `bimmlerd <https://github.com/bimmlerd>`_
- `Eli Gao <https://github.com/eligao>`_
- `ErgoZ Riftbit Vaper <https://github.com/ergoz>`_
- `Eugene Lisitsky <https://github.com/lisitsky>`_
- `franciscod <https://github.com/franciscod>`_
- `Jacob Bom <https://github.com/bomjacob>`_
- `JASON0916 <https://github.com/JASON0916>`_
- `jh0ker <https://github.com/jh0ker>`_
- `JRoot3D <https://github.com/JRoot3D>`_
- `jlmadurga <https://github.com/jlmadurga>`_
- `Kjwon15 <https://github.com/kjwon15>`_
- `Li-aung Yip <https://github.com/LiaungYip>`_
- `macrojames <https://github.com/macrojames>`_
- `Michael Elovskikh <https://github.com/wronglink>`_
- `naveenvhegde <https://github.com/naveenvhegde>`_
- `njittam <https://github.com/njittam>`_
- `Noam Meltzer <https://github.com/tsnoam>`_
- `Oleg Shlyazhko <https://github.com/ollmer>`_
- `overquota <https://github.com/overquota>`_
- `Patrick Hofmann <https://github.com/PH89>`_
- `Rahiel Kasim <https://github.com/rahiel>`_
- `Shelomentsev D <https://github.com/shelomentsevd>`_
- `sooyhwang <https://github.com/sooyhwang>`_
- `Valentijn <https://github.com/Faalentijn>`_
- `voider1 <https://github.com/voider1>`_
- `wjt <https://github.com/wjt>`_
Please add yourself here alphabetically when you submit your first pull request.
+61
View File
@@ -1,3 +1,64 @@
=======
Changes
=======
**2016-12-11**
*Released 5.3*
- Implement API changes of November 21st (Bot API 2.3)
- ``JobQueue`` now supports ``datetime.timedelta`` in addition to seconds
- ``JobQueue`` now supports running jobs only on certain days
- New ``Filters.reply`` filter
- Bugfix for ``Message.edit_reply_markup``
- Other bugfixes
**2016-10-25**
*Released 5.2*
- Implement API changes of October 3rd (games update)
- Add ``Message.edit_*`` methods
- Filters for the ``MessageHandler`` can now be combined using bitwise operators (``& and |``)
- Add a way to save user- and chat-related data temporarily
- Other bugfixes and improvements
**2016-09-24**
*Released 5.1*
- Drop Python 2.6 support
- Deprecate ``telegram.Emoji``
- Use ``ujson`` if available
- Add instance methods to ``Message``, ``Chat``, ``User``, ``InlineQuery`` and ``CallbackQuery``
- RegEx filtering for ``CallbackQueryHandler`` and ``InlineQueryHandler``
- New ``MessageHandler`` filters: ``forwarded`` and ``entity``
- Add ``Message.get_entity`` to correctly handle UTF-16 codepoints and ``MessageEntity`` offsets
- Fix bug in ``ConversationHandler`` when first handler ends the conversation
- Allow multiple ``Dispatcher`` instances
- Add ``ChatMigrated`` Exception
- Properly split and handle arguments in ``CommandHandler``
**2016-07-15**
*Released 5.0*
- Rework ``JobQueue``
- Introduce ``ConversationHandler``
**2016-07-12**
*Released 4.3.4*
- Fix proxy support with ``urllib3`` when proxy requires auth
**2016-07-08**
*Released 4.3.3*
- Fix proxy support with ``urllib3``
**2016-07-04**
*Released 4.3.2*
+18 -21
View File
@@ -1,9 +1,9 @@
.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-logo-text_768.png?raw=true
:align: center
:target: https://github.com/python-telegram-bot/logos
:target: https://python-telegram-bot.org
:alt: python-telegram-bot Logo
Not **just** a Python wrapper around the Telegram Bot API
We have made you a wrapper you can't refuse
*Stay tuned for library updates and new releases on our* `Telegram Channel <https://telegram.me/pythontelegrambotchannel>`_.
@@ -16,7 +16,7 @@ Not **just** a Python wrapper around the Telegram Bot API
:alt: Supported python versions
.. image:: https://img.shields.io/badge/docs-latest-af1a97.svg
:target: https://pythonhosted.org/python-telegram-bot/
:target: https://python-telegram-bot.readthedocs.io/
:alt: Documentation Status
.. image:: https://img.shields.io/pypi/l/python-telegram-bot.svg
@@ -37,7 +37,7 @@ Not **just** a Python wrapper around the Telegram Bot API
.. image:: http://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
:target: http://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
:alt: Average time to resolve an issue
:alt: Median time to resolve an issue
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg
:target: https://telegram.me/pythontelegrambotgroup
@@ -73,8 +73,7 @@ Introduction
This library provides a pure Python interface for the
`Telegram Bot API <https://core.telegram.org/bots/api>`_.
It works with Python versions from 2.6+ (**Note:** Support for 2.6 will be dropped at some point
this year. 2.7 will still be supported).
It's compatible with Python versions 2.7, 3.3+ and `PyPy <http://pypy.org/>`_.
It also works with `Google App Engine <https://cloud.google.com/appengine>`_.
In addition to the pure API implementation, this library features a number of high-level classes to
@@ -85,7 +84,7 @@ make the development of bots easy and straightforward. These classes are contain
Telegram API support
====================
As of **28. May 2016**, all types and methods of the Telegram Bot API are supported.
As of **3. Oct 2016**, all types and methods of the Telegram Bot API are supported.
==========
Installing
@@ -97,6 +96,14 @@ You can install or upgrade python-telegram-bot with:
$ pip install python-telegram-bot --upgrade
Or you can install from source with:
.. code:: shell
$ git clone https://github.com/python-telegram-bot/python-telegram-bot
$ cd python-telegram-bot
$ python setup.py install
===============
Getting started
===============
@@ -109,7 +116,7 @@ Our Wiki contains a lot of resources to get you started with ``python-telegram-b
Other references:
- `Telegram API documentation <https://core.telegram.org/bots/api>`_
- `python-telegram-bot documentation <https://pythonhosted.org/python-telegram-bot/>`_
- `python-telegram-bot documentation <https://python-telegram-bot.readthedocs.io/>`_
-------------------
Learning by example
@@ -117,21 +124,11 @@ Learning by example
We believe that the best way to learn and understand this simple package is by example. So here
are some examples for you to review. Even if it's not your approach for learning, please take a
look at ``echobot2`` (below), it is de facto the base for most of the bots out there. Best of all,
look at ``echobot2``, it is de facto the base for most of the bots out there. Best of all,
the code for these examples are released to the public domain, so you can start by grabbing the
code and building on top of it.
- `echobot2 <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/echobot2.py>`_ replies back messages.
- `inlinebot <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/inlinebot.py>`_ basic example of an `inline bot <https://core.telegram.org/bots/inline>`_.
- `state machine bot <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/state_machine_bot.py>`_ keeps the state for individual users, useful for multipart conversations.
- `timerbot <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/timerbot.py>`_ uses the ``JobQueue`` to send timed messages.
- `echobot <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/legacy/echobot.py>`_ uses only the pure API to echo messages.
Look at the examples on the `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Examples>`_ to see other bots the community has built.
Visit `this page <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/README.md>`_ to discover the official examples or look at the examples on the `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Examples>`_ to see other bots the community has built.
-------
Logging
@@ -165,7 +162,7 @@ If you want DEBUG logs instead:
Documentation
=============
``python-telegram-bot``'s documentation lives at `pythonhosted.org <https://pythonhosted.org/python-telegram-bot/>`_.
``python-telegram-bot``'s documentation lives at `readthedocs.io <https://python-telegram-bot.readthedocs.io/>`_.
============
Getting help
+1 -1
View File
@@ -189,4 +189,4 @@ xml:
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+12 -9
View File
@@ -15,7 +15,7 @@
import sys
import os
import shlex
import telegram
# import telegram
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -59,9 +59,9 @@ author = u'Leandro Toledo'
# built documents.
#
# The short X.Y version.
version = telegram.__version__[:3]
version = '5.3' # telegram.__version__[:3]
# The full version, including alpha/beta/rc tags.
release = telegram.__version__
release = '5.3.0' # telegram.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -131,7 +131,7 @@ html_theme = 'sphinx_rtd_theme'
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
html_logo = 'ptb-logo-orange.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
@@ -209,14 +209,17 @@ htmlhelp_basename = 'PythonTelegramBotdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
'papersize': 'a4paper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
'preamble': r'''\setcounter{tocdepth}{2}
\usepackage{enumitem}
\setlistdepth{99}''',
# Latex figure (float) alignment
#'figure_align': 'htbp',
@@ -227,12 +230,12 @@ latex_elements = {
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'PythonTelegramBot.tex', u'Python Telegram Bot Documentation',
u'Leandro Toledo', 'manual'),
author, 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
latex_logo = 'ptb-logo_1024.png'
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
@@ -271,7 +274,7 @@ man_pages = [
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'PythonTelegramBot', u'Python Telegram Bot Documentation',
author, 'PythonTelegramBot', 'Not just a Python wrapper around the Telegram Bot API',
author, 'PythonTelegramBot', "We have made you a wrapper you can't refuse",
'Miscellaneous'),
]
+1 -4
View File
@@ -6,11 +6,8 @@
Welcome to Python Telegram Bot's documentation!
===============================================
Contents:
.. toctree::
:maxdepth: 2
telegram
Indices and tables
-7
View File
@@ -1,7 +0,0 @@
telegram
========
.. toctree::
:maxdepth: 4
telegram
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

+7
View File
@@ -0,0 +1,7 @@
telegram.animation module
=========================
.. automodule:: telegram.animation
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.callbackgame module
============================
.. automodule:: telegram.callbackgame
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.callbackquery module
=============================
.. automodule:: telegram.callbackquery
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.chatmember module
==========================
.. automodule:: telegram.chatmember
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.constants module
=========================
.. automodule:: telegram.constants
:members:
:undoc-members:
:show-inheritance:
+17
View File
@@ -0,0 +1,17 @@
telegram.contrib package
========================
Submodules
----------
.. toctree::
telegram.contrib.botan
Module contents
---------------
.. automodule:: telegram.contrib
:members:
:undoc-members:
:show-inheritance:
@@ -1,7 +1,7 @@
telegram.ext.handler module
===========================
telegram.ext.callbackqueryhandler module
========================================
.. automodule:: telegram.ext.handler
.. automodule:: telegram.ext.callbackqueryhandler
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.ext.conversationhandler module
=======================================
.. automodule:: telegram.ext.conversationhandler
:members:
:undoc-members:
:show-inheritance:
@@ -1,7 +1,7 @@
telegram.nullhandler module
telegram.ext.filters module
===========================
.. automodule:: telegram.nullhandler
.. automodule:: telegram.ext.filters
:members:
:undoc-members:
:show-inheritance:
+3
View File
@@ -10,10 +10,13 @@ Submodules
telegram.ext.dispatcher
telegram.ext.jobqueue
telegram.ext.handler
telegram.ext.callbackqueryhandler
telegram.ext.choseninlineresulthandler
telegram.ext.conversationhandler
telegram.ext.commandhandler
telegram.ext.inlinequeryhandler
telegram.ext.messagehandler
telegram.ext.filters
telegram.ext.regexhandler
telegram.ext.stringcommandhandler
telegram.ext.stringregexhandler
+7
View File
@@ -0,0 +1,7 @@
telegram.file module
====================
.. automodule:: telegram.file
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.game module
====================
.. automodule:: telegram.game
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.gamehighscore module
=============================
.. automodule:: telegram.gamehighscore
:members:
:undoc-members:
:show-inheritance:
@@ -1,5 +1,5 @@
telegram.inlinekeyboardbutton module
===========================
====================================
.. automodule:: telegram.inlinekeyboardbutton
:members:
@@ -1,5 +1,5 @@
telegram.inlinekeyboardmarkup module
==========================
====================================
.. automodule:: telegram.inlinekeyboardmarkup
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultarticle module
=================================
========================================
.. automodule:: telegram.inlinequeryresultarticle
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultaudio module
=================================
======================================
.. automodule:: telegram.inlinequeryresultaudio
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedaudio module
=================================
============================================
.. automodule:: telegram.inlinequeryresultcachedaudio
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcacheddocument module
=================================
===============================================
.. automodule:: telegram.inlinequeryresultcacheddocument
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedgif module
=================================
==========================================
.. automodule:: telegram.inlinequeryresultcachedgif
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedmpeg4gif module
=================================
===============================================
.. automodule:: telegram.inlinequeryresultcachedmpeg4gif
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedphoto module
=================================
============================================
.. automodule:: telegram.inlinequeryresultcachedphoto
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedsticker module
=================================
==============================================
.. automodule:: telegram.inlinequeryresultcachedsticker
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedvideo module
=================================
============================================
.. automodule:: telegram.inlinequeryresultcachedvideo
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcachedvoice module
=================================
============================================
.. automodule:: telegram.inlinequeryresultcachedvoice
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultcontact module
=================================
========================================
.. automodule:: telegram.inlinequeryresultcontact
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultdocument module
=================================
=========================================
.. automodule:: telegram.inlinequeryresultdocument
:members:
@@ -0,0 +1,7 @@
telegram.inlinequeryresultgame module
=====================================
.. automodule:: telegram.inlinequeryresultgame
:members:
:undoc-members:
:show-inheritance:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultgif module
=================================
====================================
.. automodule:: telegram.inlinequeryresultgif
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultlocation module
=================================
=========================================
.. automodule:: telegram.inlinequeryresultlocation
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultmpeg4gif module
=================================
=========================================
.. automodule:: telegram.inlinequeryresultmpeg4gif
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultphoto module
=================================
======================================
.. automodule:: telegram.inlinequeryresultphoto
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultvenue module
=================================
======================================
.. automodule:: telegram.inlinequeryresultvenue
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultvideo module
=================================
======================================
.. automodule:: telegram.inlinequeryresultvideo
:members:
@@ -1,5 +1,5 @@
telegram.inlinequeryresultvoice module
=================================
======================================
.. automodule:: telegram.inlinequeryresultvoice
:members:
@@ -0,0 +1,7 @@
telegram.inputcontactmessagecontent module
==========================================
.. automodule:: telegram.inputcontactmessagecontent
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.inputlocationmessagecontent module
===========================================
.. automodule:: telegram.inputlocationmessagecontent
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.inputmessagecontent module
===================================
.. automodule:: telegram.inputmessagecontent
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.inputtextmessagecontent module
=======================================
.. automodule:: telegram.inputtextmessagecontent
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.inputvenuemessagecontent module
========================================
.. automodule:: telegram.inputvenuemessagecontent
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.keyboardbutton module
==============================
.. automodule:: telegram.keyboardbutton
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.messageentity module
=============================
.. automodule:: telegram.messageentity
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.parsemode module
=========================
.. automodule:: telegram.parsemode
:members:
:undoc-members:
:show-inheritance:
@@ -1,7 +0,0 @@
telegram.replykeyboardhide module
=================================
.. automodule:: telegram.replykeyboardhide
:members:
:undoc-members:
:show-inheritance:
@@ -0,0 +1,7 @@
telegram.replykeyboardremove module
===================================
.. automodule:: telegram.replykeyboardremove
:members:
:undoc-members:
:show-inheritance:
+31 -13
View File
@@ -6,14 +6,30 @@ Submodules
.. toctree::
telegram.contrib
telegram.ext
telegram.animation
telegram.audio
telegram.base
telegram.bot
telegram.ext
telegram.inlinequery
telegram.inlinequeryresult
telegram.callbackgame
telegram.callbackquery
telegram.chat
telegram.chataction
telegram.chatmember
telegram.choseninlineresult
telegram.constants
telegram.contact
telegram.document
telegram.error
telegram.file
telegram.forcereply
telegram.game
telegram.gamehighscore
telegram.inlinekeyboardbutton
telegram.inlinekeyboardmarkup
telegram.inlinequery
telegram.inlinequeryresult
telegram.inlinequeryresultarticle
telegram.inlinequeryresultaudio
telegram.inlinequeryresultcachedaudio
@@ -26,6 +42,7 @@ Submodules
telegram.inlinequeryresultcachedvoice
telegram.inlinequeryresultcontact
telegram.inlinequeryresultdocument
telegram.inlinequeryresultgame
telegram.inlinequeryresultgif
telegram.inlinequeryresultlocation
telegram.inlinequeryresultmpeg4gif
@@ -33,28 +50,29 @@ Submodules
telegram.inlinequeryresultvenue
telegram.inlinequeryresultvideo
telegram.inlinequeryresultvoice
telegram.choseninlineresult
telegram.chataction
telegram.contact
telegram.document
telegram.emoji
telegram.error
telegram.forcereply
telegram.chat
telegram.inputcontactmessagecontent
telegram.inputfile
telegram.inputlocationmessagecontent
telegram.inputmessagecontent
telegram.inputtextmessagecontent
telegram.inputvenuemessagecontent
telegram.keyboardbutton
telegram.location
telegram.message
telegram.nullhandler
telegram.messageentity
telegram.parsemode
telegram.photosize
telegram.replykeyboardhide
telegram.replykeyboardremove
telegram.replykeyboardmarkup
telegram.replymarkup
telegram.sticker
telegram.update
telegram.user
telegram.userprofilephotos
telegram.venue
telegram.video
telegram.voice
telegram.webhookinfo
Module contents
---------------
@@ -1,7 +1,7 @@
telegram.emoji module
telegram.venue module
=====================
.. automodule:: telegram.emoji
.. automodule:: telegram.venue
:members:
:undoc-members:
:show-inheritance:
+7
View File
@@ -0,0 +1,7 @@
telegram.webhookinfo module
===========================
.. automodule:: telegram.webhookinfo
:members:
:undoc-members:
:show-inheritance:
+26
View File
@@ -0,0 +1,26 @@
# Examples
The examples in this folder are small bots meant to show you how a bot that is written with `python-telegram-bot` looks like. Some bots focus on one specific aspect of the Telegram Bot API while others focus on one of the mechanics of this library. Except for the `echobot.py` example, they all use the high-level framework this library provides with the `telegram.ext` submodule.
All examples are licensed under the [CC0 License](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/LICENSE.txt) and are therefore fully dedicated to the public domain. You can use them as the base for your own bots without worrying about copyrights.
### [`echobot2.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/echobot2.py)
This is probably the base for most of the bots made with `python-telegram-bot`. It simply replies to each text message with a message that contains the same text.
### [`timerbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/timerbot.py)
This bot uses the [`JobQueue`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.jobqueue.html) class to send timed messages. The user sets a timer by using `/set` command with a specific time, for example `/set 30`. The bot then sets up a job to send a message to that user after 30 seconds. The user can also cancel the timer by sending `/unset`. To learn more about the `JobQueue`, read [this wiki article](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-JobQueue).
### [`conversationbot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.py)
A common task for a bot is to ask information from the user. In v5.0 of this library, we introduced the [`ConversationHandler`](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.conversationhandler.html) for that exact purpose. This example uses it to retrieve user-information in a conversation-like style. To get a better understanding, take a look at the [state diagram](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.png).
### [`conversationbot2.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot2.py)
A more complex example of a bot that uses the `ConversationHandler`. It is also more confusing. Good thing there is a [fancy state diagram](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot2.png) for this one, too!
### [`inlinekeyboard.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/inlinekeyboard.py)
This example sheds some light on inline keyboards, callback queries and message editing.
### [`inlinebot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/inlinebot.py)
A basic example of an [inline bot](https://core.telegram.org/bots/inline). Don't forget to enable inline mode with [@BotFather](https://telegram.me/BotFather).
## Pure API
The [`echobot.py`](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/echobot.py) example uses only the pure, "bare-metal" API wrapper.
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

+159
View File
@@ -0,0 +1,159 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Simple Bot to reply to Telegram messages
# This program is dedicated to the public domain under the CC0 license.
"""
This Bot uses the Updater class to handle the bot.
First, a few callback functions are defined. Then, those functions are passed to
the Dispatcher and registered at their respective places.
Then, the bot is started and runs until we press Ctrl-C on the command line.
Usage:
Example of a bot-user conversation using ConversationHandler.
Send /start to initiate the conversation.
Press Ctrl-C on the command line or send a signal to the process to stop the
bot.
"""
from telegram import (ReplyKeyboardMarkup, ReplyKeyboardRemove)
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters, RegexHandler,
ConversationHandler)
import logging
# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
GENDER, PHOTO, LOCATION, BIO = range(4)
def start(bot, update):
reply_keyboard = [['Boy', 'Girl', 'Other']]
update.message.reply_text(
'Hi! My name is Professor Bot. I will hold a conversation with you. '
'Send /cancel to stop talking to me.\n\n'
'Are you a boy or a girl?',
reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
return GENDER
def gender(bot, update):
user = update.message.from_user
logger.info("Gender of %s: %s" % (user.first_name, update.message.text))
update.message.reply_text('I see! Please send me a photo of yourself, '
'so I know what you look like, or send /skip if you don\'t want to.',
reply_markup=ReplyKeyboardRemove())
return PHOTO
def photo(bot, update):
user = update.message.from_user
photo_file = bot.getFile(update.message.photo[-1].file_id)
photo_file.download('user_photo.jpg')
logger.info("Photo of %s: %s" % (user.first_name, 'user_photo.jpg'))
update.message.reply_text('Gorgeous! Now, send me your location please, '
'or send /skip if you don\'t want to.')
return LOCATION
def skip_photo(bot, update):
user = update.message.from_user
logger.info("User %s did not send a photo." % user.first_name)
update.message.reply_text('I bet you look great! Now, send me your location please, '
'or send /skip.')
return LOCATION
def location(bot, update):
user = update.message.from_user
user_location = update.message.location
logger.info("Location of %s: %f / %f"
% (user.first_name, user_location.latitude, user_location.longitude))
update.message.reply_text('Maybe I can visit you sometime! '
'At last, tell me something about yourself.')
return BIO
def skip_location(bot, update):
user = update.message.from_user
logger.info("User %s did not send a location." % user.first_name)
update.message.reply_text('You seem a bit paranoid! '
'At last, tell me something about yourself.')
return BIO
def bio(bot, update):
user = update.message.from_user
logger.info("Bio of %s: %s" % (user.first_name, update.message.text))
update.message.reply_text('Thank you! I hope we can talk again some day.')
return ConversationHandler.END
def cancel(bot, update):
user = update.message.from_user
logger.info("User %s canceled the conversation." % user.first_name)
update.message.reply_text('Bye! I hope we can talk again some day.',
reply_markup=ReplyKeyboardRemove())
return ConversationHandler.END
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
# Add conversation handler with the states GENDER, PHOTO, LOCATION and BIO
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start)],
states={
GENDER: [RegexHandler('^(Boy|Girl|Other)$', gender)],
PHOTO: [MessageHandler(Filters.photo, photo),
CommandHandler('skip', skip_photo)],
LOCATION: [MessageHandler(Filters.location, location),
CommandHandler('skip', skip_location)],
BIO: [MessageHandler(Filters.text, bio)]
},
fallbacks=[CommandHandler('cancel', cancel)]
)
dp.add_handler(conv_handler)
# log all errors
dp.add_error_handler(error)
# Start the Bot
updater.start_polling()
# Run the bot until the you presses Ctrl-C or the process receives SIGINT,
# SIGTERM or SIGABRT. This should be used most of the time, since
# start_polling() is non-blocking and will stop the bot gracefully.
updater.idle()
if __name__ == '__main__':
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

+152
View File
@@ -0,0 +1,152 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Simple Bot to reply to Telegram messages
# This program is dedicated to the public domain under the CC0 license.
"""
This Bot uses the Updater class to handle the bot.
First, a few callback functions are defined. Then, those functions are passed to
the Dispatcher and registered at their respective places.
Then, the bot is started and runs until we press Ctrl-C on the command line.
Usage:
Example of a bot-user conversation using ConversationHandler.
Send /start to initiate the conversation.
Press Ctrl-C on the command line or send a signal to the process to stop the
bot.
"""
from telegram import ReplyKeyboardMarkup
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters, RegexHandler,
ConversationHandler)
import logging
# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
CHOOSING, TYPING_REPLY, TYPING_CHOICE = range(3)
reply_keyboard = [['Age', 'Favourite colour'],
['Number of siblings', 'Something else...'],
['Done']]
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
def facts_to_str(user_data):
facts = list()
for key, value in user_data.items():
facts.append('%s - %s' % (key, value))
return "\n".join(facts).join(['\n', '\n'])
def start(bot, update):
update.message.reply_text(
"Hi! My name is Doctor Botter. I will hold a more complex conversation with you. "
"Why don't you tell me something about yourself?",
reply_markup=markup)
return CHOOSING
def regular_choice(bot, update, user_data):
text = update.message.text
user_data['choice'] = text
update.message.reply_text('Your %s? Yes, I would love to hear about that!' % text.lower())
return TYPING_REPLY
def custom_choice(bot, update):
update.message.reply_text('Alright, please send me the category first, '
'for example "Most impressive skill"')
return TYPING_CHOICE
def received_information(bot, update, user_data):
text = update.message.text
category = user_data['choice']
user_data[category] = text
del user_data['choice']
update.message.reply_text("Neat! Just so you know, this is what you already told me:"
"%s"
"You can tell me more, or change your opinion on something."
% facts_to_str(user_data),
reply_markup=markup)
return CHOOSING
def done(bot, update, user_data):
if 'choice' in user_data:
del user_data['choice']
update.message.reply_text("I learned these facts about you:"
"%s"
"Until next time!" % facts_to_str(user_data))
user_data.clear()
return ConversationHandler.END
def error(bot, update, error):
logger.warn('Update "%s" caused error "%s"' % (update, error))
def main():
# Create the Updater and pass it your bot's token.
updater = Updater("TOKEN")
# Get the dispatcher to register handlers
dp = updater.dispatcher
# Add conversation handler with the states GENDER, PHOTO, LOCATION and BIO
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start)],
states={
CHOOSING: [RegexHandler('^(Age|Favourite colour|Number of siblings)$',
regular_choice,
pass_user_data=True),
RegexHandler('^Something else...$',
custom_choice),
],
TYPING_CHOICE: [MessageHandler(Filters.text,
regular_choice,
pass_user_data=True),
],
TYPING_REPLY: [MessageHandler(Filters.text,
received_information,
pass_user_data=True),
],
},
fallbacks=[RegexHandler('^Done$', done, pass_user_data=True)]
)
dp.add_handler(conv_handler)
# log all errors
dp.add_error_handler(error)
# Start the Bot
updater.start_polling()
# Run the bot until the you presses Ctrl-C or the process receives SIGINT,
# SIGTERM or SIGABRT. This should be used most of the time, since
# start_polling() is non-blocking and will stop the bot gracefully.
updater.idle()
if __name__ == '__main__':
main()
+1 -1
View File
@@ -46,7 +46,7 @@ def echo(bot):
if update.message: # your bot can receive updates without messages
# Reply to the message
bot.sendMessage(chat_id=chat_id, text=update.message.text)
update.message.reply_text(update.message.text)
if __name__ == '__main__':
+4 -4
View File
@@ -29,15 +29,15 @@ logger = logging.getLogger(__name__)
# Define a few command handlers. These usually take the two arguments bot and
# update. Error handlers also receive the raised TelegramError object in error.
def start(bot, update):
bot.sendMessage(update.message.chat_id, text='Hi!')
update.message.reply_text('Hi!')
def help(bot, update):
bot.sendMessage(update.message.chat_id, text='Help!')
update.message.reply_text('Help!')
def echo(bot, update):
bot.sendMessage(update.message.chat_id, text=update.message.text)
update.message.reply_text(update.message.text)
def error(bot, update, error):
@@ -56,7 +56,7 @@ def main():
dp.add_handler(CommandHandler("help", help))
# on noncommand i.e message - echo the message on Telegram
dp.add_handler(MessageHandler([Filters.text], echo))
dp.add_handler(MessageHandler(Filters.text, echo))
# log all errors
dp.add_error_handler(error)
+3 -3
View File
@@ -34,11 +34,11 @@ logger = logging.getLogger(__name__)
# Define a few command handlers. These usually take the two arguments bot and
# update. Error handlers also receive the raised TelegramError object in error.
def start(bot, update):
bot.sendMessage(update.message.chat_id, text='Hi!')
update.message.reply_text('Hi!')
def help(bot, update):
bot.sendMessage(update.message.chat_id, text='Help!')
update.message.reply_text('Help!')
def escape_markdown(text):
@@ -68,7 +68,7 @@ def inlinequery(bot, update):
"_%s_" % escape_markdown(query),
parse_mode=ParseMode.MARKDOWN)))
bot.answerInlineQuery(update.inline_query.id, results=results)
update.inline_query.answer(results)
def error(bot, update, error):
+20 -79
View File
@@ -1,108 +1,49 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Basic example for a bot that awaits an answer from the user. It's built upon
# the state_machine_bot.py example
# Basic example for a bot that uses inline keyboards.
# This program is dedicated to the public domain under the CC0 license.
import logging
from telegram import Emoji, ForceReply, InlineKeyboardButton, \
InlineKeyboardMarkup
from telegram.ext import Updater, CommandHandler, MessageHandler, \
CallbackQueryHandler, Filters
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.DEBUG)
# Define the different states a chat can be in
MENU, AWAIT_CONFIRMATION, AWAIT_INPUT = range(3)
# Python 2 and 3 unicode differences
try:
YES, NO = (Emoji.THUMBS_UP_SIGN.decode('utf-8'), Emoji.THUMBS_DOWN_SIGN.decode('utf-8'))
except AttributeError:
YES, NO = (Emoji.THUMBS_UP_SIGN, Emoji.THUMBS_DOWN_SIGN)
# States are saved in a dict that maps chat_id -> state
state = dict()
# Sometimes you need to save data temporarily
context = dict()
# This dict is used to store the settings value for the chat.
# Usually, you'd use persistence for this (e.g. sqlite).
values = dict()
level=logging.INFO)
# Example handler. Will be called on the /set command and on regular messages
def set_value(bot, update):
chat_id = update.message.chat_id
user_id = update.message.from_user.id
user_state = state.get(chat_id, MENU)
def start(bot, update):
keyboard = [[InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2')],
if user_state == MENU:
state[user_id] = AWAIT_INPUT # set the state
bot.sendMessage(chat_id,
text="Please enter your settings value",
reply_markup=ForceReply())
[InlineKeyboardButton("Option 3", callback_data='3')]]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text('Please choose:', reply_markup=reply_markup)
def entered_value(bot, update):
chat_id = update.message.chat_id
user_id = update.message.from_user.id
chat_state = state.get(user_id, MENU)
# Check if we are waiting for input
if chat_state == AWAIT_INPUT:
state[user_id] = AWAIT_CONFIRMATION
# Save the user id and the answer to context
context[user_id] = update.message.text
reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton(YES, callback_data=YES),
InlineKeyboardButton(NO, callback_data=NO)]])
bot.sendMessage(chat_id, text="Are you sure?", reply_markup=reply_markup)
def confirm_value(bot, update):
def button(bot, update):
query = update.callback_query
chat_id = query.message.chat_id
user_id = query.from_user.id
text = query.data
user_state = state.get(user_id, MENU)
user_context = context.get(user_id, None)
# Check if we are waiting for confirmation and the right user answered
if user_state == AWAIT_CONFIRMATION:
del state[user_id]
del context[user_id]
bot.answerCallbackQuery(query.id, text="Ok!")
if text == YES:
values[user_id] = user_context
bot.editMessageText(text="Changed value to %s." % values[user_id],
chat_id=chat_id,
message_id=query.message.message_id)
else:
bot.editMessageText(text="Alright, value is still %s." %
values.get(user_id, 'not set'),
chat_id=chat_id,
message_id=query.message.message_id)
bot.editMessageText(text="Selected option: %s" % query.data,
chat_id=query.message.chat_id,
message_id=query.message.message_id)
def help(bot, update):
bot.sendMessage(update.message.chat_id, text="Use /set to test this bot.")
update.message.reply_text("Use /start to test this bot.")
def error(bot, update, error):
logging.warning('Update "%s" caused error "%s"' % (update, error))
# Create the Updater and pass it your bot's token.
updater = Updater("TOKEN")
# The command
updater.dispatcher.add_handler(CommandHandler('set', set_value))
# The answer
updater.dispatcher.add_handler(MessageHandler([Filters.text], entered_value))
# The confirmation
updater.dispatcher.add_handler(CallbackQueryHandler(confirm_value))
updater.dispatcher.add_handler(CommandHandler('start', help))
updater.dispatcher.add_handler(CommandHandler('start', start))
updater.dispatcher.add_handler(CallbackQueryHandler(button))
updater.dispatcher.add_handler(CommandHandler('help', help))
updater.dispatcher.add_error_handler(error)
-100
View File
@@ -1,100 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Basic example for a bot that awaits an answer from the user
# This program is dedicated to the public domain under the CC0 license.
import logging
from telegram import Emoji, ForceReply, ReplyKeyboardMarkup, KeyboardButton
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
# Define the different states a chat can be in
MENU, AWAIT_CONFIRMATION, AWAIT_INPUT = range(3)
# Python 2 and 3 unicode differences
try:
YES, NO = (Emoji.THUMBS_UP_SIGN.decode('utf-8'), Emoji.THUMBS_DOWN_SIGN.decode('utf-8'))
except AttributeError:
YES, NO = (Emoji.THUMBS_UP_SIGN, Emoji.THUMBS_DOWN_SIGN)
# States are saved in a dict that maps chat_id -> state
state = dict()
# Sometimes you need to save data temporarily
context = dict()
# This dict is used to store the settings value for the chat.
# Usually, you'd use persistence for this (e.g. sqlite).
values = dict()
# Example handler. Will be called on the /set command and on regular messages
def set_value(bot, update):
chat_id = update.message.chat_id
user_id = update.message.from_user.id
text = update.message.text
chat_state = state.get(chat_id, MENU)
chat_context = context.get(chat_id, None)
# Since the handler will also be called on messages, we need to check if
# the message is actually a command
if chat_state == MENU and text[0] == '/':
state[chat_id] = AWAIT_INPUT # set the state
context[chat_id] = user_id # save the user id to context
bot.sendMessage(chat_id,
text="Please enter your settings value or send "
"/cancel to abort",
reply_markup=ForceReply())
# If we are waiting for input and the right user answered
elif chat_state == AWAIT_INPUT and chat_context == user_id:
state[chat_id] = AWAIT_CONFIRMATION
# Save the user id and the answer to context
context[chat_id] = (user_id, update.message.text)
reply_markup = ReplyKeyboardMarkup(
[[KeyboardButton(YES), KeyboardButton(NO)]],
one_time_keyboard=True)
bot.sendMessage(chat_id, text="Are you sure?", reply_markup=reply_markup)
# If we are waiting for confirmation and the right user answered
elif chat_state == AWAIT_CONFIRMATION and chat_context[0] == user_id:
del state[chat_id]
del context[chat_id]
if text == YES:
values[chat_id] = chat_context[1]
bot.sendMessage(chat_id, text="Changed value to %s." % values[chat_id])
else:
bot.sendMessage(chat_id,
text="Value not changed: %s." % values.get(chat_id, '<not set>'))
# Handler for the /cancel command.
# Sets the state back to MENU and clears the context
def cancel(bot, update):
chat_id = update.message.chat_id
del state[chat_id]
del context[chat_id]
def help(bot, update):
bot.sendMessage(update.message.chat_id, text="Use /set to test this bot.")
# Create the Updater and pass it your bot's token.
updater = Updater("TOKEN")
# The command
updater.dispatcher.add_handler(CommandHandler('set', set_value))
# The answer and confirmation
updater.dispatcher.add_handler(MessageHandler([Filters.text], set_value))
updater.dispatcher.add_handler(CommandHandler('cancel', cancel))
updater.dispatcher.add_handler(CommandHandler('start', help))
updater.dispatcher.add_handler(CommandHandler('help', help))
# Start the Bot
updater.start_polling()
# Run the bot until the user presses Ctrl-C or the process receives SIGINT,
# SIGTERM or SIGABRT
updater.idle()
+37 -21
View File
@@ -17,44 +17,62 @@ Press Ctrl-C on the command line or send a signal to the process to stop the
bot.
"""
from telegram.ext import Updater, CommandHandler
from telegram.ext import Updater, CommandHandler, Job
import logging
# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
level=logging.DEBUG)
logger = logging.getLogger(__name__)
job_queue = None
timers = dict()
# Define a few command handlers. These usually take the two arguments bot and
# update. Error handlers also receive the raised TelegramError object in error.
def start(bot, update):
bot.sendMessage(update.message.chat_id, text='Hi! Use /set <seconds> to ' 'set a timer')
update.message.reply_text('Hi! Use /set <seconds> to set a timer')
def set(bot, update, args):
""" Adds a job to the queue """
def alarm(bot, job):
"""Function to send the alarm message"""
bot.sendMessage(job.context, text='Beep!')
def set(bot, update, args, job_queue):
"""Adds a job to the queue"""
chat_id = update.message.chat_id
try:
# args[0] should contain the time for the timer in seconds
due = int(args[0])
if due < 0:
bot.sendMessage(chat_id, text='Sorry we can not go back to future!')
def alarm(bot):
""" Inner function to send the alarm message """
bot.sendMessage(chat_id, text='Beep!')
update.message.reply_text('Sorry we can not go back to future!')
return
# Add job to queue
job_queue.put(alarm, due, repeat=False)
bot.sendMessage(chat_id, text='Timer successfully set!')
job = Job(alarm, due, repeat=False, context=chat_id)
timers[chat_id] = job
job_queue.put(job)
except IndexError:
bot.sendMessage(chat_id, text='Usage: /set <seconds>')
except ValueError:
bot.sendMessage(chat_id, text='Usage: /set <seconds>')
update.message.reply_text('Timer successfully set!')
except (IndexError, ValueError):
update.message.reply_text('Usage: /set <seconds>')
def unset(bot, update):
"""Removes the job if the user changed their mind"""
chat_id = update.message.chat_id
if chat_id not in timers:
update.message.reply_text('You have no active timer')
return
job = timers[chat_id]
job.schedule_removal()
del timers[chat_id]
update.message.reply_text('Timer successfully unset!')
def error(bot, update, error):
@@ -62,10 +80,7 @@ def error(bot, update, error):
def main():
global job_queue
updater = Updater("TOKEN")
job_queue = updater.job_queue
# Get the dispatcher to register handlers
dp = updater.dispatcher
@@ -73,7 +88,8 @@ def main():
# on different commands - answer in Telegram
dp.add_handler(CommandHandler("start", start))
dp.add_handler(CommandHandler("help", start))
dp.add_handler(CommandHandler("set", set, pass_args=True))
dp.add_handler(CommandHandler("set", set, pass_args=True, pass_job_queue=True))
dp.add_handler(CommandHandler("unset", unset))
# log all errors
dp.add_error_handler(error)
-1
View File
@@ -2,7 +2,6 @@ flake8
nose
pep257
pylint
unittest2
flaky
yapf
pre-commit
+13 -5
View File
@@ -2,7 +2,7 @@
"""The setup and build script for the python-telegram-bot library."""
import codecs
import telegram
import os
from setuptools import setup, find_packages
@@ -16,18 +16,27 @@ def requirements():
return requirements_list
with codecs.open('README.rst', 'r', 'utf-8') as fd:
fn = os.path.join('telegram', 'version.py')
with open(fn) as fh:
code = compile(fh.read(), fn, 'exec')
exec(code)
setup(name='python-telegram-bot',
version=telegram.__version__,
version=__version__,
author='Leandro Toledo',
author_email='devs@python-telegram-bot.org',
license='LGPLv3',
url='https://github.com/python-telegram-bot/python-telegram-bot',
url='https://python-telegram-bot.org/',
keywords='python telegram bot api wrapper',
description='Not just a Python wrapper around the Telegram Bot API',
description="We have made you a wrapper you can't refuse",
long_description=fd.read(),
packages=find_packages(exclude=['tests*']),
install_requires=requirements(),
extras_require={
'json': 'ujson',
},
include_package_data=True,
classifiers=[
'Development Status :: 5 - Production/Stable',
@@ -39,7 +48,6 @@ with codecs.open('README.rst', 'r', 'utf-8') as fd:
'Topic :: Internet',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
+32 -24
View File
@@ -38,15 +38,16 @@ from .userprofilephotos import UserProfilePhotos
from .keyboardbutton import KeyboardButton
from .replymarkup import ReplyMarkup
from .replykeyboardmarkup import ReplyKeyboardMarkup
from .replykeyboardhide import ReplyKeyboardHide
from .replykeyboardremove import ReplyKeyboardRemove, ReplyKeyboardHide
from .forcereply import ForceReply
from .error import TelegramError
from .inputfile import InputFile
from .file import File
from .nullhandler import NullHandler
from .emoji import Emoji
from .parsemode import ParseMode
from .messageentity import MessageEntity
from .animation import Animation
from .game import Game
from .message import Message
from .inputmessagecontent import InputMessageContent
from .callbackquery import CallbackQuery
@@ -74,34 +75,41 @@ from .inlinequeryresultphoto import InlineQueryResultPhoto
from .inlinequeryresultvenue import InlineQueryResultVenue
from .inlinequeryresultvideo import InlineQueryResultVideo
from .inlinequeryresultvoice import InlineQueryResultVoice
from .inlinequeryresultgame import InlineQueryResultGame
from .inputtextmessagecontent import InputTextMessageContent
from .inputlocationmessagecontent import InputLocationMessageContent
from .inputvenuemessagecontent import InputVenueMessageContent
from .inputcontactmessagecontent import InputContactMessageContent
from .webhookinfo import WebhookInfo
from .gamehighscore import GameHighScore
from .update import Update
from .bot import Bot
from .constants import (MAX_MESSAGE_LENGTH, MAX_CAPTION_LENGTH, SUPPORTED_WEBHOOK_PORTS,
MAX_FILESIZE_DOWNLOAD, MAX_FILESIZE_UPLOAD,
MAX_MESSAGES_PER_SECOND_PER_CHAT, MAX_MESSAGES_PER_SECOND,
MAX_MESSAGES_PER_MINUTE_PER_GROUP)
from .version import __version__ # flake8: noqa
__author__ = 'devs@python-telegram-bot.org'
__version__ = '4.3.2'
__all__ = ['Audio', 'Bot', 'Chat', 'ChatMember', 'ChatAction', 'ChosenInlineResult',
'CallbackQuery', 'Contact', 'Document', 'Emoji', 'File', 'ForceReply',
'InlineKeyboardButton', 'InlineKeyboardMarkup', 'InlineQuery', 'InlineQueryResult',
'InlineQueryResult', 'InlineQueryResultArticle', 'InlineQueryResultAudio',
'InlineQueryResultCachedAudio', 'InlineQueryResultCachedDocument',
'InlineQueryResultCachedGif', 'InlineQueryResultCachedMpeg4Gif',
'InlineQueryResultCachedPhoto', 'InlineQueryResultCachedSticker',
'InlineQueryResultCachedVideo', 'InlineQueryResultCachedVoice',
'InlineQueryResultContact', 'InlineQueryResultDocument', 'InlineQueryResultGif',
'InlineQueryResultLocation', 'InlineQueryResultMpeg4Gif', 'InlineQueryResultPhoto',
'InlineQueryResultVenue', 'InlineQueryResultVideo', 'InlineQueryResultVoice',
'InputContactMessageContent', 'InputFile', 'InputLocationMessageContent',
'InputMessageContent', 'InputTextMessageContent', 'InputVenueMessageContent',
'KeyboardButton', 'Location', 'Message', 'MessageEntity', 'NullHandler', 'ParseMode',
'PhotoSize', 'ReplyKeyboardHide', 'ReplyKeyboardMarkup', 'ReplyMarkup', 'Sticker',
'TelegramError', 'TelegramObject', 'Update', 'User', 'UserProfilePhotos', 'Venue',
'Video', 'Voice']
if version_info < (2, 7):
from warnings import warn
warn("python-telegram-bot will stop supporting Python 2.6 in a future release. "
"Please upgrade your Python version to at least Python 2.7!")
__all__ = [
'Audio', 'Bot', 'Chat', 'ChatMember', 'ChatAction', 'ChosenInlineResult', 'CallbackQuery',
'Contact', 'Document', 'Emoji', 'File', 'ForceReply', 'InlineKeyboardButton',
'InlineKeyboardMarkup', 'InlineQuery', 'InlineQueryResult', 'InlineQueryResult',
'InlineQueryResultArticle', 'InlineQueryResultAudio', 'InlineQueryResultCachedAudio',
'InlineQueryResultCachedDocument', 'InlineQueryResultCachedGif',
'InlineQueryResultCachedMpeg4Gif', 'InlineQueryResultCachedPhoto',
'InlineQueryResultCachedSticker', 'InlineQueryResultCachedVideo',
'InlineQueryResultCachedVoice', 'InlineQueryResultContact', 'InlineQueryResultDocument',
'InlineQueryResultGif', 'InlineQueryResultLocation', 'InlineQueryResultMpeg4Gif',
'InlineQueryResultPhoto', 'InlineQueryResultVenue', 'InlineQueryResultVideo',
'InlineQueryResultVoice', 'InlineQueryResultGame', 'InputContactMessageContent', 'InputFile',
'InputLocationMessageContent', 'InputMessageContent', 'InputTextMessageContent',
'InputVenueMessageContent', 'KeyboardButton', 'Location', 'Message', 'MessageEntity',
'ParseMode', 'PhotoSize', 'ReplyKeyboardRemove', 'ReplyKeyboardMarkup', 'ReplyMarkup',
'Sticker', 'TelegramError', 'TelegramObject', 'Update', 'User', 'UserProfilePhotos', 'Venue',
'Video', 'Voice', 'MAX_MESSAGE_LENGTH', 'MAX_CAPTION_LENGTH', 'SUPPORTED_WEBHOOK_PORTS',
'MAX_FILESIZE_DOWNLOAD', 'MAX_FILESIZE_UPLOAD', 'MAX_MESSAGES_PER_SECOND_PER_CHAT',
'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation',
'Game', 'GameHighScore'
]
+23
View File
@@ -0,0 +1,23 @@
import sys
import urllib3
import certifi
import future
from . import __version__ as telegram_ver
def print_ver_info():
print('python-telegram-bot {0}'.format(telegram_ver))
print('urllib3 {0}'.format(urllib3.__version__))
print('certifi {0}'.format(certifi.__version__))
print('future {0}'.format(future.__version__))
print('Python {0}'.format(sys.version.replace('\n', ' ')))
def main():
print_ver_info()
if __name__ == '__main__':
main()
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2016
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Animation."""
from telegram import PhotoSize
from telegram import TelegramObject
class Animation(TelegramObject):
"""This object represents a Telegram Animation.
Attributes:
file_id (str): Unique file identifier.
Keyword Args:
thumb (Optional[:class:`telegram.PhotoSize`]): Animation thumbnail as defined by sender.
file_name (Optional[str]): Original animation filename as defined by sender.
mime_type (Optional[str]): MIME type of the file as defined by sender.
file_size (Optional[int]): File size.
"""
def __init__(self, file_id, **kwargs):
self.file_id = file_id
self.thumb = kwargs.get('thumb')
self.file_name = kwargs.get('file_name')
self.mime_type = kwargs.get('mime_type')
self.file_size = kwargs.get('file_size')
@staticmethod
def de_json(data, bot):
"""
Args:
data (dict):
bot (telegram.Bot):
Returns:
telegram.Game:
"""
if not data:
return None
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
return Animation(**data)
+18 -11
View File
@@ -16,7 +16,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 Audio."""
"""This module contains an object that represents a Telegram Audio."""
from telegram import TelegramObject
@@ -35,30 +35,37 @@ class Audio(TelegramObject):
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]):
**kwargs: Arbitrary keyword arguments.
"""
def __init__(self, file_id, duration, **kwargs):
def __init__(self,
file_id,
duration,
performer='',
title='',
mime_type='',
file_size=0,
**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))
self.performer = performer
self.title = title
self.mime_type = str(mime_type)
self.file_size = int(file_size)
@staticmethod
def de_json(data):
def de_json(data, bot):
"""
Args:
data (str):
data (dict):
bot (telegram.Bot):
Returns:
telegram.Audio:
+12 -4
View File
@@ -18,7 +18,11 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Base class for Telegram Objects."""
import json
try:
import ujson as json
except ImportError:
import json
from abc import ABCMeta
@@ -34,13 +38,14 @@ class TelegramObject(object):
return self.__dict__[item]
@staticmethod
def de_json(data):
def de_json(data, bot):
"""
Args:
data (str):
data (dict):
bot (telegram.Bot):
Returns:
telegram.TelegramObject:
dict:
"""
if not data:
return None
@@ -64,6 +69,9 @@ class TelegramObject(object):
data = dict()
for key in iter(self.__dict__):
if key == 'bot':
continue
value = self.__dict__[key]
if value is not None:
if hasattr(value, 'to_dict'):
+718 -610
View File
File diff suppressed because it is too large Load Diff
@@ -16,17 +16,10 @@
#
# 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."""
"""This module contains an object that represents a Telegram CallbackGame."""
import logging
from telegram import TelegramObject
class NullHandler(logging.Handler):
"""This object represents a logging NullHandler."""
def emit(self, record):
"""
Args:
record (str):
"""
pass
class CallbackGame(TelegramObject):
"""A placeholder, currently holds no information. Use BotFather to set up your game."""
+84 -10
View File
@@ -16,8 +16,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
CallbackQuery"""
"""This module contains an object that represents a Telegram CallbackQuery"""
from telegram import TelegramObject, Message, User
@@ -25,24 +24,46 @@ from telegram import TelegramObject, Message, User
class CallbackQuery(TelegramObject):
"""This object represents a Telegram CallbackQuery."""
def __init__(self, id, from_user, data, **kwargs):
def __init__(self,
id,
from_user,
chat_instance,
message=None,
data=None,
inline_message_id=None,
game_short_name=None,
bot=None,
**kwargs):
# Required
self.id = id
self.from_user = from_user
self.data = data
self.chat_instance = chat_instance
# Optionals
self.message = kwargs.get('message')
self.inline_message_id = kwargs.get('inline_message_id', '')
self.message = message
self.data = data
self.inline_message_id = inline_message_id
self.game_short_name = game_short_name
self.bot = bot
@staticmethod
def de_json(data):
def de_json(data, bot):
"""
Args:
data (dict):
bot (telegram.Bot):
Returns:
telegram.CallbackQuery:
"""
if not data:
return None
data['from_user'] = User.de_json(data.get('from'))
data['message'] = Message.de_json(data.get('message'))
data['from_user'] = User.de_json(data.get('from'), bot)
data['message'] = Message.de_json(data.get('message'), bot)
return CallbackQuery(**data)
return CallbackQuery(bot=bot, **data)
def to_dict(self):
"""
@@ -54,3 +75,56 @@ class CallbackQuery(TelegramObject):
# Required
data['from'] = data.pop('from_user', None)
return data
def answer(self, *args, **kwargs):
"""Shortcut for ``bot.answerCallbackQuery(update.callback_query.id, *args, **kwargs)``"""
return self.bot.answerCallbackQuery(self.id, *args, **kwargs)
def edit_message_text(self, *args, **kwargs):
"""
Shortcut for either ``bot.editMessageText(chat_id=update.callback_query.message.chat_id, \
message_id=update.callback_query.message.message_id, \
*args, **kwargs)``
or ``bot.editMessageText(inline_message_id=update.callback_query.inline_message_id, \
*args, **kwargs)``
"""
if self.inline_message_id:
return self.bot.edit_message_text(
inline_message_id=self.inline_message_id, *args, **kwargs)
else:
return self.bot.edit_message_text(
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs)
def edit_message_caption(self, *args, **kwargs):
"""
Shortcut for either
``bot.editMessageCaption(chat_id=update.callback_query.message.chat_id, \
message_id=update.callback_query.message.message_id, \
*args, **kwargs)``
or
``bot.editMessageCaption(inline_message_id=update.callback_query.inline_message_id, \
*args, **kwargs)``
"""
if self.inline_message_id:
return self.bot.edit_message_caption(
inline_message_id=self.inline_message_id, *args, **kwargs)
else:
return self.bot.edit_message_caption(
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs)
def edit_message_reply_markup(self, *args, **kwargs):
"""
Shortcut for either
``bot.editMessageReplyMarkup(chat_id=update.callback_query.message.chat_id, \
message_id=update.callback_query.message.message_id, \
*args, **kwargs)``
or
``bot.editMessageReplyMarkup(inline_message_id=update.callback_query.inline_message_id, \
*args, **kwargs)``
"""
if self.inline_message_id:
return self.bot.edit_message_reply_markup(
inline_message_id=self.inline_message_id, *args, **kwargs)
else:
return self.bot.edit_message_reply_markup(
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs)
+56 -12
View File
@@ -17,7 +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 Chat."""
"""This module contains an object that represents a Telegram Chat."""
from telegram import TelegramObject
@@ -32,36 +32,52 @@ class Chat(TelegramObject):
username (str): Username, for private chats and channels if available
first_name (str): First name of the other party in a private chat
last_name (str): Last name of the other party in a private chat
all_members_are_admins (bool): True if a group has 'All Members Are Admins' enabled.
Args:
id (int):
type (str):
**kwargs: Arbitrary keyword arguments.
title (Optional[str]):
username(Optional[str]):
first_name(Optional[str]):
last_name(Optional[str]):
bot (Optional[Bot]): The Bot to use for instance methods
**kwargs (dict): Arbitrary keyword arguments.
Keyword Args:
type (Optional[str]):
"""
PRIVATE = 'private'
GROUP = 'group'
SUPERGROUP = 'supergroup'
CHANNEL = 'channel'
def __init__(self, id, type, **kwargs):
def __init__(self,
id,
type,
title='',
username='',
first_name='',
last_name='',
all_members_are_admins=False,
bot=None,
**kwargs):
# Required
self.id = int(id)
self.type = type
# Optionals
self.title = kwargs.get('title', '')
self.username = kwargs.get('username', '')
self.first_name = kwargs.get('first_name', '')
self.last_name = kwargs.get('last_name', '')
self.title = title
self.username = username
self.first_name = first_name
self.last_name = last_name
self.all_members_are_admins = all_members_are_admins
self.bot = bot
@staticmethod
def de_json(data):
def de_json(data, bot):
"""
Args:
data (dict):
bot (telegram.Bot):
Returns:
telegram.Chat:
@@ -69,4 +85,32 @@ class Chat(TelegramObject):
if not data:
return None
return Chat(**data)
return Chat(bot=bot, **data)
def send_action(self, *args, **kwargs):
"""Shortcut for ``bot.sendChatAction(update.message.chat.id, *args, **kwargs)``"""
return self.bot.sendChatAction(self.id, *args, **kwargs)
def leave(self, *args, **kwargs):
"""Shortcut for ``bot.leaveChat(update.message.chat.id, *args, **kwargs)``"""
return self.bot.leaveChat(self.id, *args, **kwargs)
def get_administrators(self, *args, **kwargs):
"""Shortcut for ``bot.getChatAdministrators(update.message.chat.id, *args, **kwargs)``"""
return self.bot.getChatAdministrators(self.id, *args, **kwargs)
def get_members_count(self, *args, **kwargs):
"""Shortcut for ``bot.getChatMembersCount(update.message.chat.id, *args, **kwargs)``"""
return self.bot.getChatMembersCount(self.id, *args, **kwargs)
def get_member(self, *args, **kwargs):
"""Shortcut for ``bot.getChatMember(update.message.chat.id, *args, **kwargs)``"""
return self.bot.getChatMember(self.id, *args, **kwargs)
def kick_member(self, *args, **kwargs):
"""Shortcut for ``bot.kickChatMember(update.message.chat.id, *args, **kwargs)``"""
return self.bot.kickChatMember(self.id, *args, **kwargs)
def unban_member(self, *args, **kwargs):
"""Shortcut for ``bot.unbanChatMember(update.message.chat.id, *args, **kwargs)``"""
return self.bot.unbanChatMember(self.id, *args, **kwargs)
+1 -1
View File
@@ -17,7 +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 ChatAction."""
"""This module contains an object that represents a Telegram ChatAction."""
class ChatAction(object):
+6 -4
View File
@@ -16,7 +16,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 ChatMember."""
"""This module contains an object that represents a Telegram ChatMember."""
from telegram import User, TelegramObject
@@ -32,8 +32,9 @@ class ChatMember(TelegramObject):
Args:
user (:class:`telegram.User`):
status (str):
"""
**kwargs (dict): Arbitrary keyword arguments.
"""
CREATOR = 'creator'
ADMINISTRATOR = 'administrator'
MEMBER = 'member'
@@ -46,10 +47,11 @@ class ChatMember(TelegramObject):
self.status = status
@staticmethod
def de_json(data):
def de_json(data, bot):
"""
Args:
data (dict):
bot (telegram.Bot):
Returns:
telegram.ChatMember:
@@ -57,6 +59,6 @@ class ChatMember(TelegramObject):
if not data:
return None
data['user'] = User.de_json(data.get('user'))
data['user'] = User.de_json(data.get('user'), bot)
return ChatMember(**data)
+11 -5
View File
@@ -17,7 +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 ChosenInlineResult
This module contains an object that represents a Telegram ChosenInlineResult
"""
from telegram import TelegramObject, User, Location
@@ -33,11 +33,16 @@ class ChosenInlineResult(TelegramObject):
result_id (str):
from_user (:class:`telegram.User`):
query (str):
location (:class:`telegram.Location`):
inline_message_id (str):
Args:
result_id (str):
from_user (:class:`telegram.User`):
query (str):
location (Optional[:class:`telegram.Location`]):
inline_message_id (Optional[str]):
**kwargs (dict): Arbitrary keyword arguments.
"""
@@ -57,10 +62,11 @@ class ChosenInlineResult(TelegramObject):
self.inline_message_id = inline_message_id
@staticmethod
def de_json(data):
def de_json(data, bot):
"""
Args:
data (dict):
bot (telegram.Bot):
Returns:
telegram.ChosenInlineResult:
@@ -68,10 +74,10 @@ class ChosenInlineResult(TelegramObject):
if not data:
return None
# Required
data['from_user'] = User.de_json(data.pop('from'))
# Required
data['from_user'] = User.de_json(data.pop('from'), bot)
# Optionals
data['location'] = Location.de_json(data.get('location'))
data['location'] = Location.de_json(data.get('location'), bot)
return ChosenInlineResult(**data)
+54
View File
@@ -0,0 +1,54 @@
# python-telegram-bot - a Python interface to the Telegram Bot API
# Copyright (C) 2015-2016
# by the python-telegram-bot contributors <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Constants in the Telegram network.
Attributes:
MAX_MESSAGE_LENGTH (int): from
https://core.telegram.org/method/messages.sendMessage#return-errors
MAX_CAPTION_LENGTH (int): from https://core.telegram.org/bots/api#sendphoto
The following constants were extracted from the
`Telegram Bots FAQ <https://core.telegram.org/bots/faq>`_.
Attributes:
SUPPORTED_WEBHOOK_PORTS (List[int])
MAX_FILESIZE_DOWNLOAD (int): In bytes.
MAX_FILESIZE_UPLOAD (int): Official limit, the actual limit can be a bit higher.
MAX_MESSAGES_PER_SECOND_PER_CHAT (int): Telegram may allow short bursts that go over this
limit, but eventually you'll begin receiving 429 errors.
MAX_MESSAGES_PER_SECOND (int)
MAX_MESSAGES_PER_MINUTE_PER_GROUP (int)
The following constant have been found by experimentation:
Attributes:
MAX_MESSAGE_ENTITIES (int): Max number of entities that can be in a message.
(Beyond this cap telegram will simply ignore further formatting styles)
"""
MAX_MESSAGE_LENGTH = 4096
MAX_CAPTION_LENGTH = 200
# constants above this line are tested
SUPPORTED_WEBHOOK_PORTS = [443, 80, 88, 8443]
MAX_FILESIZE_DOWNLOAD = int(20E6) # (20MB)
MAX_FILESIZE_UPLOAD = int(50E6) # (50MB)
MAX_MESSAGES_PER_SECOND_PER_CHAT = 1
MAX_MESSAGES_PER_SECOND = 30
MAX_MESSAGES_PER_MINUTE_PER_GROUP = 20
MAX_MESSAGE_ENTITIES = 100
+9 -9
View File
@@ -16,7 +16,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 Contact."""
"""This module contains an object that represents a Telegram Contact."""
from telegram import TelegramObject
@@ -33,26 +33,26 @@ class Contact(TelegramObject):
Args:
phone_number (str):
first_name (str):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
last_name (Optional[str]):
user_id (Optional[int]):
**kwargs: Arbitrary keyword arguments.
"""
def __init__(self, phone_number, first_name, **kwargs):
def __init__(self, phone_number, first_name, last_name='', user_id=0, **kwargs):
# Required
self.phone_number = str(phone_number)
self.first_name = first_name
# Optionals
self.last_name = kwargs.get('last_name', '')
self.user_id = int(kwargs.get('user_id', 0))
self.last_name = last_name
self.user_id = int(user_id)
@staticmethod
def de_json(data):
def de_json(data, bot):
"""
Args:
data (str):
data (dict):
bot (telegram.Bot):
Returns:
telegram.Contact:
+5 -8
View File
@@ -1,11 +1,10 @@
import logging
from telegram import NullHandler
from future.moves.urllib.parse import quote
from future.moves.urllib.error import HTTPError, URLError
from future.moves.urllib.request import urlopen, Request
logging.getLogger(__name__).addHandler(NullHandler())
logging.getLogger(__name__).addHandler(logging.NullHandler())
class Botan(object):
@@ -29,12 +28,10 @@ class Botan(object):
return False
data = message.to_json()
try:
url = self.url_template.format(token=str(self.token),
uid=str(uid),
name=quote(event_name))
request = Request(url,
data=data.encode(),
headers={'Content-Type': 'application/json'})
url = self.url_template.format(
token=str(self.token), uid=str(uid), name=quote(event_name))
request = Request(
url, data=data.encode(), headers={'Content-Type': 'application/json'})
urlopen(request)
return True
except HTTPError as error:
+12 -12
View File
@@ -16,7 +16,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 Document."""
"""This module contains an object that represents a Telegram Document."""
from telegram import PhotoSize, TelegramObject
@@ -33,29 +33,29 @@ class Document(TelegramObject):
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]):
**kwargs (dict): Arbitrary keyword arguments.
"""
def __init__(self, file_id, **kwargs):
def __init__(self, file_id, thumb=None, file_name='', mime_type='', file_size=0, **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))
self.thumb = thumb
self.file_name = file_name
self.mime_type = str(mime_type)
self.file_size = int(file_size)
@staticmethod
def de_json(data):
def de_json(data, bot):
"""
Args:
data (str):
data (dict):
bot (telegram.Bot):
Returns:
telegram.Document:
@@ -63,6 +63,6 @@ class Document(TelegramObject):
if not data:
return None
data['thumb'] = PhotoSize.de_json(data.get('thumb'))
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
return Document(**data)
+20 -4
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# flake8: noqa
# pylint: disable=C0103,R0903
# pylint: disable=C0103,R0903,E0213
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2016
@@ -18,14 +18,27 @@
#
# 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 an Emoji."""
"""This module contains an object that represents an Emoji.
from future.utils import bytes_to_native_str as n
This module will be removed in the future.
"""
import warnings
from future.utils import bytes_to_native_str
class Emoji(object):
class Emoji2(object):
"""This object represents an Emoji."""
def n(b):
def e(cls):
warnings.warn("telegram.Emoji is being deprecated, please see https://git.io/v6DeB")
return bytes_to_native_str(b)
return property(e)
GRINNING_FACE_WITH_SMILING_EYES = n(b'\xF0\x9F\x98\x81')
FACE_WITH_TEARS_OF_JOY = n(b'\xF0\x9F\x98\x82')
SMILING_FACE_WITH_OPEN_MOUTH = n(b'\xF0\x9F\x98\x83')
@@ -879,3 +892,6 @@ class Emoji(object):
CLOCK_FACE_TEN_THIRTY = n(b'\xF0\x9F\x95\xA5')
CLOCK_FACE_ELEVEN_THIRTY = n(b'\xF0\x9F\x95\xA6')
CLOCK_FACE_TWELVE_THIRTY = n(b'\xF0\x9F\x95\xA7')
Emoji = Emoji2()
+27 -1
View File
@@ -16,7 +16,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 Error."""
"""This module contains an object that represents a Telegram Error."""
def _lstrip_str(in_s, lstr):
@@ -85,3 +85,29 @@ class TimedOut(NetworkError):
def __init__(self):
super(TimedOut, self).__init__('Timed out')
class ChatMigrated(TelegramError):
def __init__(self, new_chat_id):
"""
Args:
new_chat_id (int):
"""
super(ChatMigrated,
self).__init__('Group migrated to supergroup. New chat id: {}'.format(new_chat_id))
self.new_chat_id = new_chat_id
class RetryAfter(TelegramError):
def __init__(self, retry_after):
"""
Args:
retry_after (int):
"""
super(RetryAfter,
self).__init__('Flood control exceeded. Retry in {} seconds'.format(retry_after))
self.retry_after = float(retry_after)
+7 -5
View File
@@ -19,20 +19,22 @@
"""Extensions over the Telegram Bot API to facilitate bot making"""
from .dispatcher import Dispatcher
from .jobqueue import JobQueue
from .jobqueue import JobQueue, Job
from .updater import Updater
from .callbackqueryhandler import CallbackQueryHandler
from .choseninlineresulthandler import ChosenInlineResultHandler
from .commandhandler import CommandHandler
from .handler import Handler
from .inlinequeryhandler import InlineQueryHandler
from .messagehandler import MessageHandler, Filters
from .messagehandler import MessageHandler
from .filters import BaseFilter, Filters
from .regexhandler import RegexHandler
from .stringcommandhandler import StringCommandHandler
from .stringregexhandler import StringRegexHandler
from .typehandler import TypeHandler
from .conversationhandler import ConversationHandler
__all__ = ('Dispatcher', 'JobQueue', 'Updater', 'CallbackQueryHandler',
__all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
'ChosenInlineResultHandler', 'CommandHandler', 'Handler', 'InlineQueryHandler',
'MessageHandler', 'Filters', 'RegexHandler', 'StringCommandHandler',
'StringRegexHandler', 'TypeHandler')
'MessageHandler', 'BaseFilter', 'Filters', 'RegexHandler', 'StringCommandHandler',
'StringRegexHandler', 'TypeHandler', 'ConversationHandler')
+69 -10
View File
@@ -18,34 +18,93 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
""" This module contains the CallbackQueryHandler class """
from .handler import Handler
import re
from future.utils import string_types
from telegram import Update
from telegram.utils.deprecate import deprecate
from .handler import Handler
class CallbackQueryHandler(Handler):
"""
Handler class to handle Telegram callback queries.
Handler class to handle Telegram callback queries. Optionally based on a regex.
Read the documentation of the ``re`` module for more information.
Args:
callback (function): A function that takes ``bot, update`` as
positional arguments. It will be called when the ``check_update``
has determined that an update should be processed by this handler.
pass_update_queue (optional[bool]): If the handler should be passed the
update queue as a keyword argument called ``update_queue``. It can
be used to insert updates. Default is ``False``
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
Default is ``False``.
pattern (optional[str or Pattern]): Optional regex pattern. If not ``None`` ``re.match``
is used to determine if an update should be handled by this handler.
pass_groups (optional[bool]): If the callback should be passed the
result of ``re.match(pattern, data).groups()`` as a keyword
argument called ``groups``. Default is ``False``
pass_groupdict (optional[bool]): If the callback should be passed the
result of ``re.match(pattern, data).groupdict()`` as a keyword
argument called ``groupdict``. Default is ``False``
pass_user_data (optional[bool]): If set to ``True``, a keyword argument called
``user_data`` will be passed to the callback function. It will be a ``dict`` you
can use to keep any data related to the user that sent the update. For each update of
the same user, it will be the same ``dict``. Default is ``False``.
pass_chat_data (optional[bool]): If set to ``True``, a keyword argument called
``chat_data`` will be passed to the callback function. It will be a ``dict`` you
can use to keep any data related to the chat that the update was sent in.
For each update in the same chat, it will be the same ``dict``. Default is ``False``.
"""
def __init__(self, callback, pass_update_queue=False):
super(CallbackQueryHandler, self).__init__(callback, pass_update_queue)
def __init__(self,
callback,
pass_update_queue=False,
pass_job_queue=False,
pattern=None,
pass_groups=False,
pass_groupdict=False,
pass_user_data=False,
pass_chat_data=False):
super(CallbackQueryHandler, self).__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data)
if isinstance(pattern, string_types):
pattern = re.compile(pattern)
self.pattern = pattern
self.pass_groups = pass_groups
self.pass_groupdict = pass_groupdict
def check_update(self, update):
return isinstance(update, Update) and update.callback_query
if isinstance(update, Update) and update.callback_query:
if self.pattern:
if update.callback_query.data:
match = re.match(self.pattern, update.callback_query.data)
return bool(match)
else:
return True
def handle_update(self, update, dispatcher):
optional_args = self.collect_optional_args(dispatcher)
optional_args = self.collect_optional_args(dispatcher, update)
if self.pattern:
match = re.match(self.pattern, update.callback_query.data)
self.callback(dispatcher.bot, update, **optional_args)
if self.pass_groups:
optional_args['groups'] = match.groups()
if self.pass_groupdict:
optional_args['groupdict'] = match.groupdict()
return self.callback(dispatcher.bot, update, **optional_args)
# old non-PEP8 Handler methods
m = "telegram.CallbackQueryHandler."
+30 -7
View File
@@ -32,21 +32,44 @@ class ChosenInlineResultHandler(Handler):
callback (function): A function that takes ``bot, update`` as
positional arguments. It will be called when the ``check_update``
has determined that an update should be processed by this handler.
pass_update_queue (optional[bool]): If the handler should be passed the
update queue as a keyword argument called ``update_queue``. It can
be used to insert updates. Default is ``False``
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
Default is ``False``.
pass_user_data (optional[bool]): If set to ``True``, a keyword argument called
``user_data`` will be passed to the callback function. It will be a ``dict`` you
can use to keep any data related to the user that sent the update. For each update of
the same user, it will be the same ``dict``. Default is ``False``.
pass_chat_data (optional[bool]): If set to ``True``, a keyword argument called
``chat_data`` will be passed to the callback function. It will be a ``dict`` you
can use to keep any data related to the chat that the update was sent in.
For each update in the same chat, it will be the same ``dict``. Default is ``False``.
"""
def __init__(self, callback, pass_update_queue=False):
super(ChosenInlineResultHandler, self).__init__(callback, pass_update_queue)
def __init__(self,
callback,
pass_update_queue=False,
pass_job_queue=False,
pass_user_data=False,
pass_chat_data=False):
super(ChosenInlineResultHandler, self).__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data)
def check_update(self, update):
return isinstance(update, Update) and update.chosen_inline_result
def handle_update(self, update, dispatcher):
optional_args = self.collect_optional_args(dispatcher)
optional_args = self.collect_optional_args(dispatcher, update)
self.callback(dispatcher.bot, update, **optional_args)
return self.callback(dispatcher.bot, update, **optional_args)
# old non-PEP8 Handler methods
m = "telegram.ChosenInlineResultHandler."
+31 -9
View File
@@ -39,10 +39,24 @@ class CommandHandler(Handler):
pass_args (optional[bool]): If the handler should be passed the
arguments passed to the command as a keyword argument called `
``args``. It will contain a list of strings, which is the text
following the command split on spaces. Default is ``False``
pass_update_queue (optional[bool]): If the handler should be passed the
update queue as a keyword argument called ``update_queue``. It can
be used to insert updates. Default is ``False``
following the command split on single or consecutive whitespace characters.
Default is ``False``
pass_update_queue (optional[bool]): If set to ``True``, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the ``Updater`` and ``Dispatcher`` that contains new updates which can
be used to insert updates. Default is ``False``.
pass_job_queue (optional[bool]): If set to ``True``, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a ``JobQueue``
instance created by the ``Updater`` which can be used to schedule new jobs.
Default is ``False``.
pass_user_data (optional[bool]): If set to ``True``, a keyword argument called
``user_data`` will be passed to the callback function. It will be a ``dict`` you
can use to keep any data related to the user that sent the update. For each update of
the same user, it will be the same ``dict``. Default is ``False``.
pass_chat_data (optional[bool]): If set to ``True``, a keyword argument called
``chat_data`` will be passed to the callback function. It will be a ``dict`` you
can use to keep any data related to the chat that the update was sent in.
For each update in the same chat, it will be the same ``dict``. Default is ``False``.
"""
def __init__(self,
@@ -50,8 +64,16 @@ class CommandHandler(Handler):
callback,
allow_edited=False,
pass_args=False,
pass_update_queue=False):
super(CommandHandler, self).__init__(callback, pass_update_queue)
pass_update_queue=False,
pass_job_queue=False,
pass_user_data=False,
pass_chat_data=False):
super(CommandHandler, self).__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data)
self.command = command
self.allow_edited = allow_edited
self.pass_args = pass_args
@@ -68,14 +90,14 @@ class CommandHandler(Handler):
return False
def handle_update(self, update, dispatcher):
optional_args = self.collect_optional_args(dispatcher)
optional_args = self.collect_optional_args(dispatcher, update)
message = update.message or update.edited_message
if self.pass_args:
optional_args['args'] = message.text.split(' ')[1:]
optional_args['args'] = message.text.split()[1:]
self.callback(dispatcher.bot, update, **optional_args)
return self.callback(dispatcher.bot, update, **optional_args)
# old non-PEP8 Handler methods
m = "telegram.CommandHandler."
+204
View File
@@ -0,0 +1,204 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2016
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
""" This module contains the ConversationHandler """
import logging
from telegram import Update
from telegram.ext import Handler
from telegram.utils.helpers import extract_chat_and_user
from telegram.utils.promise import Promise
class ConversationHandler(Handler):
"""
A handler to hold a conversation with a user by managing four collections of other handlers.
The first collection, a ``list`` named ``entry_points``, is used to initiate the conversation,
for example with a ``CommandHandler`` or ``RegexHandler``.
The second collection, a ``dict`` named ``states``, contains the different conversation steps
and one or more associated handlers that should be used if the user sends a message when the
conversation with them is currently in that state. You will probably use mostly
``MessageHandler`` and ``RegexHandler`` here.
The third collection, a ``list`` named ``fallbacks``, is used if the user is currently in a
conversation but the state has either no associated handler or the handler that is associated
to the state is inappropriate for the update, for example if the update contains a command, but
a regular text message is expected. You could use this for a ``/cancel`` command or to let the
user know their message was not recognized.
The fourth, optional collection of handlers, a ``list`` named ``timed_out_behavior`` is used if
the wait for ``run_async`` takes longer than defined in ``run_async_timeout``. For example,
you can let the user know that they should wait for a bit before they can continue.
To change the state of conversation, the callback function of a handler must return the new
state after responding to the user. If it does not return anything (returning ``None`` by
default), the state will not change. To end the conversation, the callback function must
return ``CallbackHandler.END`` or ``-1``.
Args:
entry_points (list): A list of ``Handler`` objects that can trigger the start of the
conversation. The first handler which ``check_update`` method returns ``True`` will be
used. If all return ``False``, the update is not handled.
states (dict): A ``dict[object: list[Handler]]`` that defines the different states of
conversation a user can be in and one or more associated ``Handler`` objects that
should be used in that state. The first handler which ``check_update`` method returns
``True`` will be used.
fallbacks (list): A list of handlers that might be used if the user is in a conversation,
but every handler for their current state returned ``False`` on ``check_update``.
The first handler which ``check_update`` method returns ``True`` will be used. If all
return ``False``, the update is not handled.
allow_reentry (Optional[bool]): If set to ``True``, a user that is currently in a
conversation can restart the conversation by triggering one of the entry points.
run_async_timeout (Optional[float]): If the previous handler for this user was running
asynchronously using the ``run_async`` decorator, it might not be finished when the
next message arrives. This timeout defines how long the conversation handler should
wait for the next state to be computed. The default is ``None`` which means it will
wait indefinitely.
timed_out_behavior (Optional[list]): A list of handlers that might be used if
the wait for ``run_async`` timed out. The first handler which ``check_update`` method
returns ``True`` will be used. If all return ``False``, the update is not handled.
"""
END = -1
def __init__(self,
entry_points,
states,
fallbacks,
allow_reentry=False,
run_async_timeout=None,
timed_out_behavior=None):
self.entry_points = entry_points
""":type: list[telegram.ext.Handler]"""
self.states = states
""":type: dict[str: telegram.ext.Handler]"""
self.fallbacks = fallbacks
""":type: list[telegram.ext.Handler]"""
self.allow_reentry = allow_reentry
self.run_async_timeout = run_async_timeout
self.timed_out_behavior = timed_out_behavior
""":type: list[telegram.ext.Handler]"""
self.conversations = dict()
""":type: dict[(int, int): str]"""
self.current_conversation = None
self.current_handler = None
self.logger = logging.getLogger(__name__)
def check_update(self, update):
if not isinstance(update, Update):
return False
chat, user = extract_chat_and_user(update)
key = (chat.id, user.id) if chat else (None, user.id)
state = self.conversations.get(key)
# Resolve promises
if isinstance(state, tuple) and len(state) is 2 and isinstance(state[1], Promise):
self.logger.debug('waiting for promise...')
old_state, new_state = state
new_state.result(timeout=self.run_async_timeout)
if new_state.done.is_set():
self.update_state(new_state.result(), key)
state = self.conversations.get(key)
else:
for candidate in (self.timed_out_behavior or []):
if candidate.check_update(update):
# Save the current user and the selected handler for handle_update
self.current_conversation = key
self.current_handler = candidate
return True
else:
return False
self.logger.debug('selecting conversation %s with state %s' % (str(key), str(state)))
handler = None
# Search entry points for a match
if state is None or self.allow_reentry:
for entry_point in self.entry_points:
if entry_point.check_update(update):
handler = entry_point
break
else:
if state is None:
return False
# Get the handler list for current state, if we didn't find one yet and we're still here
if state is not None and not handler:
handlers = self.states.get(state)
for candidate in (handlers or []):
if candidate.check_update(update):
handler = candidate
break
# Find a fallback handler if all other handlers fail
else:
for fallback in self.fallbacks:
if fallback.check_update(update):
handler = fallback
break
else:
return False
# Save the current user and the selected handler for handle_update
self.current_conversation = key
self.current_handler = handler
return True
def handle_update(self, update, dispatcher):
new_state = self.current_handler.handle_update(update, dispatcher)
self.update_state(new_state, self.current_conversation)
def update_state(self, new_state, key):
if new_state == self.END:
if key in self.conversations:
del self.conversations[key]
else:
pass
elif isinstance(new_state, Promise):
self.conversations[key] = (self.conversations.get(key), new_state)
elif new_state is not None:
self.conversations[key] = new_state
+133 -54
View File
@@ -19,68 +19,44 @@
"""This module contains the Dispatcher class."""
import logging
import weakref
from functools import wraps
from threading import Thread, Lock, Event, current_thread
from threading import Thread, Lock, Event, current_thread, BoundedSemaphore
from time import sleep
from uuid import uuid4
from collections import defaultdict
from queue import Queue, Empty
from future.builtins import range
from telegram import (TelegramError, NullHandler)
from telegram.utils import request
from telegram import TelegramError
from telegram.ext.handler import Handler
from telegram.utils.deprecate import deprecate
from telegram.utils.promise import Promise
logging.getLogger(__name__).addHandler(NullHandler())
ASYNC_QUEUE = Queue()
ASYNC_THREADS = set()
logging.getLogger(__name__).addHandler(logging.NullHandler())
""":type: set[Thread]"""
ASYNC_LOCK = Lock() # guards ASYNC_THREADS
DEFAULT_GROUP = 0
def _pooled():
"""
A wrapper to run a thread in a thread pool
"""
while 1:
try:
func, args, kwargs = ASYNC_QUEUE.get()
# If unpacking fails, the thread pool is being closed from Updater._join_async_threads
except TypeError:
logging.getLogger(__name__).debug("Closing run_async thread %s/%d" %
(current_thread().getName(), len(ASYNC_THREADS)))
break
try:
func(*args, **kwargs)
except:
logging.getLogger(__name__).exception("run_async function raised exception")
def run_async(func):
"""
Function decorator that will run the function in a new thread.
"""Function decorator that will run the function in a new thread.
Using this decorator is only possible when only a single Dispatcher exist in the system.
Args:
func (function): The function to run in the thread.
async_queue (Queue): The queue of the functions to be executed asynchronously.
Returns:
function:
"""
# TODO: handle exception in async threads
# set a threading.Event to notify caller thread
"""
@wraps(func)
def async_func(*args, **kwargs):
"""
A wrapper to run a function in a thread
"""
ASYNC_QUEUE.put((func, args, kwargs))
return Dispatcher.get_instance().run_async(func, *args, **kwargs)
return async_func
@@ -94,11 +70,27 @@ class Dispatcher(object):
handlers
update_queue (Queue): The synchronized queue that will contain the
updates.
"""
job_queue (Optional[telegram.ext.JobQueue]): The ``JobQueue`` instance to pass onto handler
callbacks
workers (Optional[int]): Number of maximum concurrent worker threads for the ``@run_async``
decorator
def __init__(self, bot, update_queue, workers=4, exception_event=None):
"""
__singleton_lock = Lock()
__singleton_semaphore = BoundedSemaphore()
__singleton = None
logger = logging.getLogger(__name__)
def __init__(self, bot, update_queue, workers=4, exception_event=None, job_queue=None):
self.bot = bot
self.update_queue = update_queue
self.job_queue = job_queue
self.workers = workers
self.user_data = defaultdict(dict)
""":type: dict[int, dict]"""
self.chat_data = defaultdict(dict)
""":type: dict[int, dict]"""
self.handlers = {}
""":type: dict[int, list[Handler]"""
@@ -106,23 +98,90 @@ class Dispatcher(object):
""":type: list[int]"""
self.error_handlers = []
self.logger = logging.getLogger(__name__)
self.running = False
self.__stop_event = Event()
self.__exception_event = exception_event or Event()
self.__async_queue = Queue()
self.__async_threads = set()
with ASYNC_LOCK:
if not ASYNC_THREADS:
if request.is_con_pool_initialized():
raise RuntimeError('Connection Pool already initialized')
request.CON_POOL_SIZE = workers + 3
for i in range(workers):
thread = Thread(target=_pooled, name=str(i))
ASYNC_THREADS.add(thread)
thread.start()
# For backward compatibility, we allow a "singleton" mode for the dispatcher. When there's
# only one instance of Dispatcher, it will be possible to use the `run_async` decorator.
with self.__singleton_lock:
if self.__singleton_semaphore.acquire(blocking=0):
self._set_singleton(self)
else:
self.logger.debug('Thread pool already initialized, skipping.')
self._set_singleton(None)
@classmethod
def _reset_singleton(cls):
# NOTE: This method was added mainly for test_updater benefit and specifically pypy. Never
# call it in production code.
cls.__singleton_semaphore.release()
def _init_async_threads(self, base_name, workers):
base_name = '{}_'.format(base_name) if base_name else ''
for i in range(workers):
thread = Thread(target=self._pooled, name='{}{}'.format(base_name, i))
self.__async_threads.add(thread)
thread.start()
@classmethod
def _set_singleton(cls, val):
cls.logger.debug('Setting singleton dispatcher as %s', val)
cls.__singleton = weakref.ref(val) if val else None
@classmethod
def get_instance(cls):
"""Get the singleton instance of this class.
Returns:
Dispatcher
"""
if cls.__singleton is not None:
return cls.__singleton()
else:
raise RuntimeError('{} not initialized or multiple instances exist'.format(
cls.__name__))
def _pooled(self):
"""
A wrapper to run a thread in a thread pool
"""
thr_name = current_thread().getName()
while 1:
promise = self.__async_queue.get()
# If unpacking fails, the thread pool is being closed from Updater._join_async_threads
if not isinstance(promise, Promise):
self.logger.debug("Closing run_async thread %s/%d", thr_name,
len(self.__async_threads))
break
try:
promise.run()
except:
self.logger.exception("run_async function raised exception")
def run_async(self, func, *args, **kwargs):
"""Queue a function (with given args/kwargs) to be run asynchronously.
Args:
func (function): The function to run in the thread.
args (Optional[tuple]): Arguments to `func`.
kwargs (Optional[dict]): Keyword arguments to `func`.
Returns:
Promise
"""
# TODO: handle exception in async threads
# set a threading.Event to notify caller thread
promise = Promise(func, args, kwargs)
self.__async_queue.put(promise)
return promise
def start(self):
"""
@@ -139,6 +198,7 @@ class Dispatcher(object):
self.logger.error(msg)
raise TelegramError(msg)
self._init_async_threads(uuid4(), self.workers)
self.running = True
self.logger.debug('Dispatcher started')
@@ -171,6 +231,25 @@ class Dispatcher(object):
sleep(0.1)
self.__stop_event.clear()
# async threads must be join()ed only after the dispatcher thread was joined,
# otherwise we can still have new async threads dispatched
threads = list(self.__async_threads)
total = len(threads)
# Stop all threads in the thread pool by put()ting one non-tuple per thread
for i in range(total):
self.__async_queue.put(None)
for i, thr in enumerate(threads):
self.logger.debug('Waiting for async thread {0}/{1} to end'.format(i + 1, total))
thr.join()
self.__async_threads.remove(thr)
self.logger.debug('async thread {0}/{1} has ended'.format(i + 1, total))
@property
def has_running_threads(self):
return self.running or bool(self.__async_threads)
def process_update(self, update):
"""
Processes a single update.
@@ -230,7 +309,7 @@ class Dispatcher(object):
which handlers were added to the group defines the priority.
Args:
handler (Handler): A Handler instance
handler (telegram.ext.Handler): A Handler instance
group (Optional[int]): The group identifier. Default is 0
"""
@@ -251,7 +330,7 @@ class Dispatcher(object):
Remove a handler from the specified group
Args:
handler (Handler): A Handler instance
handler (telegram.ext.Handler): A Handler instance
group (optional[object]): The group identifier. Default is 0
"""
if handler in self.handlers[group]:
+223
View File
@@ -0,0 +1,223 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2016
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
""" This module contains the Filters for use with the MessageHandler class """
class BaseFilter(object):
"""Base class for all Message Filters
Subclassing from this class filters to be combined using bitwise operators:
And:
>>> (Filters.text & Filters.entity(MENTION))
Or:
>>> (Filters.audio | Filters.video)
Also works with more than two filters:
>>> (Filters.text & (Filters.entity(URL) | Filters.entity(TEXT_LINK)))
If you want to create your own filters create a class inheriting from this class and implement
a `filter` method that returns a boolean: `True` if the message should be handled, `False`
otherwise. Note that the filters work only as class instances, not actual class objects
(so remember to initialize your filter classes).
"""
def __call__(self, message):
return self.filter(message)
def __and__(self, other):
return MergedFilter(self, and_filter=other)
def __or__(self, other):
return MergedFilter(self, or_filter=other)
def filter(self, message):
raise NotImplementedError
class MergedFilter(BaseFilter):
"""Represents a filter consisting of two other filters.
Args:
base_filter: Filter 1 of the merged filter
and_filter: Optional filter to "and" with base_filter. Mutually exclusive with or_filter.
or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter.
"""
def __init__(self, base_filter, and_filter=None, or_filter=None):
self.base_filter = base_filter
self.and_filter = and_filter
self.or_filter = or_filter
def filter(self, message):
if self.and_filter:
return self.base_filter(message) and self.and_filter(message)
elif self.or_filter:
return self.base_filter(message) or self.or_filter(message)
def __str__(self):
return ("<telegram.ext.filters.MergedFilter consisting of"
" {} {} {}>").format(self.base_filter, "and" if self.and_filter else "or",
self.and_filter or self.or_filter)
__repr__ = __str__
class Filters(object):
"""
Predefined filters for use with the `filter` argument of :class:`telegram.ext.MessageHandler`.
"""
class _All(BaseFilter):
def filter(self, message):
return True
all = _All()
class _Text(BaseFilter):
def filter(self, message):
return bool(message.text and not message.text.startswith('/'))
text = _Text()
class _Command(BaseFilter):
def filter(self, message):
return bool(message.text and message.text.startswith('/'))
class _Reply(BaseFilter):
def filter(self, message):
return bool(message.reply_to_message)
reply = _Reply()
command = _Command()
class _Audio(BaseFilter):
def filter(self, message):
return bool(message.audio)
audio = _Audio()
class _Document(BaseFilter):
def filter(self, message):
return bool(message.document)
document = _Document()
class _Photo(BaseFilter):
def filter(self, message):
return bool(message.photo)
photo = _Photo()
class _Sticker(BaseFilter):
def filter(self, message):
return bool(message.sticker)
sticker = _Sticker()
class _Video(BaseFilter):
def filter(self, message):
return bool(message.video)
video = _Video()
class _Voice(BaseFilter):
def filter(self, message):
return bool(message.voice)
voice = _Voice()
class _Contact(BaseFilter):
def filter(self, message):
return bool(message.contact)
contact = _Contact()
class _Location(BaseFilter):
def filter(self, message):
return bool(message.location)
location = _Location()
class _Venue(BaseFilter):
def filter(self, message):
return bool(message.venue)
venue = _Venue()
class _StatusUpdate(BaseFilter):
def filter(self, message):
return bool(message.new_chat_member or message.left_chat_member
or message.new_chat_title or message.new_chat_photo
or message.delete_chat_photo or message.group_chat_created
or message.supergroup_chat_created or message.channel_chat_created
or message.migrate_to_chat_id or message.migrate_from_chat_id
or message.pinned_message)
status_update = _StatusUpdate()
class _Forwarded(BaseFilter):
def filter(self, message):
return bool(message.forward_date)
forwarded = _Forwarded()
class _Game(BaseFilter):
def filter(self, message):
return bool(message.game)
game = _Game()
class entity(BaseFilter):
"""Filters messages to only allow those which have a :class:`telegram.MessageEntity`
where their `type` matches `entity_type`.
Args:
entity_type: Entity type to check for. All types can be found as constants
in :class:`telegram.MessageEntity`.
Returns: function to use as filter
"""
def __init__(self, entity_type):
self.entity_type = entity_type
def filter(self, message):
return any([entity.type == self.entity_type for entity in message.entities])

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