Compare commits

...

136 Commits

Author SHA1 Message Date
Bibo-Joshi 9323caf2b8 Bump Version to v21.11 (#4694) 2025-03-01 12:03:34 +01:00
Bibo-Joshi 77c25931a9 Stabilize Linkcheck Test (#4693) 2025-03-01 11:31:41 +01:00
Poolitzer b75948ede4 Full Support for Bot API 8.3 (#4676)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Abdelrahman Elkheir <90580077+aelkheir@users.noreply.github.com>
2025-03-01 11:13:46 +01:00
Bibo-Joshi b0d22acedb Add Bootstrapping Logic to Application.run_* (#4673) 2025-03-01 11:12:59 +01:00
Bibo-Joshi 35a48f82f4 Documentation Improvements (#4641)
Co-authored-by: Poolitzer <github@poolitzer.eu>
2025-02-27 20:18:15 +01:00
Bibo-Joshi 5d73132838 Make provider_token Argument Optional (#4689) 2025-02-26 20:57:57 +01:00
Bibo-Joshi 7c23087d08 Remove Deprecated InlineQueryResultArticle.hide_url (#4640) 2025-02-17 17:49:31 +01:00
vavasik800 2d5f4a68bb Fix a Bug in edit_user_star_subscription (#4681) 2025-02-15 16:21:33 +01:00
Bibo-Joshi f9f1533c40 Refactor Tests for TelegramObject Classes with Subclasses (#4654) 2025-02-06 12:46:33 +01:00
Bibo-Joshi dfb0ae3747 Use Fine Grained Permissions for GitHub Actions Workflows (#4668) 2025-02-02 10:24:46 +01:00
dependabot[bot] 64006aa7ae Bump actions/setup-python from 5.3.0 to 5.4.0 (#4665)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2025-02-02 09:52:35 +01:00
dependabot[bot] 69ddc47a6e Bump dependabot/fetch-metadata from 2.2.0 to 2.3.0 (#4666)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-02 09:34:10 +01:00
Bibo-Joshi a2150b3751 Accept datetime.timedelta Input in Bot Method Parameters (#4651) 2025-02-02 09:31:18 +01:00
dependabot[bot] 79acc1ae53 Bump actions/stale from 9.0.0 to 9.1.0 (#4667)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-02 09:22:47 +01:00
dependabot[bot] 4cdb1a0cf7 Bump astral-sh/setup-uv from 5.1.0 to 5.2.2 (#4664)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-02 09:09:55 +01:00
dependabot[bot] 6319f4bae1 Bump codecov/test-results-action from 1.0.1 to 1.0.2 (#4663)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-02 09:09:13 +01:00
Harshil d7e063dbad Overhaul Admonition Insertion in Documentation (#4462)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2025-01-31 19:23:09 +01:00
Bibo-Joshi 5dd7b8f1e2 Extend Customization Support for Bot.base_(file_)url (#4632) 2025-01-23 06:01:27 +01:00
Bibo-Joshi 61b87ba318 Support allow_paid_broadcast in AIORateLimiter (#4627) 2025-01-23 05:59:39 +01:00
Bibo-Joshi dd592cdd7c Simplify Handling of Empty Data in TelegramObject.de_json and Friends (#4617) 2025-01-14 17:12:55 +01:00
Bibo-Joshi f57dd52100 Add BaseUpdateProcessor.current_concurrent_updates (#4626) 2025-01-14 17:00:20 +01:00
pre-commit-ci[bot] 16605c54d7 Bump pre-commit Hooks to Latest Versions (#4643)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2025-01-07 18:11:35 +01:00
Bibo-Joshi e4b0f8cb64 Bump Version to v21.10 (#4639) 2025-01-03 12:11:53 +01:00
Poolitzer f2dc0175cd Full Support for Bot API 8.2 (#4633)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2025-01-03 11:39:35 +01:00
Bibo-Joshi a781a4fddb Add Parameter pattern to JobQueue.jobs() (#4613) 2025-01-02 10:03:39 +01:00
Bibo-Joshi 679d038979 Ensure Forward Compatibility of Gift and Gifts (#4634) 2025-01-02 09:17:01 +01:00
dependabot[bot] d0a6e5141c Bump APS & Deprecate pytz Support (#4582)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2025-01-01 19:43:52 +01:00
Bibo-Joshi 5f35304e63 Update Copyright to 2025 (#4631) 2025-01-01 14:51:12 +01:00
Poolitzer 3fc50c78eb Remove Redundant pylint Suppressions (#4628) 2024-12-31 15:13:31 +01:00
dependabot[bot] 3c9bba63eb Bump astral-sh/setup-uv from 4.2.0 to 5.1.0 (#4625)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-31 11:47:39 +01:00
dependabot[bot] a9a7b07b10 Bump codecov/codecov-action from 5.1.1 to 5.1.2 (#4622)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-31 11:41:56 +01:00
dependabot[bot] e1e7b621f1 Bump actions/upload-artifact from 4.4.3 to 4.5.0 (#4623)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-30 23:03:03 +01:00
dependabot[bot] dfb3c13d1d Bump github/codeql-action from 3.27.9 to 3.28.0 (#4624)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-30 23:02:43 +01:00
Bibo-Joshi f7a3f67a9f Use Custom Labels for dependabot PRs (#4621) 2024-12-30 22:50:23 +01:00
Bibo-Joshi a6cd9c5292 Allow Input of Type Sticker for Several Methods (#4616) 2024-12-29 20:16:46 +01:00
Bibo-Joshi df20e49db1 Refactor Module Structure and Tests for Star Payments Classes (#4615) 2024-12-29 17:58:37 +01:00
Juan Andrés Cuevas 4f255b6e21 Unify datetime Imports (#4605)
Co-authored-by: Miguel Salomon <128310363+Migueldsc12@users.noreply.github.com>
Co-authored-by: Jeamhowards Montiel <106713677+Jeam-zx@users.noreply.github.com>
Co-authored-by: Snehashish Biswas <coderrx06@gmail.com>
Co-authored-by: Luis Pérez <luis.i.perez.0@gmail.com>
Co-authored-by: henryg311 <55552582+henryg311@users.noreply.github.com>
Co-authored-by: AnyaMarcanito <129221958+AnyaMarcanito@users.noreply.github.com>
Co-authored-by: Jeam Montiel <19-10234@usb.ve>
2024-12-15 10:26:37 +01:00
Bibo-Joshi 4afe174b5c Add Static Security Analysis of GitHub Actions Workflows (#4606) 2024-12-13 22:16:31 +01:00
Bibo-Joshi 2ac52018c2 Bump Version to v21.9 (#4601) 2024-12-07 13:39:41 +01:00
dependabot[bot] ca7a30963d Update aiolimiter requirement from ~=1.1.0 to >=1.1,<1.3 (#4595)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-12-07 11:31:52 +01:00
dependabot[bot] c42a230b96 Bump pytest from 8.3.3 to 8.3.4 (#4596)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-12-07 11:15:53 +01:00
Luis Pérez ce9742a602 Use MessageLimit.DEEP_LINK_LENGTH in helpers.create_deep_linked_url (#4597) 2024-12-07 10:25:13 +01:00
Bibo-Joshi 43279543a3 Full Support for Bot API 8.1 (#4594) 2024-12-07 10:20:08 +01:00
Luis Pérez eda2172617 Allow Sequence Input for allowed_updates in Application and Updater Methods (#4589) 2024-12-04 21:20:12 +01:00
dependabot[bot] 89dfa37dbf Bump codecov/codecov-action from 4 to 5 (#4585)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-04 21:04:47 +01:00
Luis Pérez 3709c2fa93 Bump pylint to v3.3.2 to Improve Python 3.13 Support (#4590) 2024-12-04 20:54:03 +01:00
dependabot[bot] da93fe94ae Bump srvaroa/labeler from 1.11.1 to 1.12.0 (#4586)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 06:17:52 +01:00
Bibo-Joshi cec34e4bca Bump Version to v21.8 (#4583) 2024-12-01 12:19:55 +01:00
Bibo-Joshi ffe23be992 Documentation Improvements (#4573, #4565)
Co-authored-by: Snehashish Biswas <coderrx06@gmail.com>
Co-authored-by: poolitzer <github@poolitzer.eu>
2024-12-01 11:47:38 +01:00
Bibo-Joshi ef1685c436 Full Support for Bot API 8.0 (#4566, #4568, #4570, #4571, #4574, #4576, #4572) 2024-12-01 10:26:48 +01:00
Bibo-Joshi 151123745e Bump Version to v21.7 (#4557) 2024-11-04 21:29:59 +01:00
Bibo-Joshi 0eb11ff3e9 Documentation Improvements (#4536, #4556)
Co-authored-by: Abubakar Alaya <ecode5814@gmail.com>
2024-11-04 20:38:41 +01:00
Bibo-Joshi dab75fb963 Add Message.reply_paid_media (#4551) 2024-11-04 20:33:56 +01:00
Bibo-Joshi 62f89758d7 Bot API 7.11 (#4546) 2024-11-04 20:11:10 +01:00
Bibo-Joshi 7a8f4412b2 Update Issue Templates to Use Issue Types (#4553) 2024-11-04 19:08:04 +01:00
Bibo-Joshi 032a859149 Update Automation to Label Changes (#4552) 2024-11-03 21:43:40 +01:00
Bibo-Joshi 507d6bc0e3 Improve Exception Handling in File.download_* (#4542) 2024-11-03 16:35:16 +01:00
dependabot[bot] bd6a60bb30 Bump srvaroa/labeler from 1.11.0 to 1.11.1 (#4549)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-02 18:04:50 +01:00
Bibo-Joshi 3c8f6ed42b Fix Linkcheck Workflow (#4545) 2024-11-01 22:17:14 +01:00
Bibo-Joshi 6540f288f5 Use sphinx-build-compatibility to Keep Sphinx Compatibility (#4492) 2024-10-31 08:27:58 +01:00
Pablo Martínez 5ab82a9c2b Drop Support for Python 3.8 (#4398)
Co-authored-by: poolitzer <github@poolitzer.eu>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2024-10-24 20:48:49 +02:00
Bibo-Joshi 847b97f86e Use Stable Python 3.13 Release in Test Suite (#4535) 2024-10-24 20:03:16 +02:00
Siloé Garcez efacc3dd1b Allow Sequence in Application.add_handlers (#4531) 2024-10-23 22:14:03 +02:00
dependabot[bot] 2ce687c8f1 Bump sphinx from 8.0.2 to 8.1.3 (#4532)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <dependabot[bot]@users.noreply.github.com>
2024-10-21 19:40:12 +02:00
dependabot[bot] a39a59ee9b Bump sphinxcontrib-mermaid from 0.9.2 to 1.0.0 (#4529)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 19:12:44 +02:00
dependabot[bot] 06854633ab Bump srvaroa/labeler from 1.10.1 to 1.11.0 (#4509)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-10-02 03:00:45 +02:00
dependabot[bot] 9a8b208ef7 Bump Bibo-Joshi/pyright-type-completeness from 1.0.0 to 1.0.1 (#4510)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 02:57:34 +02:00
Bibo-Joshi 2f06902518 Improve Test Instability Caused by Message Fixtures (#4507) 2024-10-01 07:16:29 +02:00
Bibo-Joshi 2bc65560eb Stabilize Some Flaky Tests (#4500) 2024-09-25 18:53:26 +02:00
Bibo-Joshi 79e589b39e Reduce Creation of HTTP Clients in Tests (#4493) 2024-09-25 17:17:55 +02:00
Bibo-Joshi bd3cdbcdbd Update pytest-xdist Usage (#4491) 2024-09-22 19:49:48 +02:00
Bibo-Joshi 9709c03b35 Fix Failing Tests by Making Them Independent (#4494) 2024-09-21 18:49:33 +02:00
Bibo-Joshi 3409f51107 Introduce Codecov's Test Analysis (#4487) 2024-09-21 17:15:22 +02:00
Bibo-Joshi 2eae2830f3 Maintenance Work on Bot Tests (#4489)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2024-09-21 11:34:25 +02:00
Bibo-Joshi 28d19c3b9a Introduce conftest.py for File Related Tests (#4488)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2024-09-21 11:33:52 +02:00
Bibo-Joshi e314e78d06 Bump Version to v21.6 (#4486) 2024-09-19 20:17:08 +02:00
Harshil 67a97ae5a7 API 7.10 (#4461, #4460, #4463, #4464)
Co-authored-by: aelkheir <90580077+aelkheir@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-09-17 18:09:19 +02:00
dependabot[bot] 9248c539d0 Bump pytest from 8.3.2 to 8.3.3 (#4475)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-14 08:17:31 +02:00
Bibo-Joshi 6b5e46cc08 Improve Type Completeness (#4466) 2024-09-14 08:16:39 +02:00
Harshil b3155b2e55 Update Python 3.13 Test Suite to RC2 (#4471) 2024-09-13 19:32:22 +02:00
Bibo-Joshi ec909e62cf Enforce the offline_bot Fixture in Test*WithoutRequest (#4465) 2024-09-13 19:10:09 +02:00
Bibo-Joshi 1223e851c3 Add Parameter httpx_kwargs to HTTPXRequest (#4451) 2024-09-11 22:34:18 +02:00
Bibo-Joshi 0b352b043e Make Tests for telegram.ext Independent of Networking (#4454) 2024-09-09 07:32:32 +02:00
Bibo-Joshi b9d2efdec5 Rename Testing Base Classes (#4453) 2024-09-03 05:24:25 +02:00
Bibo-Joshi 8c692d1008 Bump Version to v21.5 (#4449) 2024-09-01 15:25:34 +02:00
Bibo-Joshi 970d2ab085 Documentation Improvements (#4400, #4448)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Palaptin <100526200+Palaptin@users.noreply.github.com>
2024-09-01 14:12:41 +02:00
dependabot[bot] 60b439ff42 Update cachetools requirement from <5.5.0,>=5.3.3 to >=5.3.3,<5.6.0 (#4437)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-09-01 10:35:11 +02:00
Bibo-Joshi b17b0d248d Improve PyPI Automation (#4375) 2024-09-01 09:34:20 +02:00
Bibo-Joshi e0f36867cc Add MessageEntity.shift_entities and MessageEntity.concatenate (#4376) 2024-09-01 09:33:12 +02:00
Poolitzer 01f689373c Bot API 7.9 (#4429)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2024-09-01 09:32:42 +02:00
Bibo-Joshi 1e05381133 Update Test Suite to New Test Channel Setup (#4435) 2024-08-26 20:16:35 +02:00
Martin Hjelmare a05362c79a Remove Surplus Logging from Updater Network Loop (#4432) 2024-08-19 16:40:28 +02:00
Palaptin fbf07bf126 Improve Fixture Usage in test_message.py (#4431) 2024-08-19 16:14:01 +02:00
Harshil 3017bf00a4 Update Python 3.13 Test Suite to RC1 (#4415) 2024-08-13 17:58:08 +02:00
dependabot[bot] 374875c786 Bump sphinx from 7.4.7 to 8.0.2 and furo from 2024.7.18 to 2024.8.6 (#4412)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2024-08-13 17:57:26 +02:00
Harshil 8f9db63f4f Bump ruff and Add New Rules (#4416)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-08-07 21:56:46 +02:00
Harshil 1787586902 Bugfix for "Available In" Admonitions (#4413) 2024-08-03 22:47:38 +02:00
dependabot[bot] 9c50a38512 Bump test-summary/action from 2.3 to 2.4 (#4410)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2024-08-03 17:27:39 +02:00
Bibo-Joshi 3a49372591 Add Parameter read_file_handle to InputFile (#4388) 2024-08-02 22:28:38 +02:00
dependabot[bot] e637d1733c Bump pytest from 8.2.2 to 8.3.2 (#4403)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-02 14:01:31 +02:00
dependabot[bot] b89f5d6126 Bump dependabot/fetch-metadata from 2.1.0 to 2.2.0 (#4411)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2024-08-02 14:00:26 +02:00
Bibo-Joshi 6578c76068 API 7.8 (#4408) 2024-08-02 13:43:27 +02:00
Bibo-Joshi a967dbe37a Document Return Types of RequestData Members (#4396) 2024-08-02 13:41:39 +02:00
dependabot[bot] af76a8485f Update cachetools requirement from ~=5.3.3 to >=5.3.3,<5.5.0 (#4390)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-07-24 21:03:54 +02:00
MOHD YUSUF 8a205b10c0 Add Introductory Paragraphs to Telegram Types Subsections (#4389)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2024-07-24 21:02:53 +02:00
dependabot[bot] 6d70c56159 Bump sphinx from 7.3.7 to 7.4.7 (#4395)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-21 21:23:21 +02:00
Pablo Martínez 0913b859d7 Add Internal Constants for Encodings (#4378) 2024-07-21 21:13:30 +02:00
Bibo-Joshi c3f17bb18e Start Adapting to RTD Addons (#4386) 2024-07-21 21:12:30 +02:00
dependabot[bot] 006a290b7b Bump furo from 2024.5.6 to 2024.7.18 (#4392)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-21 21:05:01 +02:00
Jãїиãм 422993b8ab Add Parameter game_pattern to CallbackQueryHandler (#4353) 2024-07-13 21:26:44 +02:00
Bibo-Joshi 2ac4e009d0 Bump version to v21.4 (#4371) 2024-07-12 17:40:42 +02:00
Bibo-Joshi efe1392e73 Automate PyPI Releases (#4364) 2024-07-12 16:44:41 +02:00
Bibo-Joshi 0a673e8f7e Documentation Improvements (#4303)
Co-authored-by: poolitzer <github@poolitzer.eu>
2024-07-12 16:33:42 +02:00
Bibo-Joshi 86c8cae40d Restructure Readme (#4362) 2024-07-10 20:36:47 +02:00
Bibo-Joshi f737702544 Use a Composite Action for Testing Type Completeness (#4367) 2024-07-10 17:33:04 +02:00
Bibo-Joshi 06f1da576e Stabilize Some Concurrency Usages in Test Suite (#4360) 2024-07-10 17:11:22 +02:00
Bibo-Joshi 7a470d57c8 Add a Test Case for MenuButton (#4363) 2024-07-10 17:10:33 +02:00
Poolitzer 1714bfd8f6 Deprecate Inclusion of successful_payment in Message.effective_attachment (#4365) 2024-07-09 23:33:57 +02:00
Poolitzer 71e4015e22 API 7.7 (#4356)
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-07-09 10:35:18 +02:00
Harshil 52237cf00c Add filters.PAID_MEDIA (#4357) 2024-07-07 22:23:31 +02:00
Harshil dba7866aab API 7.6 (#4333, #4341, #4342, #4334, #4335, #4344, #4348, #4351)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-07-07 13:08:52 +02:00
Bibo-Joshi 98bed6f01a Log Received Data on Deserialization Errors (#4304) 2024-07-06 16:09:04 +02:00
Antares 42d7c8c477 Add MessageEntity.adjust_message_entities_to_utf_16 Utility Function (#4323)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
2024-07-06 16:08:29 +02:00
Poolitzer 8018e5ff3f Extend SuccessfulPayment Test (#4349) 2024-07-05 23:03:54 +02:00
Harshil c39839b026 Small Fixes for test_stars.py (#4347) 2024-07-05 18:44:41 +02:00
Harshil 4213c12c5b Use Python 3.13 Beta 3 in Test Suite (#4336)
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2024-07-03 19:04:45 +02:00
pre-commit-ci[bot] 97226b1ae3 Bump pre-commit Hooks to Latest Versions (#4337)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
2024-07-03 18:29:09 +02:00
Harshil 146ec54a00 API 7.5 (#4312, #4311, #4315, #4328, #4316)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-07-01 21:45:37 +02:00
Bibo-Joshi df8aae0a38 Fix Link-Check Workflow (#4332) 2024-07-01 20:43:54 +02:00
Bibo-Joshi 4ccc80f9c1 Make Argument bot of TelegramObject.de_json Optional (#4320) 2024-07-01 19:59:54 +02:00
Harshil cfc75bb08b Bump ruff and Add New Rules (#4329) 2024-06-30 18:22:12 +02:00
Palaptin 51ef571a07 Add Lower Bound for flaky Dependency (#4322) 2024-06-23 20:15:37 +02:00
Harshil 9ce0f49882 Add Support for Python 3.13 Beta (#4253)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-06-18 22:25:02 +02:00
dependabot[bot] 5b1e7399a4 Bump pytest from 8.2.1 to 8.2.2 (#4294)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
2024-06-18 22:20:47 +02:00
Harshil a83046e1ec Add mise-en-place to .gitignore (#4300) 2024-06-17 19:32:47 +02:00
Bibo-Joshi 44e8292838 Drop python-telegram-bot-raw And Switch to pyproject.toml Based Packaging (#4288) 2024-06-15 10:29:19 +02:00
520 changed files with 19269 additions and 8007 deletions
+4 -9
View File
@@ -26,7 +26,7 @@ Setting things up
.. code-block:: bash
$ pip install -r requirements-all.txt
$ pip install -r requirements-dev-all.txt
5. Install pre-commit hooks:
@@ -194,7 +194,7 @@ Feel free to copy (parts of) the checklist to the PR description to remind you o
- Added or updated documentation for the changed class(es) and/or method(s)
- Added the new method(s) to ``_extbot.py``
- Added or updated ``bot_methods.rst``
- Updated the Bot API version number in all places: ``README.rst`` and ``README_RAW.rst`` (including the badge), as well as ``telegram.constants.BOT_API_VERSION_INFO``
- Updated the Bot API version number in all places: ``README.rst`` (including the badge) and ``telegram.constants.BOT_API_VERSION_INFO``
- Added logic for arbitrary callback data in :class:`telegram.ext.ExtBot` for new methods that either accept a ``reply_markup`` in some form or have a return type that is/contains :class:`~telegram.Message`
Documenting
@@ -210,13 +210,8 @@ doc strings don't have a separate documentation site they generate, instead, the
User facing documentation
-------------------------
We use `sphinx`_ to generate static HTML docs. To build them, first make sure you're running Python 3.9 or above and have the required dependencies:
.. code-block:: bash
$ pip install -r docs/requirements-docs.txt
then run the following from the PTB root directory:
We use `sphinx`_ to generate static HTML docs. To build them, first make sure you're running Python 3.10 or above and have the required dependencies installed as explained above.
Then, run the following from the PTB root directory:
.. code-block:: bash
+2 -2
View File
@@ -1,7 +1,7 @@
name: Bug Report
description: Create a report to help us improve
title: "[BUG]"
labels: ["bug :bug:"]
labels: ["📋 triage"]
type: '🐛 bug'
body:
- type: markdown
+2 -2
View File
@@ -1,7 +1,7 @@
name: Feature Request
description: Suggest an idea for this project
title: "[FEATURE]"
labels: ["enhancement"]
labels: ["📋 triage"]
type: '💡 feature'
body:
- type: textarea
+1 -1
View File
@@ -1,7 +1,7 @@
name: Question
description: Get help with errors or general questions
title: "[QUESTION]"
labels: ["question"]
type: '❔ question'
body:
- type: markdown
+6
View File
@@ -5,6 +5,9 @@ updates:
schedule:
interval: "weekly"
day: "friday"
labels:
- "⚙️ dependencies"
- "🔗 python"
# Updates the dependencies of the GitHub Actions workflows
- package-ecosystem: "github-actions"
@@ -12,3 +15,6 @@ updates:
schedule:
interval: "monthly"
day: "friday"
labels:
- "⚙️ dependencies"
- "🔗 github-actions"
+2 -2
View File
@@ -3,7 +3,7 @@
version: 1
labels:
- label: "dependencies"
- label: "⚙️ dependencies"
authors: ["dependabot[bot]", "pre-commit-ci[bot]"]
- label: "code quality"
- label: "🛠 code-quality"
authors: ["pre-commit-ci[bot]"]
+7 -4
View File
@@ -4,6 +4,8 @@ on:
pull_request:
types: [opened, reopened]
permissions: {}
jobs:
process-dependabot-prs:
permissions:
@@ -16,14 +18,15 @@ jobs:
- name: Fetch Dependabot metadata
id: dependabot-metadata
uses: dependabot/fetch-metadata@v2.1.0
uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7 # v2.3.0
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ github.event.pull_request.head.ref }}
persist-credentials: false
- name: Update Version Number in Other Files
uses: jacobtomlinson/gha-find-replace@v3
uses: jacobtomlinson/gha-find-replace@f1069b438f125e5395d84d1c6fd3b559a7880cb5 # v3
with:
find: ${{ steps.dependabot-metadata.outputs.previous-version }}
replace: ${{ steps.dependabot-metadata.outputs.new-version }}
@@ -31,7 +34,7 @@ jobs:
exclude: CHANGES.rst
- name: Commit & Push Changes to PR
uses: EndBug/add-and-commit@v9.1.4
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4
with:
message: 'Update version number in other files'
committer_name: GitHub Actions
+18 -4
View File
@@ -3,6 +3,11 @@ on:
schedule:
# First day of month at 05:46 in every 2nd month
- cron: '46 5 1 */2 *'
pull_request:
paths:
- .github/workflows/docs-linkcheck.yml
permissions: {}
jobs:
test-sphinx-build:
@@ -10,18 +15,27 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: [3.9]
python-version: ['3.10']
os: [ubuntu-latest]
fail-fast: False
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -r requirements-all.txt
python -W ignore -m pip install -r requirements-dev-all.txt
- name: Check Links
run: sphinx-build docs/source docs/build/html -W --keep-going -j auto -b linkcheck
- name: Upload linkcheck output
# Run also if the previous steps failed
if: always()
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: linkcheck-output
path: docs/build/html/output.*
+12 -5
View File
@@ -8,19 +8,26 @@ on:
branches:
- master
permissions: {}
jobs:
test-sphinx-build:
name: test-sphinx-build
runs-on: ${{matrix.os}}
permissions:
# for uploading artifacts
actions: write
strategy:
matrix:
python-version: [3.9]
python-version: ['3.10']
os: [ubuntu-latest]
fail-fast: False
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
@@ -28,13 +35,13 @@ jobs:
- name: Install dependencies
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -r requirements-all.txt
python -W ignore -m pip install -r requirements-dev-all.txt
- name: Test autogeneration of admonitions
run: pytest -v --tb=short tests/docs/admonition_inserter.py
- name: Build docs
run: sphinx-build docs/source docs/build/html -W --keep-going -j auto
- name: Upload docs
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: HTML Docs
retention-days: 7
+33
View File
@@ -0,0 +1,33 @@
name: GitHub Actions Security Analysis
on:
push:
branches:
- master
pull_request:
permissions: {}
jobs:
zizmor:
name: Security Analysis with zizmor
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Install the latest version of uv
uses: astral-sh/setup-uv@4db96194c378173c656ce18a155ffc14a9fc4355 # v5.2.2
- name: Run zizmor
run: uvx zizmor --persona=pedantic --format sarif . > results.sarif
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
with:
sarif_file: results.sarif
category: zizmor
+3 -1
View File
@@ -4,6 +4,8 @@ on:
pull_request:
types: [opened]
permissions: {}
jobs:
pre-commit-ci:
permissions:
@@ -11,7 +13,7 @@ jobs:
pull-requests: write # for srvaroa/labeler to add labels in PR
runs-on: ubuntu-latest
steps:
- uses: srvaroa/labeler@v1.10.1
- uses: srvaroa/labeler@fe4b1c73bb8abf2f14a44a6912a8b4fee835d631 # v1.12.0
# Config file at .github/labeler.yml
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+7 -1
View File
@@ -4,11 +4,17 @@ on:
schedule:
- cron: '8 4 * * *'
permissions: {}
jobs:
lock:
runs-on: ubuntu-latest
permissions:
# For locking the threads
issues: write
pull-requests: write
steps:
- uses: dessant/lock-threads@v5.0.1
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
with:
github-token: ${{ github.token }}
issue-inactive-days: '7'
@@ -1,19 +0,0 @@
name: Warning maintainers
on:
pull_request_target:
paths:
- requirements.txt
- requirements-opts.txt
- .pre-commit-config.yaml
permissions:
pull-requests: write
jobs:
job:
runs-on: ubuntu-latest
name: about pre-commit and dependency change
steps:
- name: running the check
uses: Poolitzer/notifier-action@master
with:
notify-message: Hey! Looks like you edited the (optional) requirements or the pre-commit hooks. I'm just a friendly reminder to keep the additional dependencies for the hooks in sync with the requirements :)
repo-token: ${{ secrets.GITHUB_TOKEN }}
-18
View File
@@ -1,18 +0,0 @@
name: Warning maintainers
on:
pull_request_target:
paths:
- README.rst
- README_RAW.rst
permissions:
pull-requests: write
jobs:
job:
runs-on: ubuntu-latest
name: about readme change
steps:
- name: running the check
uses: Poolitzer/notifier-action@master
with:
notify-message: Hey! Looks like you edited README.rst or README_RAW.rst. I'm just a friendly reminder to apply relevant changes to both of those files :)
repo-token: ${{ secrets.GITHUB_TOKEN }}
+139
View File
@@ -0,0 +1,139 @@
name: Publish to PyPI
on:
# manually trigger the workflow
workflow_dispatch:
permissions: {}
jobs:
build:
name: Build Distribution
runs-on: ubuntu-latest
outputs:
TAG: ${{ steps.get_tag.outputs.TAG }}
permissions:
# for uploading artifacts
actions: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.x"
- name: Install pypa/build
run: >-
python3 -m pip install build --user
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: python-package-distributions
path: dist/
- name: Get Tag Name
id: get_tag
run: |
pip install .
TAG=$(python -c "from telegram import __version__; print(f'v{__version__}')")
echo "TAG=$TAG" >> $GITHUB_OUTPUT
publish-to-pypi:
name: Publish to PyPI
needs:
- build
runs-on: ubuntu-latest
environment:
name: release_pypi
url: https://pypi.org/p/python-telegram-bot
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
actions: read # for downloading artifacts
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: python-package-distributions
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
compute-signatures:
name: Compute SHA1 Sums and Sign with Sigstore
runs-on: ubuntu-latest
needs:
- publish-to-pypi
permissions:
id-token: write # IMPORTANT: mandatory for sigstore
actions: write # for up/downloading artifacts
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: python-package-distributions
path: dist/
- name: Compute SHA1 Sums
run: |
# Compute SHA1 sum of the distribution packages and save it to a file with the same name,
# but with .sha1 extension
for file in dist/*; do
sha1sum $file > $file.sha1
done
- name: Sign the dists with Sigstore
uses: sigstore/gh-action-sigstore-python@f514d46b907ebcd5bedc05145c03b69c1edd8b46 # v3.0.0
with:
inputs: >-
./dist/*.tar.gz
./dist/*.whl
- name: Store the distribution packages and signatures
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: python-package-distributions-and-signatures
path: dist/
github-release:
name: Upload to GitHub Release
needs:
- build
- compute-signatures
runs-on: ubuntu-latest
permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases
actions: read # for downloading artifacts
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: python-package-distributions-and-signatures
path: dist/
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
TAG: ${{ needs.build.outputs.TAG }}
# Create a tag and a GitHub Release. The description can be changed later, as for now
# we don't define it through this workflow.
run: >-
gh release create
"$TAG"
--repo '${{ github.repository }}'
--generate-notes
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
TAG: ${{ needs.build.outputs.TAG }}
# Upload to GitHub Release using the `gh` CLI.
# `dist/` contains the built packages, and the
# sigstore-produced signatures and certificates.
run: >-
gh release upload
"$TAG" dist/**
--repo '${{ github.repository }}'
+142
View File
@@ -0,0 +1,142 @@
name: Publish to Test PyPI
on:
# manually trigger the workflow
workflow_dispatch:
permissions: {}
jobs:
build:
name: Build Distribution
runs-on: ubuntu-latest
outputs:
TAG: ${{ steps.get_tag.outputs.TAG }}
permissions:
# for uploading artifacts
actions: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: "3.x"
- name: Install pypa/build
run: >-
python3 -m pip install build --user
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: python-package-distributions
path: dist/
- name: Get Tag Name
id: get_tag
run: |
pip install .
TAG=$(python -c "from telegram import __version__; print(f'v{__version__}')")
echo "TAG=$TAG" >> $GITHUB_OUTPUT
publish-to-test-pypi:
name: Publish to Test PyPI
needs:
- build
runs-on: ubuntu-latest
environment:
name: release_test_pypi
url: https://test.pypi.org/p/python-telegram-bot
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
actions: read # for downloading artifacts
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: python-package-distributions
path: dist/
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3
with:
repository-url: https://test.pypi.org/legacy/
compute-signatures:
name: Compute SHA1 Sums and Sign with Sigstore
runs-on: ubuntu-latest
needs:
- publish-to-test-pypi
permissions:
id-token: write # IMPORTANT: mandatory for sigstore
actions: write # for up/downloading artifacts
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: python-package-distributions
path: dist/
- name: Compute SHA1 Sums
run: |
# Compute SHA1 sum of the distribution packages and save it to a file with the same name,
# but with .sha1 extension
for file in dist/*; do
sha1sum $file > $file.sha1
done
- name: Sign the dists with Sigstore
uses: sigstore/gh-action-sigstore-python@f514d46b907ebcd5bedc05145c03b69c1edd8b46 # v3.0.0
with:
inputs: >-
./dist/*.tar.gz
./dist/*.whl
- name: Store the distribution packages and signatures
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: python-package-distributions-and-signatures
path: dist/
github-test-release:
name: Upload to GitHub Release Draft
needs:
- build
- compute-signatures
runs-on: ubuntu-latest
permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases
actions: read # for downloading artifacts
steps:
- name: Download all the dists
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: python-package-distributions-and-signatures
path: dist/
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
TAG: ${{ needs.build.outputs.TAG }}
# Create a GitHub Release *draft*. The description can be changed later, as for now
# we don't define it through this workflow.
run: >-
gh release create
"$TAG"
--repo '${{ github.repository }}'
--generate-notes
--draft
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
TAG: ${{ needs.build.outputs.TAG }}
# Upload to GitHub Release using the `gh` CLI.
# `dist/` contains the built packages, and the
# sigstore-produced signatures and certificates.
run: >-
gh release upload
"$TAG" dist/**
--repo '${{ github.repository }}'
+7 -2
View File
@@ -3,17 +3,22 @@ on:
schedule:
- cron: '42 2 * * *'
permissions: {}
jobs:
stale:
runs-on: ubuntu-latest
permissions:
# For adding labels and closing
issues: write
steps:
- uses: actions/stale@v9
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
with:
# PRs never get stale
days-before-stale: 3
days-before-close: 2
days-before-pr-stale: -1
stale-issue-label: 'stale'
stale-issue-label: '📋 stale'
only-labels: 'question'
stale-issue-message: ''
close-issue-message: 'This issue has been automatically closed due to inactivity. Feel free to comment in order to reopen or ask again in our Telegram support group at https://t.me/pythontelegrambotgroup.'
+9 -6
View File
@@ -11,6 +11,8 @@ on:
# Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions
- cron: '7 3 * * 1,5'
permissions: {}
jobs:
check-conformity:
name: check-conformity
@@ -21,17 +23,18 @@ jobs:
os: [ubuntu-latest]
fail-fast: False
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -r requirements.txt
python -W ignore -m pip install -r requirements-opts.txt
python -W ignore -m pip install -r requirements-dev.txt
python -W ignore -m pip install .[all]
python -W ignore -m pip install -r requirements-unit-tests.txt
- name: Compare to official api
run: |
pytest -v tests/test_official/test_official.py --junit-xml=.test_report_official.xml
@@ -42,7 +45,7 @@ jobs:
- name: Test Summary
id: test_summary
uses: test-summary/action@v2.3
uses: test-summary/action@31493c76ec9e7aa675f1585d3ed6f1da69269a86 # v2.4
if: always() # always run, even if tests fail
with:
paths: .test_report_official.xml
+8 -64
View File
@@ -3,77 +3,21 @@ on:
pull_request:
paths:
- telegram/**
- requirements.txt
- requirements-opts.txt
- pyproject.toml
- .github/workflows/type_completeness.yml
push:
branches:
- master
permissions: {}
jobs:
test-type-completeness:
name: test-type-completeness
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: git fetch --depth=1 # https://github.com/actions/checkout/issues/329#issuecomment-674881489
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- uses: Bibo-Joshi/pyright-type-completeness@c85a67ff3c66f51dcbb2d06bfcf4fe83a57d69cc # v1.0.1
with:
python-version: 3.9
cache: 'pip'
cache-dependency-path: '**/requirements*.txt'
- name: Install Pyright
run: |
python -W ignore -m pip install pyright~=1.1.316
- name: Get PR Completeness
# Must run before base completeness, as base completeness will checkout the base branch
# And we can't go back to the PR branch after that in case the PR is coming from a fork
run: |
pip install . -U
pyright --verifytypes telegram --ignoreexternal --outputjson > pr.json || true
pyright --verifytypes telegram --ignoreexternal > pr.readable || true
- name: Get Base Completeness
run: |
git checkout ${{ github.base_ref }}
pip install . -U
pyright --verifytypes telegram --ignoreexternal --outputjson > base.json || true
- name: Compare Completeness
uses: jannekem/run-python-script-action@v1
with:
script: |
import json
import os
from pathlib import Path
base = float(
json.load(open("base.json", "rb"))["typeCompleteness"]["completenessScore"]
)
pr = float(
json.load(open("pr.json", "rb"))["typeCompleteness"]["completenessScore"]
)
base_text = f"This PR changes type completeness from {round(base, 3)} to {round(pr, 3)}."
if base == 0:
text = f"Something is broken in the workflow. Reported type completeness is 0. 💥"
set_summary(text)
print(Path("pr.readable").read_text(encoding="utf-8"))
error(text)
exit(1)
if pr < (base - 0.001):
text = f"{base_text} ❌"
set_summary(text)
print(Path("pr.readable").read_text(encoding="utf-8"))
error(text)
exit(1)
elif pr > (base + 0.001):
text = f"{base_text} ✨"
set_summary(text)
if pr < 1:
print(Path("pr.readable").read_text(encoding="utf-8"))
print(text)
else:
text = f"{base_text} This is less than 0.1 percentage points. ✅"
set_summary(text)
print(Path("pr.readable").read_text(encoding="utf-8"))
print(text)
package-name: telegram
python-version: 3.12
pyright-version: ~=1.1.367
@@ -0,0 +1,35 @@
name: Check Type Completeness Monthly Run
on:
schedule:
# Run first friday of the month at 03:17 - odd time to spread load on GitHub Actions
- cron: '17 3 1-7 * 5'
permissions: {}
jobs:
test-type-completeness:
name: test-type-completeness
runs-on: ubuntu-latest
steps:
- uses: Bibo-Joshi/pyright-type-completeness@c85a67ff3c66f51dcbb2d06bfcf4fe83a57d69cc # v1.0.1
id: pyright-type-completeness
with:
package-name: telegram
python-version: 3.12
pyright-version: ~=1.1.367
- name: Check Output
uses: jannekem/run-python-script-action@bbfca66c612a28f3eeca0ae40e1f810265e2ea68 # v1.7
env:
TYPE_COMPLETENESS: ${{ steps.pyright-type-completeness.outputs.base-completeness-score }}
with:
script: |
import os
completeness = float(os.getenv("TYPE_COMPLETENESS"))
if completeness >= 1:
exit(0)
text = f"Type Completeness Decreased to {completeness}. ❌"
error(text)
set_summary(text)
exit(1)
+32 -25
View File
@@ -4,9 +4,9 @@ on:
paths:
- telegram/**
- tests/**
- requirements.txt
- requirements-opts.txt
- requirements-dev.txt
- .github/workflows/unit_tests.yml
- pyproject.toml
- requirements-unit-tests.txt
push:
branches:
- master
@@ -14,19 +14,23 @@ on:
# Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions
- cron: '7 3 * * 1,5'
permissions: {}
jobs:
pytest:
name: pytest
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
os: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: False
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
@@ -35,9 +39,9 @@ jobs:
run: |
python -W ignore -m pip install --upgrade pip
python -W ignore -m pip install -U pytest-cov
python -W ignore -m pip install -r requirements.txt
python -W ignore -m pip install -r requirements-dev.txt
python -W ignore -m pip install pytest-xdist[psutil]
python -W ignore -m pip install .
python -W ignore -m pip install -r requirements-unit-tests.txt
python -W ignore -m pip install pytest-xdist
- name: Test with pytest
# We run 4 different suites here
@@ -57,21 +61,18 @@ jobs:
# - without socks support
# - without http2 support
TO_TEST="test_no_passport.py or test_datetime.py or test_defaults.py or test_jobqueue.py or test_applicationbuilder.py or test_ratelimiter.py or test_updater.py or test_callbackdatacache.py or test_request.py"
pytest -v --cov -k "${TO_TEST}"
# Rerun only failed tests (--lf), and don't run any tests if none failed (--lfnf=none)
pytest -v --cov --cov-append -k "${TO_TEST}" --lf --lfnf=none --junit-xml=.test_report_no_optionals.xml
# No tests were selected, convert returned status code to 0
opt_dep_status=$(( $? == 5 ? 0 : $? ))
pytest -v --cov -k "${TO_TEST}" --junit-xml=.test_report_no_optionals_junit.xml
opt_dep_status=$?
# Test the rest
export TEST_WITH_OPT_DEPS='true'
pip install -r requirements-opts.txt
# `-n auto --dist loadfile` uses pytest-xdist to run each test file on a different CPU
# worker. Increasing number of workers has little effect on test duration, but it seems
# to increase flakyness, specially on python 3.7 with --dist=loadgroup.
pytest -v --cov --cov-append -n auto --dist loadfile
pytest -v --cov --cov-append -n auto --dist loadfile --lf --lfnf=none --junit-xml=.test_report_optionals.xml
main_status=$(( $? == 5 ? 0 : $? ))
# need to manually install pytz here, because it's no longer in the optional reqs
pip install .[all] pytz
# `-n auto --dist worksteal` uses pytest-xdist to run tests on multiple CPU
# workers. Increasing number of workers has little effect on test duration, but it seems
# to increase flakyness.
pytest -v --cov --cov-append -n auto --dist worksteal --junit-xml=.test_report_optionals_junit.xml
main_status=$?
# exit with non-zero status if any of the two pytest runs failed
exit $(( ${opt_dep_status} || ${main_status} ))
env:
@@ -83,17 +84,23 @@ jobs:
- name: Test Summary
id: test_summary
uses: test-summary/action@v2.3
uses: test-summary/action@31493c76ec9e7aa675f1585d3ed6f1da69269a86 # v2.4
if: always() # always run, even if tests fail
with:
paths: |
.test_report_no_optionals.xml
.test_report_optionals.xml
.test_report_no_optionals_junit.xml
.test_report_optionals_junit.xml
- name: Submit coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2
with:
env_vars: OS,PYTHON
name: ${{ matrix.os }}-${{ matrix.python-version }}
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload test results to Codecov
uses: codecov/test-results-action@4e79e65778be1cecd5df25e14af1eafb6df80ea9 # v1.0.2
if: ${{ !cancelled() }}
with:
files: .test_report_no_optionals_junit.xml,.test_report_optionals_junit.xml
token: ${{ secrets.CODECOV_TOKEN }}
+4
View File
@@ -67,6 +67,7 @@ docs/_build/
# PyBuilder
target/
.idea/
.run/
# Sublime Text 2
*.sublime*
@@ -92,3 +93,6 @@ telegram.jpg
# virtual env
venv*
# environment manager:
.mise.toml
+15 -15
View File
@@ -1,4 +1,4 @@
# Make sure that the additional_dependencies here match requirements(-opts).txt
# Make sure that the additional_dependencies here match pyproject.toml
ci:
autofix_prs: false
@@ -7,7 +7,7 @@ ci:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.4.3'
rev: 'v0.8.6'
hooks:
- id: ruff
name: ruff
@@ -15,21 +15,21 @@ repos:
- httpx~=0.27
- tornado~=6.4
- APScheduler~=3.10.4
- cachetools~=5.3.3
- aiolimiter~=1.1.0
- cachetools>=5.3.3,<5.5.0
- aiolimiter~=1.1,<1.3
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.4.2
rev: 24.10.0
hooks:
- id: black
args:
- --diff
- --check
- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
rev: 7.1.1
hooks:
- id: flake8
- repo: https://github.com/PyCQA/pylint
rev: v3.1.0
rev: v3.3.3
hooks:
- id: pylint
files: ^(?!(tests|docs)).*\.py$
@@ -37,11 +37,11 @@ repos:
- httpx~=0.27
- tornado~=6.4
- APScheduler~=3.10.4
- cachetools~=5.3.3
- aiolimiter~=1.1.0
- cachetools>=5.3.3,<5.5.0
- aiolimiter~=1.1,<1.3
- . # this basically does `pip install -e .`
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
rev: v1.14.1
hooks:
- id: mypy
name: mypy-ptb
@@ -53,8 +53,8 @@ repos:
- httpx~=0.27
- tornado~=6.4
- APScheduler~=3.10.4
- cachetools~=5.3.3
- aiolimiter~=1.1.0
- cachetools>=5.3.3,<5.5.0
- aiolimiter~=1.1,<1.3
- . # this basically does `pip install -e .`
- id: mypy
name: mypy-examples
@@ -65,14 +65,14 @@ repos:
additional_dependencies:
- tornado~=6.4
- APScheduler~=3.10.4
- cachetools~=5.3.3
- cachetools>=5.3.3,<5.5.0
- . # this basically does `pip install -e .`
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.2
rev: v3.19.1
hooks:
- id: pyupgrade
args:
- --py38-plus
- --py39-plus
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
+12
View File
@@ -23,6 +23,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Abdelrahman <https://github.com/aelkheir>`_
- `Abshar <https://github.com/abxhr>`_
- `Abubakar Alaya <https://github.com/Ecode2>`_
- `Alateas <https://github.com/alateas>`_
- `Ales Dokshanin <https://github.com/alesdokshanin>`_
- `Alexandre <https://github.com/xTudoS>`_
@@ -30,6 +31,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Ambro17 <https://github.com/Ambro17>`_
- `Andrej Zhilenkov <https://github.com/Andrej730>`_
- `Anton Tagunov <https://github.com/anton-tagunov>`_
- `Anya Marcano <https://github.com/AnyaMarcanito>`
- `Avanatiker <https://github.com/Avanatiker>`_
- `Balduro <https://github.com/Balduro>`_
- `Bibo-Joshi <https://github.com/Bibo-Joshi>`_
@@ -57,11 +59,14 @@ The following wonderful people contributed directly or indirectly to this projec
- `gamgi <https://github.com/gamgi>`_
- `Gauthamram Ravichandran <https://github.com/GauthamramRavichandran>`_
- `Harshil <https://github.com/harshil21>`_
- `Henry Galue <https://github.com/henryg311>`
- `Hugo Damer <https://github.com/HakimusGIT>`_
- `ihoru <https://github.com/ihoru>`_
- `Iulian Onofrei <https://github.com/revolter>`_
- `Jainam Oswal <https://github.com/jainamoswal>`_
- `Jasmin Bom <https://github.com/jsmnbom>`_
- `JASON0916 <https://github.com/JASON0916>`_
- `Jeamhowards Montiel <https://github.com/Jeam-zx>`
- `jeffffc <https://github.com/jeffffc>`_
- `Jelle Besseling <https://github.com/pingiun>`_
- `jh0ker <https://github.com/jh0ker>`_
@@ -70,6 +75,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Joscha Götzer <https://github.com/Rostgnom>`_
- `jossalgon <https://github.com/jossalgon>`_
- `JRoot3D <https://github.com/JRoot3D>`_
- `Juan Cuevas <https://github.com/cuevasrja>`
- `kenjitagawa <https://github.com/kenjitagawa>`_
- `kennethcheo <https://github.com/kennethcheo>`_
- `Kirill Vasin <https://github.com/vasinkd>`_
@@ -79,13 +85,16 @@ The following wonderful people contributed directly or indirectly to this projec
- `LRezende <https://github.com/lrezende>`_
- `Luca Bellanti <https://github.com/Trifase>`_
- `Lucas Molinari <https://github.com/lucasmolinari>`_
- `Luis Pérez <https://github.com/nemacysts>`_
- `macrojames <https://github.com/macrojames>`_
- `Matheus Lemos <https://github.com/mlemosf>`_
- `Michael Dix <https://github.com/Eisberge>`_
- `Michael Elovskikh <https://github.com/wronglink>`_
- `Miguel C. R. <https://github.com/MiguelX413>`_
- `Miguel Salomon <https://github.com/Migueldsc12>`
- `miles <https://github.com/miles170>`_
- `Mischa Krüger <https://github.com/Makman2>`_
- `Mohd Yusuf <https://github.com/mohdyusuf2312>`_
- `naveenvhegde <https://github.com/naveenvhegde>`_
- `neurrone <https://github.com/neurrone>`_
- `NikitaPirate <https://github.com/NikitaPirate>`_
@@ -96,6 +105,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Oleg Sushchenko <https://github.com/feuillemorte>`_
- `Or Bin <https://github.com/OrBin>`_
- `overquota <https://github.com/overquota>`_
- `Pablo Martinez <https://github.com/elpekenin>`_
- `Paradox <https://github.com/paradox70>`_
- `Patrick Hofmann <https://github.com/PH89>`_
- `Paul Larsen <https://github.com/PaulSonOfLars>`_
@@ -107,11 +117,13 @@ The following wonderful people contributed directly or indirectly to this projec
- `Rahiel Kasim <https://github.com/rahiel>`_
- `Riko Naka <https://github.com/rikonaka>`_
- `Rizlas <https://github.com/rizlas>`_
- Snehashish Biswas
- `Sahil Sharma <https://github.com/sahilsharma811>`_
- `Sam Mosleh <https://github.com/sam-mosleh>`_
- `Sascha <https://github.com/saschalalala>`_
- `Shelomentsev D <https://github.com/shelomentsevd>`_
- `Shivam Saini <https://github.com/shivamsn97>`_
- `Siloé Garcez <https://github.com/roast-lord>`_
- `Simon Schürrle <https://github.com/SitiSchu>`_
- `sooyhwang <https://github.com/sooyhwang>`_
- `syntx <https://github.com/syntx>`_
+317
View File
@@ -4,6 +4,323 @@
Changelog
=========
Version 21.11
=============
*Released 2025-03-01*
This is the technical changelog for version 21.11. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes and New Features
------------------------------
- Full Support for Bot API 8.3 (:pr:`4676` closes :issue:`4677`, :pr:`4682` by `aelkheir <https://github.com/aelkheir>`_, :pr:`4690` by `aelkheir <https://github.com/aelkheir>`_, :pr:`4691` by `aelkheir <https://github.com/aelkheir>`_)
- Make ``provider_token`` Argument Optional (:pr:`4689`)
- Remove Deprecated ``InlineQueryResultArticle.hide_url`` (:pr:`4640` closes :issue:`4638`)
- Accept ``datetime.timedelta`` Input in ``Bot`` Method Parameters (:pr:`4651`)
- Extend Customization Support for ``Bot.base_(file_)url`` (:pr:`4632` closes :issue:`3355`)
- Support ``allow_paid_broadcast`` in ``AIORateLimiter`` (:pr:`4627` closes :issue:`4578`)
- Add ``BaseUpdateProcessor.current_concurrent_updates`` (:pr:`4626` closes :issue:`3984`)
Minor Changes and Bug Fixes
---------------------------
- Add Bootstrapping Logic to ``Application.run_*`` (:pr:`4673` closes :issue:`4657`)
- Fix a Bug in ``edit_user_star_subscription`` (:pr:`4681` by `vavasik800 <https://github.com/vavasik800>`_)
- Simplify Handling of Empty Data in ``TelegramObject.de_json`` and Friends (:pr:`4617` closes :issue:`4614`)
Documentation Improvements
--------------------------
- Documentation Improvements (:pr:`4641`)
- Overhaul Admonition Insertion in Documentation (:pr:`4462` closes :issue:`4414`)
Internal Changes
----------------
- Stabilize Linkcheck Test (:pr:`4693`)
- Bump ``pre-commit`` Hooks to Latest Versions (:pr:`4643`)
- Refactor Tests for ``TelegramObject`` Classes with Subclasses (:pr:`4654` closes :issue:`4652`)
- Use Fine Grained Permissions for GitHub Actions Workflows (:pr:`4668`)
Dependency Updates
------------------
- Bump ``actions/setup-python`` from 5.3.0 to 5.4.0 (:pr:`4665`)
- Bump ``dependabot/fetch-metadata`` from 2.2.0 to 2.3.0 (:pr:`4666`)
- Bump ``actions/stale`` from 9.0.0 to 9.1.0 (:pr:`4667`)
- Bump ``astral-sh/setup-uv`` from 5.1.0 to 5.2.2 (:pr:`4664`)
- Bump ``codecov/test-results-action`` from 1.0.1 to 1.0.2 (:pr:`4663`)
Version 21.10
=============
*Released 2025-01-03*
This is the technical changelog for version 21.10. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for Bot API 8.2 (:pr:`4633`)
- Bump ``apscheduler`` & Deprecate ``pytz`` Support (:pr:`4582`)
New Features
------------
- Add Parameter ``pattern`` to ``JobQueue.jobs()`` (:pr:`4613` closes :issue:`4544`)
- Allow Input of Type ``Sticker`` for Several Methods (:pr:`4616` closes :issue:`4580`)
Bug Fixes
---------
- Ensure Forward Compatibility of ``Gift`` and ``Gifts`` (:pr:`4634` closes :issue:`4637`)
Documentation Improvements & Internal Changes
---------------------------------------------
- Use Custom Labels for ``dependabot`` PRs (:pr:`4621`)
- Remove Redundant ``pylint`` Suppressions (:pr:`4628`)
- Update Copyright to 2025 (:pr:`4631`)
- Refactor Module Structure and Tests for Star Payments Classes (:pr:`4615` closes :issue:`4593`)
- Unify ``datetime`` Imports (:pr:`4605` by `cuevasrja <https://github.com/cuevasrja>`_ closes :issue:`4577`)
- Add Static Security Analysis of GitHub Actions Workflows (:pr:`4606`)
Dependency Updates
------------------
- Bump ``astral-sh/setup-uv`` from 4.2.0 to 5.1.0 (:pr:`4625`)
- Bump ``codecov/codecov-action`` from 5.1.1 to 5.1.2 (:pr:`4622`)
- Bump ``actions/upload-artifact`` from 4.4.3 to 4.5.0 (:pr:`4623`)
- Bump ``github/codeql-action`` from 3.27.9 to 3.28.0 (:pr:`4624`)
Version 21.9
============
*Released 2024-12-07*
This is the technical changelog for version 21.9. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for Bot API 8.1 (:pr:`4594` closes :issue:`4592`)
Minor Changes
-------------
- Use ``MessageLimit.DEEP_LINK_LENGTH`` in ``helpers.create_deep_linked_url`` (:pr:`4597` by `nemacysts <https://github.com/nemacysts>`_)
- Allow ``Sequence`` Input for ``allowed_updates`` in ``Application`` and ``Updater`` Methods (:pr:`4589` by `nemacysts <https://github.com/nemacysts>`_)
Dependency Updates
------------------
- Update ``aiolimiter`` requirement from ~=1.1.0 to >=1.1,<1.3 (:pr:`4595`)
- Bump ``pytest`` from 8.3.3 to 8.3.4 (:pr:`4596`)
- Bump ``codecov/codecov-action`` from 4 to 5 (:pr:`4585`)
- Bump ``pylint`` to v3.3.2 to Improve Python 3.13 Support (:pr:`4590` by `nemacysts <https://github.com/nemacysts>`_)
- Bump ``srvaroa/labeler`` from 1.11.1 to 1.12.0 (:pr:`4586`)
Version 21.8
============
*Released 2024-12-01*
This is the technical changelog for version 21.8. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for Bot API 8.0 (:pr:`4568`, :pr:`4566` closes :issue:`4567`, :pr:`4572`, :pr:`4571`, :pr:`4570`, :pr:`4576`, :pr:`4574`)
Documentation Improvements
--------------------------
- Documentation Improvements (:pr:`4565` by Snehashish06, :pr:`4573`)
Version 21.7
============
*Released 2024-11-04*
This is the technical changelog for version 21.7. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for Bot API 7.11 (:pr:`4546` closes :issue:`4543`)
- Add ``Message.reply_paid_media`` (:pr:`4551`)
- Drop Support for Python 3.8 (:pr:`4398` by `elpekenin <https://github.com/elpekenin>`_)
Minor Changes
-------------
- Allow ``Sequence`` in ``Application.add_handlers`` (:pr:`4531` by `roast-lord <https://github.com/roast-lord>`_ closes :issue:`4530`)
- Improve Exception Handling in ``File.download_*`` (:pr:`4542`)
- Use Stable Python 3.13 Release in Test Suite (:pr:`4535`)
Documentation Improvements
--------------------------
- Documentation Improvements (:pr:`4536` by `Ecode2 <https://github.com/Ecode2>`_, :pr:`4556`)
- Fix Linkcheck Workflow (:pr:`4545`)
- Use ``sphinx-build-compatibility`` to Keep Sphinx Compatibility (:pr:`4492`)
Internal Changes
----------------
- Improve Test Instability Caused by ``Message`` Fixtures (:pr:`4507`)
- Stabilize Some Flaky Tests (:pr:`4500`)
- Reduce Creation of HTTP Clients in Tests (:pr:`4493`)
- Update ``pytest-xdist`` Usage (:pr:`4491`)
- Fix Failing Tests by Making Them Independent (:pr:`4494`)
- Introduce Codecov's Test Analysis (:pr:`4487`)
- Maintenance Work on ``Bot`` Tests (:pr:`4489`)
- Introduce ``conftest.py`` for File Related Tests (:pr:`4488`)
- Update Issue Templates to Use Issue Types (:pr:`4553`)
- Update Automation to Label Changes (:pr:`4552`)
Dependency Updates
------------------
- Bump ``srvaroa/labeler`` from 1.11.0 to 1.11.1 (:pr:`4549`)
- Bump ``sphinx`` from 8.0.2 to 8.1.3 (:pr:`4532`)
- Bump ``sphinxcontrib-mermaid`` from 0.9.2 to 1.0.0 (:pr:`4529`)
- Bump ``srvaroa/labeler`` from 1.10.1 to 1.11.0 (:pr:`4509`)
- Bump ``Bibo-Joshi/pyright-type-completeness`` from 1.0.0 to 1.0.1 (:pr:`4510`)
Version 21.6
============
*Released 2024-09-19*
This is the technical changelog for version 21.6. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
New Features
------------
- Full Support for Bot API 7.10 (:pr:`4461` closes :issue:`4459`, :pr:`4460`, :pr:`4463` by `aelkheir <https://github.com/aelkheir>`_, :pr:`4464`)
- Add Parameter ``httpx_kwargs`` to ``HTTPXRequest`` (:pr:`4451` closes :issue:`4424`)
Minor Changes
-------------
- Improve Type Completeness (:pr:`4466`)
Internal Changes
----------------
- Update Python 3.13 Test Suite to RC2 (:pr:`4471`)
- Enforce the ``offline_bot`` Fixture in ``Test*WithoutRequest`` (:pr:`4465`)
- Make Tests for ``telegram.ext`` Independent of Networking (:pr:`4454`)
- Rename Testing Base Classes (:pr:`4453`)
Dependency Updates
------------------
- Bump ``pytest`` from 8.3.2 to 8.3.3 (:pr:`4475`)
Version 21.5
============
*Released 2024-09-01*
This is the technical changelog for version 21.5. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for Bot API 7.9 (:pr:`4429`)
- Full Support for Bot API 7.8 (:pr:`4408`)
New Features
------------
- Add ``MessageEntity.shift_entities`` and ``MessageEntity.concatenate`` (:pr:`4376` closes :issue:`4372`)
- Add Parameter ``game_pattern`` to ``CallbackQueryHandler`` (:pr:`4353` by `jainamoswal <https://github.com/jainamoswal>`_ closes :issue:`4269`)
- Add Parameter ``read_file_handle`` to ``InputFile`` (:pr:`4388` closes :issue:`4339`)
Documentation Improvements
--------------------------
- Bugfix for "Available In" Admonitions (:pr:`4413`)
- Documentation Improvements (:pr:`4400` closes :issue:`4446`, :pr:`4448` by `Palaptin <https://github.com/Palaptin>`_)
- Document Return Types of ``RequestData`` Members (:pr:`4396`)
- Add Introductory Paragraphs to Telegram Types Subsections (:pr:`4389` by `mohdyusuf2312 <https://github.com/mohdyusuf2312>`_ closes :issue:`4380`)
- Start Adapting to RTD Addons (:pr:`4386`)
Minor and Internal Changes
---------------------------
- Remove Surplus Logging from ``Updater`` Network Loop (:pr:`4432` by `MartinHjelmare <https://github.com/MartinHjelmare>`_)
- Add Internal Constants for Encodings (:pr:`4378` by `elpekenin <https://github.com/elpekenin>`_)
- Improve PyPI Automation (:pr:`4375` closes :issue:`4373`)
- Update Test Suite to New Test Channel Setup (:pr:`4435`)
- Improve Fixture Usage in ``test_message.py`` (:pr:`4431` by `Palaptin <https://github.com/Palaptin>`_)
- Update Python 3.13 Test Suite to RC1 (:pr:`4415`)
- Bump ``ruff`` and Add New Rules (:pr:`4416`)
Dependency Updates
------------------
- Update ``cachetools`` requirement from <5.5.0,>=5.3.3 to >=5.3.3,<5.6.0 (:pr:`4437`)
- Bump ``sphinx`` from 7.4.7 to 8.0.2 and ``furo`` from 2024.7.18 to 2024.8.6 (:pr:`4412`)
- Bump ``test-summary/action`` from 2.3 to 2.4 (:pr:`4410`)
- Bump ``pytest`` from 8.2.2 to 8.3.2 (:pr:`4403`)
- Bump ``dependabot/fetch-metadata`` from 2.1.0 to 2.2.0 (:pr:`4411`)
- Update ``cachetools`` requirement from ~=5.3.3 to >=5.3.3,<5.5.0 (:pr:`4390`)
- Bump ``sphinx`` from 7.3.7 to 7.4.7 (:pr:`4395`)
- Bump ``furo`` from 2024.5.6 to 2024.7.18 (:pr:`4392`)
Version 21.4
============
*Released 2024-07-12*
This is the technical changelog for version 21.4. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel <https://t.me/pythontelegrambotchannel>`_.
Major Changes
-------------
- Full Support for Bot API 7.5 (:pr:`4328`, :pr:`4316`, :pr:`4315`, :pr:`4312` closes :issue:`4310`, :pr:`4311`)
- Full Support for Bot API 7.6 (:pr:`4333` closes :issue:`4331`, :pr:`4344`, :pr:`4341`, :pr:`4334`, :pr:`4335`, :pr:`4351`, :pr:`4342`, :pr:`4348`)
- Full Support for Bot API 7.7 (:pr:`4356` closes :issue:`4355`)
- Drop ``python-telegram-bot-raw`` And Switch to ``pyproject.toml`` Based Packaging (:pr:`4288` closes :issue:`4129` and :issue:`4296`)
- Deprecate Inclusion of ``successful_payment`` in ``Message.effective_attachment`` (:pr:`4365` closes :issue:`4350`)
New Features
------------
- Add Support for Python 3.13 Beta (:pr:`4253`)
- Add ``filters.PAID_MEDIA`` (:pr:`4357`)
- Log Received Data on Deserialization Errors (:pr:`4304`)
- Add ``MessageEntity.adjust_message_entities_to_utf_16`` Utility Function (:pr:`4323` by `Antares0982 <https://github.com/Antares0982>`_ closes :issue:`4319`)
- Make Argument ``bot`` of ``TelegramObject.de_json`` Optional (:pr:`4320`)
Documentation Improvements
--------------------------
- Documentation Improvements (:pr:`4303` closes :issue:`4301`)
- Restructure Readme (:pr:`4362`)
- Fix Link-Check Workflow (:pr:`4332`)
Internal Changes
----------------
- Automate PyPI Releases (:pr:`4364` closes :issue:`4318`)
- Add ``mise-en-place`` to ``.gitignore`` (:pr:`4300`)
- Use a Composite Action for Testing Type Completeness (:pr:`4367`)
- Stabilize Some Concurrency Usages in Test Suite (:pr:`4360`)
- Add a Test Case for ``MenuButton`` (:pr:`4363`)
- Extend ``SuccessfulPayment`` Test (:pr:`4349`)
- Small Fixes for ``test_stars.py`` (:pr:`4347`)
- Use Python 3.13 Beta 3 in Test Suite (:pr:`4336`)
Dependency Updates
------------------
- Bump ``ruff`` and Add New Rules (:pr:`4329`)
- Bump ``pre-commit`` Hooks to Latest Versions (:pr:`4337`)
- Add Lower Bound for ``flaky`` Dependency (:pr:`4322` by `Palaptin <https://github.com/Palaptin>`_)
- Bump ``pytest`` from 8.2.1 to 8.2.2 (:pr:`4294`)
Version 21.3
============
*Released 2024-06-07*
-1
View File
@@ -1 +0,0 @@
include LICENSE LICENSE.lesser requirements.txt requirements-opts.txt README_RAW.rst telegram/py.typed
+52 -27
View File
@@ -11,7 +11,7 @@
:target: https://pypi.org/project/python-telegram-bot/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-7.4-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-8.3-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API version
@@ -66,23 +66,36 @@ We have a vibrant community of developers helping each other in our `Telegram gr
*Stay tuned for library updates and new releases on our* `Telegram Channel <https://telegram.me/pythontelegrambotchannel>`_.
Introduction
============
------------
This library provides a pure Python, asynchronous interface for the
`Telegram Bot API <https://core.telegram.org/bots/api>`_.
It's compatible with Python versions **3.8+**.
It's compatible with Python versions **3.9+**.
In addition to the pure API implementation, this library features a number of high-level classes to
In addition to the pure API implementation, this library features several convenience methods and shortcuts as well as a number of high-level classes to
make the development of bots easy and straightforward. These classes are contained in the
``telegram.ext`` submodule.
Telegram API support
====================
After installing_ the library, be sure to check out the section on `working with PTB`_.
All types and methods of the Telegram Bot API **7.4** are supported.
Telegram API support
~~~~~~~~~~~~~~~~~~~~
All types and methods of the Telegram Bot API **8.3** are natively supported by this library.
In addition, Bot API functionality not yet natively included can still be used as described `in our wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Bot-API-Forward-Compatibility>`_.
Notable Features
~~~~~~~~~~~~~~~~
- `Fully asynchronous <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Concurrency>`_
- Convenient shortcut methods, e.g. `Message.reply_text <https://docs.python-telegram-bot.org/en/stable/telegram.message.html#telegram.Message.reply_text>`_
- `Fully annotated with static type hints <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Type-Checking>`_
- `Customizable and extendable interface <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Architecture>`_
- Seamless integration with `webhooks <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Webhooks>`_ and `polling <https://docs.python-telegram-bot.org/en/stable/telegram.ext.application.html#telegram.ext.Application.run_polling>`_
- `Comprehensive documentation and examples <#working-with-ptb>`_
Installing
==========
----------
You can install or upgrade ``python-telegram-bot`` via
@@ -98,22 +111,27 @@ You can also install ``python-telegram-bot`` from source, though this is usually
$ git clone https://github.com/python-telegram-bot/python-telegram-bot
$ cd python-telegram-bot
$ python setup.py install
$ pip install build
$ python -m build
Verifying Releases
------------------
~~~~~~~~~~~~~~~~~~
We sign all the releases with a GPG key.
The signatures are uploaded to both the `GitHub releases page <https://github.com/python-telegram-bot/python-telegram-bot/releases>`_ and the `PyPI project <https://pypi.org/project/python-telegram-bot/>`_ and end with a suffix ``.asc``.
To enable you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team, we have taken the following measures.
Starting with v21.4, all releases are signed via `sigstore <https://www.sigstore.dev>`_.
The corresponding signature files are uploaded to the `GitHub releases page`_.
To verify the signature, please install the `sigstore Python client <https://pypi.org/project/sigstore/>`_ and follow the instructions for `verifying signatures from GitHub Actions <https://github.com/sigstore/sigstore-python?tab=readme-ov-file>`_. As input for the ``--repository`` parameter, please use the value ``python-telegram-bot/python-telegram-bot``.
Earlier releases are signed with a GPG key.
The signatures are uploaded to both the `GitHub releases page`_ and the `PyPI project <https://pypi.org/project/python-telegram-bot/>`_ and end with a suffix ``.asc``.
Please find the public keys `here <https://github.com/python-telegram-bot/python-telegram-bot/tree/master/public_keys>`_.
The keys are named in the format ``<first_version>-<last_version>.gpg`` or ``<first_version>-current.gpg`` if the key is currently being used for new releases.
The keys are named in the format ``<first_version>-<last_version>.gpg``.
In addition, the GitHub release page also contains the sha1 hashes of the release files in the files with the suffix ``.sha1``.
This allows you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team.
Dependencies & Their Versions
-----------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``python-telegram-bot`` tries to use as few 3rd party dependencies as possible.
However, for some features using a 3rd party library is more sane than implementing the functionality again.
@@ -137,10 +155,10 @@ PTB can be installed with optional dependencies:
* ``pip install "python-telegram-bot[passport]"`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install "python-telegram-bot[socks]"`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
* ``pip install "python-telegram-bot[http2]"`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
* ``pip install "python-telegram-bot[rate-limiter]"`` installs `aiolimiter~=1.1.0 <https://aiolimiter.readthedocs.io/en/stable/>`_. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
* ``pip install "python-telegram-bot[rate-limiter]"`` installs `aiolimiter~=1.1,<1.3 <https://aiolimiter.readthedocs.io/en/stable/>`_. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
* ``pip install "python-telegram-bot[webhooks]"`` installs the `tornado~=6.4 <https://www.tornadoweb.org/en/stable/>`_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.run_webhook``.
* ``pip install "python-telegram-bot[callback-data]"`` installs the `cachetools~=5.3.3 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
* ``pip install "python-telegram-bot[job-queue]"`` installs the `APScheduler~=3.10.4 <https://apscheduler.readthedocs.io/en/3.x/>`_ library and enforces `pytz>=2018.6 <https://pypi.org/project/pytz/>`_, where ``pytz`` is a dependency of ``APScheduler``. Use this, if you want to use the ``telegram.ext.JobQueue``.
* ``pip install "python-telegram-bot[callback-data]"`` installs the `cachetools>=5.3.3,<5.6.0 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
* ``pip install "python-telegram-bot[job-queue]"`` installs the `APScheduler>=3.10.4,<3.12.0 <https://apscheduler.readthedocs.io/en/3.x/>`_ library. Use this, if you want to use the ``telegram.ext.JobQueue``.
To install multiple optional dependencies, separate them by commas, e.g. ``pip install "python-telegram-bot[socks,webhooks]"``.
@@ -149,14 +167,19 @@ Additionally, two shortcuts are provided:
* ``pip install "python-telegram-bot[all]"`` installs all optional dependencies.
* ``pip install "python-telegram-bot[ext]"`` installs all optional dependencies that are related to ``telegram.ext``, i.e. ``[rate-limiter, webhooks, callback-data, job-queue]``.
Working with PTB
----------------
Once you have installed the library, you can begin working with it - so let's get started!
Quick Start
===========
~~~~~~~~~~~
Our Wiki contains an `Introduction to the API <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API>`_ explaining how the pure Bot API can be accessed via ``python-telegram-bot``.
Moreover, the `Tutorial: Your first Bot <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions---Your-first-Bot>`_ gives an introduction on how chatbots can be easily programmed with the help of the ``telegram.ext`` module.
Resources
=========
~~~~~~~~~
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
@@ -167,7 +190,7 @@ Resources
- The `official Telegram Bot API documentation <https://core.telegram.org/bots/api>`_ is of course always worth a read.
Getting help
============
~~~~~~~~~~~~
If the resources mentioned above don't answer your questions or simply overwhelm you, there are several ways of getting help.
@@ -178,7 +201,7 @@ If the resources mentioned above don't answer your questions or simply overwhelm
3. You can even ask for help on Stack Overflow using the `python-telegram-bot tag <https://stackoverflow.com/questions/tagged/python-telegram-bot>`_.
Concurrency
===========
~~~~~~~~~~~
Since v20.0, ``python-telegram-bot`` is built on top of Pythons ``asyncio`` module.
Because ``asyncio`` is in general single-threaded, ``python-telegram-bot`` does currently not aim to be thread-safe.
@@ -191,20 +214,22 @@ Noteworthy parts of ``python-telegram-bots`` API that are likely to cause issues
* all classes in the ``telegram.ext.filters`` module that allow to add/remove allowed users/chats at runtime
Contributing
============
------------
Contributions of all sizes are welcome.
Please review our `contribution guidelines <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst>`_ to get started.
You can also help by `reporting bugs or feature requests <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_.
Donating
========
--------
Occasionally we are asked if we accept donations to support the development.
While we appreciate the thought, maintaining PTB is our hobby, and we have almost no running costs for it. We therefore have nothing set up to accept donations.
If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead.
License
=======
-------
You may copy, distribute and modify the software provided that modifications are described and licensed for free under `LGPL-3 <https://www.gnu.org/licenses/lgpl-3.0.html>`_.
Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be.
Derivative works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be.
.. _`GitHub releases page`: https://github.com/python-telegram-bot/python-telegram-bot/releases
-213
View File
@@ -1,213 +0,0 @@
.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-raw-logo-text_768.png?raw=true
:align: center
:target: https://python-telegram-bot.org
:alt: python-telegram-bot-raw Logo
.. image:: https://img.shields.io/pypi/v/python-telegram-bot-raw.svg
:target: https://pypi.org/project/python-telegram-bot-raw/
:alt: PyPi Package Version
.. image:: https://img.shields.io/pypi/pyversions/python-telegram-bot-raw.svg
:target: https://pypi.org/project/python-telegram-bot-raw/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-7.4-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API version
.. image:: https://img.shields.io/pypi/dm/python-telegram-bot-raw
:target: https://pypistats.org/packages/python-telegram-bot-raw
:alt: PyPi Package Monthly Download
.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable
:target: https://docs.python-telegram-bot.org/
:alt: Documentation Status
.. image:: https://img.shields.io/pypi/l/python-telegram-bot-raw.svg
:target: https://www.gnu.org/licenses/lgpl-3.0.html
:alt: LGPLv3 License
.. image:: https://github.com/python-telegram-bot/python-telegram-bot/actions/workflows/unit_tests.yml/badge.svg?branch=master
:target: https://github.com/python-telegram-bot/python-telegram-bot/
:alt: Github Actions workflow
.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg
:target: https://app.codecov.io/gh/python-telegram-bot/python-telegram-bot
:alt: Code coverage
.. image:: https://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg
:target: https://isitmaintained.com/project/python-telegram-bot/python-telegram-bot
:alt: Median time to resolve an issue
.. image:: https://api.codacy.com/project/badge/Grade/99d901eaa09b44b4819aec05c330c968
:target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard
:alt: Code quality: Codacy
.. image:: https://results.pre-commit.ci/badge/github/python-telegram-bot/python-telegram-bot/master.svg
:target: https://results.pre-commit.ci/latest/github/python-telegram-bot/python-telegram-bot/master
:alt: pre-commit.ci status
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
:alt: Code Style: Black
.. image:: https://img.shields.io/badge/Telegram-Channel-blue.svg?logo=telegram
:target: https://t.me/pythontelegrambotchannel
:alt: Telegram Channel
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram
:target: https://telegram.me/pythontelegrambotgroup
:alt: Telegram Group
⚠️ Deprecation Notice
=====================
The ``python-telegram-bot-raw`` library will no longer be updated after 21.3.
Please instead use the ``python-telegram-bot`` `library <https://pypi.org/python-telegram-bot>`_.
The change requires no changes in your code and requires no additional dependencies.
For additional information, please see this `channel post <https://t.me/pythontelegrambotchannel/145>`_.
----
We have made you a wrapper you can't refuse
We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us!
*Stay tuned for library updates and new releases on our* `Telegram Channel <https://telegram.me/pythontelegrambotchannel>`_.
Introduction
============
This library provides a pure Python, asynchronous interface for the
`Telegram Bot API <https://core.telegram.org/bots/api>`_.
It's compatible with Python versions **3.8+**.
``python-telegram-bot-raw`` is part of the `python-telegram-bot <https://python-telegram-bot.org>`_ ecosystem and provides the pure API functionality extracted from PTB. It therefore does not have independent release schedules, changelogs or documentation.
Note
----
Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conjunction will result in undesired side-effects, so only install *one* of both.
Telegram API support
====================
All types and methods of the Telegram Bot API **7.4** are supported.
Installing
==========
You can install or upgrade ``python-telegram-bot`` via
.. code:: shell
$ pip install python-telegram-bot-raw --upgrade
To install a pre-release, use the ``--pre`` `flag <https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-pre>`_ in addition.
You can also install ``python-telegram-bot-raw`` from source, though this is usually not necessary.
.. code:: shell
$ git clone https://github.com/python-telegram-bot/python-telegram-bot
$ cd python-telegram-bot
$ python setup_raw.py install
Note
----
Installing the ``.tar.gz`` archive available on PyPi directly via ``pip`` will *not* work as expected, as ``pip`` does not recognize that it should use ``setup_raw.py`` instead of ``setup.py``.
Verifying Releases
------------------
We sign all the releases with a GPG key.
The signatures are uploaded to both the `GitHub releases page <https://github.com/python-telegram-bot/python-telegram-bot/releases>`_ and the `PyPI project <https://pypi.org/project/python-telegram-bot/>`_ and end with a suffix ``.asc``.
Please find the public keys `here <https://github.com/python-telegram-bot/python-telegram-bot/tree/master/public_keys>`_.
The keys are named in the format ``<first_version>-<last_version>.gpg`` or ``<first_version>-current.gpg`` if the key is currently being used for new releases.
In addition, the GitHub release page also contains the sha1 hashes of the release files in the files with the suffix ``.sha1``.
This allows you to verify that a release file that you downloaded was indeed provided by the ``python-telegram-bot`` team.
Dependencies & Their Versions
-----------------------------
``python-telegram-bot`` tries to use as few 3rd party dependencies as possible.
However, for some features using a 3rd party library is more sane than implementing the functionality again.
As these features are *optional*, the corresponding 3rd party dependencies are not installed by default.
Instead, they are listed as optional dependencies.
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
The only required dependency is `httpx ~= 0.27 <https://www.python-httpx.org>`_ for
``telegram.request.HTTPXRequest``, the default networking backend.
``python-telegram-bot`` is most useful when used along with additional libraries.
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
On the other hand, we have to ensure stability of ``python-telegram-bot``, which is why we do apply version bounds.
If you encounter dependency conflicts due to these bounds, feel free to reach out.
Optional Dependencies
#####################
PTB can be installed with optional dependencies:
* ``pip install "python-telegram-bot-raw[passport]"`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
* ``pip install "python-telegram-bot-raw[socks]"`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
* ``pip install "python-telegram-bot-raw[http2]"`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
To install multiple optional dependencies, separate them by commas, e.g. ``pip install "python-telegram-bot-raw[passport,socks]"``.
Additionally, the shortcut ``pip install "python-telegram-bot-raw[all]"`` installs all optional dependencies.
Quick Start
===========
Our Wiki contains an `Introduction to the API <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API>`_ explaining how the pure Bot API can be accessed via ``python-telegram-bot``.
Resources
=========
- The `package documentation <https://docs.python-telegram-bot.org/>`_ is the technical reference for ``python-telegram-bot``.
It contains descriptions of all available classes, modules, methods and arguments as well as the `changelog <https://docs.python-telegram-bot.org/changelog.html>`_.
- The `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ is home to number of more elaborate introductions of the different features of ``python-telegram-bot`` and other useful resources that go beyond the technical documentation.
- Our `examples section <https://docs.python-telegram-bot.org/examples.html>`_ contains several examples that showcase the different features of both the Bot API and ``python-telegram-bot``.
Even if it is not your approach for learning, please take a look at ``echobot.py``. It is the de facto base for most of the bots out there.
The code for these examples is released to the public domain, so you can start by grabbing the code and building on top of it.
- The `official Telegram Bot API documentation <https://core.telegram.org/bots/api>`_ is of course always worth a read.
Getting help
============
If the resources mentioned above don't answer your questions or simply overwhelm you, there are several ways of getting help.
1. We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us! Asking a question here is often the quickest way to get a pointer in the right direction.
2. Ask questions by opening `a discussion <https://github.com/python-telegram-bot/python-telegram-bot/discussions/new>`_.
3. You can even ask for help on Stack Overflow using the `python-telegram-bot tag <https://stackoverflow.com/questions/tagged/python-telegram-bot>`_.
Concurrency
===========
Since v20.0, ``python-telegram-bot`` is built on top of Pythons ``asyncio`` module.
Because ``asyncio`` is in general single-threaded, ``python-telegram-bot`` does currently not aim to be thread-safe.
Contributing
============
Contributions of all sizes are welcome.
Please review our `contribution guidelines <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst>`_ to get started.
You can also help by `reporting bugs or feature requests <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_.
Donating
========
Occasionally we are asked if we accept donations to support the development.
While we appreciate the thought, maintaining PTB is our hobby, and we have almost no running costs for it. We therefore have nothing set up to accept donations.
If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead.
License
=======
You may copy, distribute and modify the software provided that modifications are described and licensed for free under `LGPL-3 <https://www.gnu.org/licenses/lgpl-3.0.html>`_.
Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be.
+204 -227
View File
@@ -1,6 +1,6 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -16,17 +16,55 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import collections.abc
import contextlib
import inspect
import re
import typing
from collections import defaultdict
from typing import Any, Iterator, Union
from collections.abc import Iterator
from socket import socket
from types import FunctionType
from typing import Union
from apscheduler.job import Job as APSJob
import telegram
import telegram._utils.defaultvalue
import telegram._utils.types
import telegram.ext
import telegram.ext._utils.types
from tests.auxil.slots import mro_slots
# Define the namespace for type resolution. This helps dealing with the internal imports that
# we do in many places
# The .copy() is important to avoid modifying the original namespace
TG_NAMESPACE = vars(telegram).copy()
TG_NAMESPACE.update(vars(telegram._utils.types))
TG_NAMESPACE.update(vars(telegram._utils.defaultvalue))
TG_NAMESPACE.update(vars(telegram.ext))
TG_NAMESPACE.update(vars(telegram.ext._utils.types))
TG_NAMESPACE.update(vars(telegram.ext._applicationbuilder))
TG_NAMESPACE.update({"socket": socket, "APSJob": APSJob})
def _iter_own_public_methods(cls: type) -> Iterator[tuple[str, type]]:
class PublicMethod(typing.NamedTuple):
name: str
method: FunctionType
def _is_inherited_method(cls: type, method_name: str) -> bool:
"""Checks if a method is inherited from a parent class.
Inheritance is not considered if the parent class is private.
Recurses through all direcot or indirect parent classes.
"""
# The [1:] slice is used to exclude the class itself from the MRO.
for base in cls.__mro__[1:]:
if method_name in base.__dict__ and not base.__name__.startswith("_"):
return True
return False
def _iter_own_public_methods(cls: type) -> Iterator[PublicMethod]:
"""Iterates over methods of a class that are not protected/private,
not camelCase and not inherited from the parent class.
@@ -34,13 +72,15 @@ def _iter_own_public_methods(cls: type) -> Iterator[tuple[str, type]]:
This function is defined outside the class because it is used to create class constants.
"""
return (
m
for m in inspect.getmembers(cls, predicate=inspect.isfunction) # not .ismethod
if not m[0].startswith("_")
and m[0].islower() # to avoid camelCase methods
and m[0] in cls.__dict__ # method is not inherited from parent class
)
# Use .isfunction() instead of .ismethod() because we want to include static methods.
for m in inspect.getmembers(cls, predicate=inspect.isfunction):
if (
not m[0].startswith("_")
and m[0].islower() # to avoid camelCase methods
and not _is_inherited_method(cls, m[0])
):
yield PublicMethod(m[0], m[1])
class AdmonitionInserter:
@@ -57,18 +97,12 @@ class AdmonitionInserter:
start and end markers.
"""
FORWARD_REF_SKIP_PATTERN = re.compile(r"^ForwardRef\('DefaultValue\[\w+]'\)$")
"""A pattern that will be used to skip known ForwardRef's that need not be resolved
to a Telegram class, e.g.:
ForwardRef('DefaultValue[None]')
ForwardRef('DefaultValue[DVValueType]')
"""
METHOD_NAMES_FOR_BOT_AND_APPBUILDER: typing.ClassVar[dict[type, str]] = {
cls: tuple(m[0] for m in _iter_own_public_methods(cls)) # m[0] means we take only names
for cls in (telegram.Bot, telegram.ext.ApplicationBuilder)
METHOD_NAMES_FOR_BOT_APP_APPBUILDER: typing.ClassVar[dict[type, str]] = {
cls: tuple(m.name for m in _iter_own_public_methods(cls))
for cls in (telegram.Bot, telegram.ext.ApplicationBuilder, telegram.ext.Application)
}
"""A dictionary mapping Bot and ApplicationBuilder classes to their relevant methods that will
"""A dictionary mapping Bot, Application & ApplicationBuilder classes to their relevant methods
that will
be mentioned in 'Returned in' and 'Use in' admonitions in other classes' docstrings.
Methods must be public, not aliases, not inherited from TelegramObject.
"""
@@ -82,13 +116,20 @@ class AdmonitionInserter:
"""Dictionary with admonitions. Contains sub-dictionaries, one per admonition type.
Each sub-dictionary matches bot methods (for "Shortcuts") or telegram classes (for other
admonition types) to texts of admonitions, e.g.:
```
{
"use_in": {<class 'telegram._chatinvitelink.ChatInviteLink'>:
<"Use in" admonition for ChatInviteLink>, ...},
"available_in": {<class 'telegram._chatinvitelink.ChatInviteLink'>:
<"Available in" admonition">, ...},
"returned_in": {...}
"use_in": {
<class 'telegram._chatinvitelink.ChatInviteLink'>:
<"Use in" admonition for ChatInviteLink>,
...
},
"available_in": {
<class 'telegram._chatinvitelink.ChatInviteLink'>:
<"Available in" admonition">,
...
},
"returned_in": {...}
}
```
"""
@@ -127,34 +168,6 @@ class AdmonitionInserter:
# i.e. {telegram._files.sticker.Sticker: {":attr:`telegram.Message.sticker`", ...}}
attrs_for_class = defaultdict(set)
# The following regex is supposed to capture a class name in a line like this:
# media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
#
# Note that even if such typing description spans over multiple lines but each line ends
# with a backslash (otherwise Sphinx will throw an error)
# (e.g. EncryptedPassportElement.data), then Sphinx will combine these lines into a single
# line automatically, and it will contain no backslash (only some extra many whitespaces
# from the indentation).
attr_docstr_pattern = re.compile(
r"^\s*(?P<attr_name>[a-z_]+)" # Any number of spaces, named group for attribute
r"\s?\(" # Optional whitespace, opening parenthesis
r".*" # Any number of characters (that could denote a built-in type)
r":class:`.+`" # Marker of a classref, class name in backticks
r".*\):" # Any number of characters, closing parenthesis, colon.
# The ^ colon above along with parenthesis is important because it makes sure that
# the class is mentioned in the attribute description, not in free text.
r".*$", # Any number of characters, end of string (end of line)
re.VERBOSE,
)
# for properties: there is no attr name in docstring. Just check if there's a class name.
prop_docstring_pattern = re.compile(r":class:`.+`.*:")
# pattern for iterating over potentially many class names in docstring for one attribute.
# Tilde is optional (sometimes it is in the docstring, sometimes not).
single_class_name_pattern = re.compile(r":class:`~?(?P<class_name>[\w.]*)`")
classes_to_inspect = inspect.getmembers(telegram, inspect.isclass) + inspect.getmembers(
telegram.ext, inspect.isclass
)
@@ -165,40 +178,31 @@ class AdmonitionInserter:
# docstrings.
name_of_inspected_class_in_docstr = self._generate_class_name_for_link(inspected_class)
# Parsing part of the docstring with attributes (parsing of properties follows later)
docstring_lines = inspect.getdoc(inspected_class).splitlines()
lines_with_attrs = []
for idx, line in enumerate(docstring_lines):
if line.strip() == "Attributes:":
lines_with_attrs = docstring_lines[idx + 1 :]
break
# Writing to dictionary: matching the class found in the type hint
# and its subclasses to the attribute of the class being inspected.
# The class in the attribute typehint (or its subclass) is the key,
# ReST link to attribute of the class currently being inspected is the value.
for line in lines_with_attrs:
if not (line_match := attr_docstr_pattern.match(line)):
continue
target_attr = line_match.group("attr_name")
# a typing description of one attribute can contain multiple classes
for match in single_class_name_pattern.finditer(line):
name_of_class_in_attr = match.group("class_name")
# Writing to dictionary: matching the class found in the docstring
# and its subclasses to the attribute of the class being inspected.
# The class in the attribute docstring (or its subclass) is the key,
# ReST link to attribute of the class currently being inspected is the value.
try:
self._resolve_arg_and_add_link(
arg=name_of_class_in_attr,
dict_of_methods_for_class=attrs_for_class,
link=f":attr:`{name_of_inspected_class_in_docstr}.{target_attr}`",
)
except NotImplementedError as e:
raise NotImplementedError(
"Error generating Sphinx 'Available in' admonition "
f"(admonition_inserter.py). Class {name_of_class_in_attr} present in "
f"attribute {target_attr} of class {name_of_inspected_class_in_docstr}"
f" could not be resolved. {e!s}"
) from e
# best effort - args of __init__ means not all attributes are covered, but there is no
# other way to get type hints of all attributes, other than doing ast parsing maybe.
# (Docstring parsing was discontinued with the closing of #4414)
type_hints = typing.get_type_hints(inspected_class.__init__, localns=TG_NAMESPACE)
class_attrs = [slot for slot in mro_slots(inspected_class) if not slot.startswith("_")]
for target_attr in class_attrs:
try:
self._resolve_arg_and_add_link(
dict_of_methods_for_class=attrs_for_class,
link=f":attr:`{name_of_inspected_class_in_docstr}.{target_attr}`",
type_hints={target_attr: type_hints.get(target_attr)},
resolve_nested_type_vars=False,
)
except NotImplementedError as e:
raise NotImplementedError(
"Error generating Sphinx 'Available in' admonition "
f"(admonition_inserter.py). Class {inspected_class} present in "
f"attribute {target_attr} of class {name_of_inspected_class_in_docstr}"
f" could not be resolved. {e!s}"
) from e
# Properties need to be parsed separately because they act like attributes but not
# listed as attributes.
@@ -209,39 +213,29 @@ class AdmonitionInserter:
if prop_name not in inspected_class.__dict__:
continue
# 1. Can't use typing.get_type_hints because double-quoted type hints
# (like "Application") will throw a NameError
# 2. Can't use inspect.signature because return annotations of properties can be
# hard to parse (like "(self) -> BD").
# 3. fget is used to access the actual function under the property wrapper
docstring = inspect.getdoc(getattr(inspected_class, prop_name).fget)
if docstring is None:
continue
# fget is used to access the actual function under the property wrapper
type_hints = typing.get_type_hints(
getattr(inspected_class, prop_name).fget, localns=TG_NAMESPACE
)
first_line = docstring.splitlines()[0]
if not prop_docstring_pattern.match(first_line):
continue
for match in single_class_name_pattern.finditer(first_line):
name_of_class_in_prop = match.group("class_name")
# Writing to dictionary: matching the class found in the docstring and its
# subclasses to the property of the class being inspected.
# The class in the property docstring (or its subclass) is the key,
# ReST link to property of the class currently being inspected is the value.
try:
self._resolve_arg_and_add_link(
arg=name_of_class_in_prop,
dict_of_methods_for_class=attrs_for_class,
link=f":attr:`{name_of_inspected_class_in_docstr}.{prop_name}`",
)
except NotImplementedError as e:
raise NotImplementedError(
"Error generating Sphinx 'Available in' admonition "
f"(admonition_inserter.py). Class {name_of_class_in_prop} present in "
f"property {prop_name} of class {name_of_inspected_class_in_docstr}"
f" could not be resolved. {e!s}"
) from e
# Writing to dictionary: matching the class found in the docstring and its
# subclasses to the property of the class being inspected.
# The class in the property docstring (or its subclass) is the key,
# ReST link to property of the class currently being inspected is the value.
try:
self._resolve_arg_and_add_link(
dict_of_methods_for_class=attrs_for_class,
link=f":attr:`{name_of_inspected_class_in_docstr}.{prop_name}`",
type_hints={prop_name: type_hints.get("return")},
resolve_nested_type_vars=False,
)
except NotImplementedError as e:
raise NotImplementedError(
"Error generating Sphinx 'Available in' admonition "
f"(admonition_inserter.py). Class {inspected_class} present in "
f"property {prop_name} of class {name_of_inspected_class_in_docstr}"
f" could not be resolved. {e!s}"
) from e
return self._generate_admonitions(attrs_for_class, admonition_type="available_in")
@@ -249,29 +243,28 @@ class AdmonitionInserter:
"""Creates a dictionary with 'Returned in' admonitions for classes that are returned
in Bot's and ApplicationBuilder's methods.
"""
# Generate a mapping of classes to ReST links to Bot methods which return it,
# i.e. {<class 'telegram._message.Message'>: {:meth:`telegram.Bot.send_message`, ...}}
methods_for_class = defaultdict(set)
for cls, method_names in self.METHOD_NAMES_FOR_BOT_AND_APPBUILDER.items():
for cls, method_names in self.METHOD_NAMES_FOR_BOT_APP_APPBUILDER.items():
for method_name in method_names:
sig = inspect.signature(getattr(cls, method_name))
ret_annot = sig.return_annotation
method_link = self._generate_link_to_method(method_name, cls)
arg = getattr(cls, method_name)
ret_type_hint = typing.get_type_hints(arg, localns=TG_NAMESPACE)
try:
self._resolve_arg_and_add_link(
arg=ret_annot,
dict_of_methods_for_class=methods_for_class,
link=method_link,
type_hints={"return": ret_type_hint.get("return")},
resolve_nested_type_vars=False,
)
except NotImplementedError as e:
raise NotImplementedError(
"Error generating Sphinx 'Returned in' admonition "
f"(admonition_inserter.py). {cls}, method {method_name}. "
f"Couldn't resolve type hint in return annotation {ret_annot}. {e!s}"
f"Couldn't resolve type hint in return annotation {ret_type_hint}. {e!s}"
) from e
return self._generate_admonitions(methods_for_class, admonition_type="returned_in")
@@ -298,8 +291,13 @@ class AdmonitionInserter:
# inspect methods of all telegram classes for return statements that indicate
# that this given method is a shortcut for a Bot method
for _class_name, cls in inspect.getmembers(telegram, predicate=inspect.isclass):
# no need to inspect Bot's own methods, as Bot can't have shortcuts in Bot
if not cls.__module__.startswith("telegram"):
# For some reason inspect.getmembers() also yields some classes that are
# imported in the namespace but not part of the telegram module.
continue
if cls is telegram.Bot:
# no need to inspect Bot's own methods, as Bot can't have shortcuts in Bot
continue
for method_name, method in _iter_own_public_methods(cls):
@@ -309,9 +307,7 @@ class AdmonitionInserter:
continue
bot_method = getattr(telegram.Bot, bot_method_match.group())
link_to_shortcut_method = self._generate_link_to_method(method_name, cls)
shortcuts_for_bot_method[bot_method].add(link_to_shortcut_method)
return self._generate_admonitions(shortcuts_for_bot_method, admonition_type="shortcuts")
@@ -326,26 +322,24 @@ class AdmonitionInserter:
# {:meth:`telegram.Bot.answer_inline_query`, ...}}
methods_for_class = defaultdict(set)
for cls, method_names in self.METHOD_NAMES_FOR_BOT_AND_APPBUILDER.items():
for cls, method_names in self.METHOD_NAMES_FOR_BOT_APP_APPBUILDER.items():
for method_name in method_names:
method_link = self._generate_link_to_method(method_name, cls)
sig = inspect.signature(getattr(cls, method_name))
parameters = sig.parameters
for param in parameters.values():
try:
self._resolve_arg_and_add_link(
arg=param.annotation,
dict_of_methods_for_class=methods_for_class,
link=method_link,
)
except NotImplementedError as e:
raise NotImplementedError(
"Error generating Sphinx 'Use in' admonition "
f"(admonition_inserter.py). {cls}, method {method_name}, parameter "
f"{param}: Couldn't resolve type hint {param.annotation}. {e!s}"
) from e
arg = getattr(cls, method_name)
param_type_hints = typing.get_type_hints(arg, localns=TG_NAMESPACE)
param_type_hints.pop("return", None)
try:
self._resolve_arg_and_add_link(
dict_of_methods_for_class=methods_for_class,
link=method_link,
type_hints=param_type_hints,
)
except NotImplementedError as e:
raise NotImplementedError(
"Error generating Sphinx 'Use in' admonition "
f"(admonition_inserter.py). {cls}, method {method_name}, parameter "
) from e
return self._generate_admonitions(methods_for_class, admonition_type="use_in")
@@ -361,11 +355,12 @@ class AdmonitionInserter:
for idx, value in list(enumerate(lines)):
if value.startswith(
(
".. seealso:",
# ".. seealso:",
# The docstring contains heading "Examples:", but Sphinx will have it converted
# to ".. admonition: Examples":
".. admonition:: Examples",
".. version",
"Args:",
# The space after ":param" is important because docstring can contain
# ":paramref:" in its plain text in the beginning of a line (e.g. ExtBot):
":param ",
@@ -433,12 +428,12 @@ class AdmonitionInserter:
return admonition_for_class
@staticmethod
def _generate_class_name_for_link(cls: type) -> str:
def _generate_class_name_for_link(cls_: type) -> str:
"""Generates class name that can be used in a ReST link."""
# Check for potential presence of ".ext.", we will need to keep it.
ext = ".ext" if ".ext." in str(cls) else ""
return f"telegram{ext}.{cls.__name__}"
ext = ".ext" if ".ext." in str(cls_) else ""
return f"telegram{ext}.{cls_.__name__}"
def _generate_link_to_method(self, method_name: str, cls: type) -> str:
"""Generates a ReST link to a method of a telegram class."""
@@ -446,19 +441,22 @@ class AdmonitionInserter:
return f":meth:`{self._generate_class_name_for_link(cls)}.{method_name}`"
@staticmethod
def _iter_subclasses(cls: type) -> Iterator:
def _iter_subclasses(cls_: type) -> Iterator:
if not hasattr(cls_, "__subclasses__") or cls_ is telegram.TelegramObject:
return iter([])
return (
# exclude private classes
c
for c in cls.__subclasses__()
for c in cls_.__subclasses__()
if not str(c).split(".")[-1].startswith("_")
)
def _resolve_arg_and_add_link(
self,
arg: Any,
dict_of_methods_for_class: defaultdict,
link: str,
type_hints: dict[str, type],
resolve_nested_type_vars: bool = True,
) -> None:
"""A helper method. Tries to resolve the arg into a valid class. In case of success,
adds the link (to a method, attribute, or property) for that class' and its subclasses'
@@ -466,7 +464,9 @@ class AdmonitionInserter:
**Modifies dictionary in place.**
"""
for cls in self._resolve_arg(arg):
type_hints.pop("self", None)
for cls in self._resolve_arg(type_hints, resolve_nested_type_vars):
# When trying to resolve an argument from args or return annotation,
# the method _resolve_arg returns None if nothing could be resolved.
# Also, if class was resolved correctly, "telegram" will definitely be in its str().
@@ -478,88 +478,67 @@ class AdmonitionInserter:
for subclass in self._iter_subclasses(cls):
dict_of_methods_for_class[subclass].add(link)
def _resolve_arg(self, arg: Any) -> Iterator[Union[type, None]]:
def _resolve_arg(
self,
type_hints: dict[str, type],
resolve_nested_type_vars: bool,
) -> list[type]:
"""Analyzes an argument of a method and recursively yields classes that the argument
or its sub-arguments (in cases like Union[...]) belong to, if they can be resolved to
telegram or telegram.ext classes.
Args:
type_hints: A dictionary of argument names and their types.
resolve_nested_type_vars: If True, nested type variables (like Application[BT, ])
will be resolved to their actual classes. If False, only the outermost type
variable will be resolved. *Only* affects ptb classes, not built-in types.
Useful for checking the return type of methods, where nested type variables
are not really useful.
Raises `NotImplementedError`.
"""
origin = typing.get_origin(arg)
def _is_ptb_class(cls: type) -> bool:
if not hasattr(cls, "__module__"):
return False
return cls.__module__.startswith("telegram")
if (
origin in (collections.abc.Callable, typing.IO)
or arg is None
# no other check available (by type or origin) for these:
or str(type(arg)) in ("<class 'typing._SpecialForm'>", "<class 'ellipsis'>")
):
pass
# will be edited in place
telegram_classes = set()
# RECURSIVE CALLS
# for cases like Union[Sequence....
elif origin in (
Union,
collections.abc.Coroutine,
collections.abc.Sequence,
):
for sub_arg in typing.get_args(arg):
yield from self._resolve_arg(sub_arg)
def recurse_type(type_, is_recursed_from_ptb_class: bool):
next_is_recursed_from_ptb_class = is_recursed_from_ptb_class or _is_ptb_class(type_)
elif isinstance(arg, typing.TypeVar):
# gets access to the "bound=..." parameter
yield from self._resolve_arg(arg.__bound__)
# END RECURSIVE CALLS
if hasattr(type_, "__origin__"): # For generic types like Union, List, etc.
# Make sure it's not a telegram.ext generic type (e.g. ContextTypes[...])
org = typing.get_origin(type_)
if "telegram.ext" in str(org):
telegram_classes.add(org)
elif isinstance(arg, typing.ForwardRef):
m = self.FORWARD_REF_PATTERN.match(str(arg))
# We're sure it's a ForwardRef, so, unless it belongs to known exceptions,
# the class must be resolved.
# If it isn't resolved, we'll have the program throw an exception to be sure.
try:
cls = self._resolve_class(m.group("class_name"))
except AttributeError as exc:
# skip known ForwardRef's that need not be resolved to a Telegram class
if self.FORWARD_REF_SKIP_PATTERN.match(str(arg)):
pass
else:
raise NotImplementedError(f"Could not process ForwardRef: {arg}") from exc
else:
yield cls
args = typing.get_args(type_)
for arg in args:
recurse_type(arg, next_is_recursed_from_ptb_class)
elif isinstance(type_, typing.TypeVar) and (
resolve_nested_type_vars or not is_recursed_from_ptb_class
):
# gets access to the "bound=..." parameter
recurse_type(type_.__bound__, next_is_recursed_from_ptb_class)
elif inspect.isclass(type_) and "telegram" in inspect.getmodule(type_).__name__:
telegram_classes.add(type_)
elif isinstance(type_, typing.ForwardRef):
# Resolving ForwardRef is not easy. https://peps.python.org/pep-0749/ will
# hopefully make it better by introducing typing.resolve_forward_ref() in py3.14
# but that's not there yet
# So for now we fall back to a best effort approach of guessing if the class is
# available in tg or tg.ext
with contextlib.suppress(AttributeError):
telegram_classes.add(self._resolve_class(type_.__forward_arg__))
# For custom generics like telegram.ext._application.Application[~BT, ~CCT, ~UD...].
# This must come before the check for isinstance(type) because GenericAlias can also be
# recognized as type if it belongs to <class 'types.GenericAlias'>.
elif str(type(arg)) in (
"<class 'typing._GenericAlias'>",
"<class 'types.GenericAlias'>",
"<class 'typing._LiteralGenericAlias'>",
):
if "telegram" in str(arg):
# get_origin() of telegram.ext._application.Application[~BT, ~CCT, ~UD...]
# will produce <class 'telegram.ext._application.Application'>
yield origin
for type_hint in type_hints.values():
if type_hint is not None:
recurse_type(type_hint, False)
elif isinstance(arg, type):
if "telegram" in str(arg):
yield arg
# For some reason "InlineQueryResult", "InputMedia" & some others are currently not
# recognized as ForwardRefs and are identified as plain strings.
elif isinstance(arg, str):
# args like "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]" can be recognized as strings.
# Remove whatever is in the square brackets because it doesn't need to be parsed.
arg = re.sub(r"\[.+]", "", arg)
cls = self._resolve_class(arg)
# Here we don't want an exception to be thrown since we're not sure it's ForwardRef
if cls is not None:
yield cls
else:
raise NotImplementedError(
f"Cannot process argument {arg} of type {type(arg)} (origin {origin})"
)
return list(telegram_classes)
@staticmethod
def _resolve_class(name: str) -> Union[type, None]:
@@ -579,16 +558,14 @@ class AdmonitionInserter:
f"telegram.ext.{name}",
f"telegram.ext.filters.{name}",
):
try:
return eval(option)
# NameError will be raised if trying to eval just name and it doesn't work, e.g.
# "Name 'ApplicationBuilder' is not defined".
# AttributeError will be raised if trying to e.g. eval f"telegram.{name}" when the
# class denoted by `name` actually belongs to `telegram.ext`:
# "module 'telegram' has no attribute 'ApplicationBuilder'".
# If neither option works, this is not a PTB class.
except (NameError, AttributeError):
continue
with contextlib.suppress(NameError, AttributeError):
return eval(option)
return None
+2 -3
View File
@@ -1,6 +1,6 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,6 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import inspect
from typing import List
keyword_args = [
"Keyword Arguments:",
@@ -85,7 +84,7 @@ get_updates_read_timeout_addition = [
]
def find_insert_pos_for_kwargs(lines: List[str]) -> int:
def find_insert_pos_for_kwargs(lines: list[str]) -> int:
"""Finds the correct position to insert the keyword arguments and returns the index."""
for idx, value in reversed(list(enumerate(lines))): # reversed since :returns: is at the end
if value.startswith("Returns"):
+2 -3
View File
@@ -1,6 +1,6 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -21,7 +21,6 @@ https://github.com/sphinx-doc/sphinx/issues/1556 is closed
"""
import subprocess
from pathlib import Path
from typing import Dict, Tuple
from sphinx.util import logging
@@ -32,7 +31,7 @@ sphinx_logger = logging.getLogger(__name__)
# must be a module-level variable so that it can be written to by the `autodoc-process-docstring`
# event handler in `sphinx_hooks.py`
LINE_NUMBERS: Dict[str, Tuple[Path, int, int]] = {}
LINE_NUMBERS: dict[str, tuple[Path, int, int]] = {}
def _git_branch() -> str:
+8 -4
View File
@@ -1,6 +1,6 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -16,6 +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/].
import collections.abc
import contextlib
import inspect
import re
import typing
@@ -153,13 +154,11 @@ def autodoc_process_docstring(
if isinstance(obj, telegram.ext.filters.BaseFilter):
obj = obj.__class__
try:
with contextlib.suppress(Exception):
source_lines, start_line = inspect.getsourcelines(obj)
end_line = start_line + len(source_lines)
file = Path(inspect.getsourcefile(obj)).relative_to(FILE_ROOT)
LINE_NUMBERS[name] = (file, start_line, end_line)
except Exception:
pass
# Since we don't document the `__init__`, we call this manually to have it available for
# attributes -- see the note above
@@ -188,6 +187,11 @@ def autodoc_process_bases(app, name, obj, option, bases: list) -> None:
bases[idx] = ":class:`enum.IntEnum`"
continue
if "FloatEnum" in base:
bases[idx] = ":class:`enum.Enum`"
bases.insert(0, ":class:`float`")
continue
# Drop generics (at least for now)
if base.endswith("]"):
base = base.split("[", maxsplit=1)[0]
+5 -4
View File
@@ -1,6 +1,6 @@
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -15,7 +15,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/].
import datetime
import datetime as dtm
from enum import Enum
from docutils.nodes import Element
@@ -75,7 +75,7 @@ class TGConstXRefRole(PyXRefRole):
):
return str(value), target
if (
isinstance(value, datetime.datetime)
isinstance(value, dtm.datetime)
and value == telegram.constants.ZERO_DATE
and target in ("telegram.constants.ZERO_DATE",)
):
@@ -88,7 +88,6 @@ class TGConstXRefRole(PyXRefRole):
refnode.rawsource,
CONSTANTS_ROLE,
)
return title, target
except Exception as exc:
sphinx_logger.exception(
"%s:%d: WARNING: Did not convert reference %s due to an exception.",
@@ -98,3 +97,5 @@ class TGConstXRefRole(PyXRefRole):
exc_info=exc,
)
return title, target
else:
return title, target
+5 -3
View File
@@ -1,7 +1,9 @@
sphinx==7.3.7
furo==2024.5.6
sphinx==8.1.3
furo==2024.8.6
furo-sphinx-search @ git+https://github.com/harshil21/furo-sphinx-search@v0.2.0.1
sphinx-paramlinks==0.6.0
sphinxcontrib-mermaid==0.9.2
sphinxcontrib-mermaid==1.0.0
sphinx-copybutton==0.5.2
sphinx-inline-tabs==2023.4.21
# Temporary. See #4387
sphinx-build-compatibility @ git+https://github.com/readthedocs/sphinx-build-compatibility.git@58aabc5f207c6c2421f23d3578adc0b14af57047
+1 -1
View File
@@ -61,5 +61,5 @@
}
.admonition.returned-in > ul, .admonition.available-in > ul, .admonition.use-in > ul, .admonition.shortcuts > ul {
max-height: 200px;
overflow-y: scroll;
overflow-y: auto;
}
+20 -3
View File
@@ -1,3 +1,4 @@
import os
import re
import sys
from pathlib import Path
@@ -12,7 +13,7 @@ sys.path.insert(0, str(Path("../..").resolve().absolute()))
# -- General configuration ------------------------------------------------
# General information about the project.
project = "python-telegram-bot"
copyright = "2015-2024, Leandro Toledo"
copyright = "2015-2025, Leandro Toledo"
author = "Leandro Toledo"
# The version info for the project you're documenting, acts as replacement for
@@ -29,7 +30,7 @@ version = telegram.__version__
release = telegram.__version__
# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = "6.1.3"
needs_sphinx = "8.1.3"
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -47,6 +48,10 @@ extensions = [
"sphinx_search.extension",
]
# Temporary. See #4387
if os.environ.get("READTHEDOCS", "") == "True":
extensions.append("sphinx_build_compatibility.extension")
# For shorter links to Wiki in docstrings
extlinks = {
"wiki": ("https://github.com/python-telegram-bot/python-telegram-bot/wiki/%s", "%s"),
@@ -106,6 +111,11 @@ linkcheck_ignore = [
# Anchors are apparently inserted by GitHub dynamically, so let's skip checking them
"https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples#",
r"https://github\.com/python-telegram-bot/python-telegram-bot/wiki/[\w\-_,]+\#",
# The LGPL license link regularly causes network errors for some reason
re.escape("https://www.gnu.org/licenses/lgpl-3.0.html"),
# The doc-fixes branch may not always exist - doesn't matter, we only link to it from the
# contributing guide
re.escape("https://docs.python-telegram-bot.org/en/doc-fixes"),
]
linkcheck_allowed_redirects = {
# Redirects to the default version are okay
@@ -251,7 +261,14 @@ htmlhelp_basename = "python-telegram-bot-doc"
# The base URL which points to the root of the HTML documentation. It is used to indicate the
# location of document using The Canonical Link Relation. Default: ''.
html_baseurl = "https://docs.python-telegram-bot.org"
# Set canonical URL from the Read the Docs Domain
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
# Tell Jinja2 templates the build is running on Read the Docs
html_context = {}
if os.environ.get("READTHEDOCS", "") == "True":
html_context["READTHEDOCS"] = True
# -- Options for LaTeX output ---------------------------------------------
+55 -3
View File
@@ -25,6 +25,8 @@
- Used for sending documents
* - :meth:`~telegram.Bot.send_game`
- Used for sending a game
* - :meth:`~telegram.Bot.send_gift`
- Used for sending a gift
* - :meth:`~telegram.Bot.send_invoice`
- Used for sending an invoice
* - :meth:`~telegram.Bot.send_location`
@@ -33,6 +35,8 @@
- Used for sending media grouped together
* - :meth:`~telegram.Bot.send_message`
- Used for sending text messages
* - :meth:`~telegram.Bot.send_paid_media`
- Used for sending paid media to channels
* - :meth:`~telegram.Bot.send_photo`
- Used for sending photos
* - :meth:`~telegram.Bot.send_poll`
@@ -149,6 +153,8 @@
- Used for setting a chat title
* - :meth:`~telegram.Bot.set_chat_description`
- Used for setting the description of a chat
* - :meth:`~telegram.Bot.set_user_emoji_status`
- Used for setting the users status emoji
* - :meth:`~telegram.Bot.pin_chat_message`
- Used for pinning a message
* - :meth:`~telegram.Bot.unpin_chat_message`
@@ -177,6 +183,29 @@
</details>
<br>
.. raw:: html
<details>
<summary>Verification on behalf of an organization</summary>
.. list-table::
:align: left
:widths: 1 4
* - :meth:`~telegram.Bot.verify_chat`
- Used for verifying a chat
* - :meth:`~telegram.Bot.verify_user`
- Used for verifying a user
* - :meth:`~telegram.Bot.remove_chat_verification`
- Used for removing the verification from a chat
* - :meth:`~telegram.Bot.remove_user_verification`
- Used for removing the verification from a user
.. raw:: html
</details>
<br>
.. raw:: html
<details>
@@ -353,7 +382,7 @@
.. raw:: html
<details>
<summary>Miscellaneous</summary>
<summary>Payments and Stars</summary>
.. list-table::
:align: left
@@ -361,16 +390,39 @@
* - :meth:`~telegram.Bot.create_invoice_link`
- Used to generate an HTTP link for an invoice
* - :meth:`~telegram.Bot.edit_user_star_subscription`
- Used for editing a user's star subscription
* - :meth:`~telegram.Bot.get_star_transactions`
- Used for obtaining the bot's Telegram Stars transactions
* - :meth:`~telegram.Bot.refund_star_payment`
- Used for refunding a payment in Telegram Stars
.. raw:: html
</details>
<br>
.. raw:: html
<details>
<summary>Miscellaneous</summary>
.. list-table::
:align: left
:widths: 1 4
* - :meth:`~telegram.Bot.close`
- Used for closing server instance when switching to another local server
* - :meth:`~telegram.Bot.log_out`
- Used for logging out from cloud Bot API server
* - :meth:`~telegram.Bot.get_file`
- Used for getting basic info about a file
* - :meth:`~telegram.Bot.get_available_gifts`
- Used for getting information about gifts available for sending
* - :meth:`~telegram.Bot.get_me`
- Used for getting basic information about the bot
* - :meth:`~telegram.Bot.refund_star_payment`
- Used for refunding a payment in Telegram Stars
* - :meth:`~telegram.Bot.save_prepared_inline_message`
- Used for storing a message to be sent by a user of a Mini App
.. raw:: html
+12
View File
@@ -3,6 +3,18 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
.. raw:: html
<div style="display: none">
Hidden Headline
===============
This is just here to get furo to display the right sidebar.
.. raw:: html
</div>
.. include:: ../../README.rst
.. The toctrees are hidden such that they don't render on the start page but still include the contents into the documentation.
+6
View File
@@ -0,0 +1,6 @@
AffiliateInfo
=============
.. autoclass:: telegram.AffiliateInfo
:members:
:show-inheritance:
+11 -1
View File
@@ -29,6 +29,7 @@ Available Types
telegram.chat
telegram.chatadministratorrights
telegram.chatbackground
telegram.copytextbutton
telegram.backgroundtype
telegram.backgroundtypefill
telegram.backgroundtypewallpaper
@@ -88,8 +89,10 @@ Available Types
telegram.inputmediadocument
telegram.inputmediaphoto
telegram.inputmediavideo
telegram.inputpaidmedia
telegram.inputpaidmediaphoto
telegram.inputpaidmediavideo
telegram.inputpolloption
telegram.inputsticker
telegram.keyboardbutton
telegram.keyboardbuttonpolltype
telegram.keyboardbuttonrequestchat
@@ -113,6 +116,12 @@ Available Types
telegram.messageoriginuser
telegram.messagereactioncountupdated
telegram.messagereactionupdated
telegram.paidmedia
telegram.paidmediainfo
telegram.paidmediaphoto
telegram.paidmediapreview
telegram.paidmediapurchased
telegram.paidmediavideo
telegram.photosize
telegram.poll
telegram.pollanswer
@@ -122,6 +131,7 @@ Available Types
telegram.reactiontype
telegram.reactiontypecustomemoji
telegram.reactiontypeemoji
telegram.reactiontypepaid
telegram.replykeyboardmarkup
telegram.replykeyboardremove
telegram.replyparameters
+1 -1
View File
@@ -5,5 +5,5 @@ telegram.constants Module
:members:
:show-inheritance:
:no-undoc-members:
:inherited-members: Enum, EnumMeta, str, int
:inherited-members: Enum, EnumMeta, str, int, float
:exclude-members: __format__, __new__, __repr__, __str__
+6
View File
@@ -0,0 +1,6 @@
CopyTextButton
==============
.. autoclass:: telegram.CopyTextButton
:members:
:show-inheritance:
@@ -18,6 +18,7 @@ Handlers
telegram.ext.inlinequeryhandler
telegram.ext.messagehandler
telegram.ext.messagereactionhandler
telegram.ext.paidmediapurchasedhandler
telegram.ext.pollanswerhandler
telegram.ext.pollhandler
telegram.ext.precheckoutqueryhandler
@@ -0,0 +1,6 @@
PaidMediaPurchasedHandler
=========================
.. autoclass:: telegram.ext.PaidMediaPurchasedHandler
:members:
:show-inheritance:
+15
View File
@@ -1,6 +1,21 @@
.. _games-tree:
Games
-----
Your bot can offer users **HTML5 games** to play solo or to compete against each other in groups and one-on-one chats. Create games via `@BotFather <https://telegram.me/BotFather>`_ using the ``/newgame`` command. Please note that this kind of power requires responsibility: you will need to accept the terms for each game that your bots will be offering.
* Games are a new type of content on Telegram, represented by the :class:`telegram.Game` and :class:`telegram.InlineQueryResultGame` objects.
* Once you've created a game via `BotFather <https://t.me/botfather>`_, you can send games to chats as regular messages using the :meth:`~telegram.Bot.sendGame` method, or use :ref:`inline mode <inline-tree>` with :class:`telegram.InlineQueryResultGame`.
* If you send the game message without any buttons, it will automatically have a 'Play ``GameName``' button. When this button is pressed, your bot gets a :class:`telegram.CallbackQuery` with the ``game_short_name`` of the requested game. You provide the correct URL for this particular user and the app opens the game in the in-app browser.
* You can manually add multiple buttons to your game message. Please note that the first button in the first row **must always** launch the game, using the field ``callback_game`` in :class:`telegram.InlineKeyboardButton`. You can add extra buttons according to taste: e.g., for a description of the rules, or to open the game's official community.
* To make your game more attractive, you can upload a GIF animation that demonstrates the game to the users via `BotFather <https://t.me/botfather>`_ (see `Lumberjack <https://t.me/gamebot?game=lumberjack>`_ for example).
* A game message will also display high scores for the current chat. Use :meth:`~telegram.Bot.setGameScore` to post high scores to the chat with the game, add the :paramref:`~telegram.Bot.set_game_score.disable_edit_message` parameter to disable automatic update of the message with the current scoreboard.
* Use :meth:`~telegram.Bot.getGameHighScores` to get data for in-game high score tables.
* You can also add an extra sharing button for users to share their best score to different chats.
* For examples of what can be done using this new stuff, check the `@gamebot <https://t.me/gamebot>`_ and `@gamee <https://t.me/gamee>`_ bots.
.. toctree::
:titlesonly:
+6
View File
@@ -0,0 +1,6 @@
Gift
====
.. autoclass:: telegram.Gift
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
Gifts
=====
.. autoclass:: telegram.Gifts
:members:
:show-inheritance:
+9
View File
@@ -1,6 +1,14 @@
.. _inline-tree:
Inline Mode
-----------
The following methods and objects allow your bot to work in `inline mode <https://core.telegram.org/bots/inline>`_.
Please see Telegrams `Introduction to Inline bots <https://core.telegram.org/bots/inline>`_ for more details.
To enable this option, send the ``/setinline`` command to `@BotFather <https://t.me/botfather>`_ and provide the placeholder text that the user will see in the input field after typing your bot's name.
.. toctree::
:titlesonly:
@@ -34,3 +42,4 @@ Inline Mode
telegram.inputvenuemessagecontent
telegram.inputcontactmessagecontent
telegram.inputinvoicemessagecontent
telegram.preparedinlinemessage
+6
View File
@@ -0,0 +1,6 @@
InputPaidMedia
==============
.. autoclass:: telegram.InputPaidMedia
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputPaidMediaPhoto
===================
.. autoclass:: telegram.InputPaidMediaPhoto
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
InputPaidMediaVideo
===================
.. autoclass:: telegram.InputPaidMediaVideo
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
PaidMedia
=========
.. autoclass:: telegram.PaidMedia
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
PaidMediaInfo
=============
.. autoclass:: telegram.PaidMediaInfo
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
PaidMediaPhoto
==============
.. autoclass:: telegram.PaidMediaPhoto
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
PaidMediaPreview
================
.. autoclass:: telegram.PaidMediaPreview
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
PaidMediaPurchased
==================
.. autoclass:: telegram.PaidMediaPurchased
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
PaidMediaVideo
==============
.. autoclass:: telegram.PaidMediaVideo
:members:
:show-inheritance:
+3
View File
@@ -1,6 +1,9 @@
Passport
--------
Passport is a unified authorization method for services that require personal identification. Users can upload their documents once, then instantly share their data with services that require real-world ID (finance, ICOs, etc.). Please see the `manual <https://core.telegram.org/passport>`_ for details.
.. toctree::
:titlesonly:
+21
View File
@@ -1,14 +1,35 @@
.. _payments-tree:
Payments
--------
Your bot can accept payments from Telegram users. Please see the `introduction to payments <https://core.telegram.org/bots/payments>`_ for more details on the process and how to set up payments for your bot.
.. toctree::
:titlesonly:
telegram.affiliateinfo
telegram.invoice
telegram.labeledprice
telegram.orderinfo
telegram.precheckoutquery
telegram.refundedpayment
telegram.revenuewithdrawalstate
telegram.revenuewithdrawalstatefailed
telegram.revenuewithdrawalstatepending
telegram.revenuewithdrawalstatesucceeded
telegram.shippingaddress
telegram.shippingoption
telegram.shippingquery
telegram.startransaction
telegram.startransactions
telegram.successfulpayment
telegram.transactionpartner
telegram.transactionpartneraffiliateprogram
telegram.transactionpartnerchat
telegram.transactionpartnerfragment
telegram.transactionpartnerother
telegram.transactionpartnertelegramads
telegram.transactionpartnertelegramapi
telegram.transactionpartneruser
@@ -0,0 +1,6 @@
PreparedInlineMessage
=====================
.. autoclass:: telegram.PreparedInlineMessage
:members:
:show-inheritance:
@@ -0,0 +1,6 @@
ReactionTypePaid
================
.. autoclass:: telegram.ReactionTypePaid
:members:
:show-inheritance:
+6
View File
@@ -0,0 +1,6 @@
RefundedPayment
===============
.. autoclass:: telegram.RefundedPayment
:members:
:show-inheritance:
@@ -0,0 +1,7 @@
RevenueWithdrawalState
======================
.. autoclass:: telegram.RevenueWithdrawalState
:members:
:show-inheritance:
:inherited-members: TelegramObject
@@ -0,0 +1,7 @@
RevenueWithdrawalStateFailed
=============================
.. autoclass:: telegram.RevenueWithdrawalStateFailed
:members:
:show-inheritance:
:inherited-members: TelegramObject
@@ -0,0 +1,7 @@
RevenueWithdrawalStatePending
=============================
.. autoclass:: telegram.RevenueWithdrawalStatePending
:members:
:show-inheritance:
:inherited-members: TelegramObject
@@ -0,0 +1,7 @@
RevenueWithdrawalStateSucceeded
===============================
.. autoclass:: telegram.RevenueWithdrawalStateSucceeded
:members:
:show-inheritance:
:inherited-members: TelegramObject
+7
View File
@@ -0,0 +1,7 @@
StarTransaction
===============
.. autoclass:: telegram.StarTransaction
:members:
:show-inheritance:
:inherited-members: TelegramObject
@@ -0,0 +1,8 @@
StarTransactions
================
.. autoclass:: telegram.StarTransactions
:members:
:show-inheritance:
:inherited-members: TelegramObject
+5
View File
@@ -1,9 +1,14 @@
Stickers
--------
The following methods and objects allow your bot to handle stickers and sticker sets.
.. toctree::
:titlesonly:
telegram.gift
telegram.gifts
telegram.inputsticker
telegram.maskposition
telegram.sticker
telegram.stickerset
@@ -0,0 +1,7 @@
TransactionPartner
==================
.. autoclass:: telegram.TransactionPartner
:members:
:show-inheritance:
:inherited-members: TelegramObject
@@ -0,0 +1,6 @@
TransactionPartnerAffiliateProgram
===================================
.. autoclass:: telegram.TransactionPartnerAffiliateProgram
:members:
:show-inheritance:
@@ -0,0 +1,7 @@
TransactionPartnerChat
======================
.. autoclass:: telegram.TransactionPartnerChat
:members:
:show-inheritance:
:inherited-members: TransactionPartner
@@ -0,0 +1,7 @@
TransactionPartnerFragment
==========================
.. autoclass:: telegram.TransactionPartnerFragment
:members:
:show-inheritance:
:inherited-members: TransactionPartner
@@ -0,0 +1,7 @@
TransactionPartnerOther
=======================
.. autoclass:: telegram.TransactionPartnerOther
:members:
:show-inheritance:
:inherited-members: TransactionPartner
@@ -0,0 +1,7 @@
TransactionPartnerTelegramAds
=============================
.. autoclass:: telegram.TransactionPartnerTelegramAds
:members:
:show-inheritance:
:inherited-members: TransactionPartner
@@ -0,0 +1,7 @@
TransactionPartnerTelegramApi
=============================
.. autoclass:: telegram.TransactionPartnerTelegramApi
:members:
:show-inheritance:
:inherited-members: TransactionPartner
@@ -0,0 +1,7 @@
TransactionPartnerUser
======================
.. autoclass:: telegram.TransactionPartnerUser
:members:
:show-inheritance:
:inherited-members: TransactionPartner
+15 -1
View File
@@ -16,6 +16,8 @@
.. |editreplymarkup| replace:: It is currently only possible to edit messages without :attr:`telegram.Message.reply_markup` or with inline keyboards.
.. |bcid_edit_time| replace:: Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within *48 hours* from the time they were sent.
.. |toapikwargsbase| replace:: These arguments are also considered by :meth:`~telegram.TelegramObject.to_dict` and :meth:`~telegram.TelegramObject.to_json`, i.e. when passing objects to Telegram. Passing them to Telegram is however not guaranteed to work for all kinds of objects, e.g. this will fail for objects that can not directly be JSON serialized.
.. |toapikwargsarg| replace:: Arbitrary keyword arguments. Can be used to store data for which there are no dedicated attributes. |toapikwargsbase|
@@ -58,10 +60,12 @@
.. |removed_thumb_note| replace:: Removed the deprecated argument and attribute ``thumb``.
.. |removed_thumb_url_note| replace:: Removed the deprecated argument and attribute ``thumb_url``.
.. |removed_thumb_url_note| replace:: Removed the deprecated argument and attribute ``thumb_url`` which made thumbnail_url mandatory.
.. |removed_thumb_wildcard_note| replace:: Removed the deprecated arguments and attributes ``thumb_*``.
.. |thumbnail_url_mandatory| replace:: Removal of the deprecated argument ``thumb_url`` made ``thumbnail_url`` mandatory.
.. |async_context_manager| replace:: Asynchronous context manager which
.. |reply_parameters| replace:: Description of the message to reply to.
@@ -82,8 +86,18 @@
.. |business_id_str| replace:: Unique identifier of the business connection on behalf of which the message will be sent.
.. |business_id_str_edit| replace:: Unique identifier of the business connection on behalf of which the message to be edited was sent
.. |message_effect_id| replace:: Unique identifier of the message effect to be added to the message; for private chats only.
.. |show_cap_above_med| replace:: :obj:`True`, if the caption must be shown above the message media.
.. |tg_stars| replace:: `Telegram Stars <https://t.me/BotNews/90>`__
.. |allow_paid_broadcast| replace:: Pass True to allow up to :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second, ignoring `broadcasting limits <https://core.telegram.org/bots/faq#how-can-i-message-all-of-my-bot-39s-subscribers-at-once>`__ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance.
.. |tz-naive-dtms| replace:: For timezone naive :obj:`datetime.datetime` objects, the default timezone of the bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used.
.. |org-verify| replace:: `on behalf of the organization <https://telegram.org/verify#third-party-verification>`__
.. |time-period-input| replace:: :class:`datetime.timedelta` objects are accepted in addition to plain :obj:`int` values.
+4 -4
View File
@@ -12,7 +12,7 @@ To use arbitrary callback data, you must install PTB via
`pip install "python-telegram-bot[callback-data]"`
"""
import logging
from typing import List, Tuple, cast
from typing import cast
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import (
@@ -36,7 +36,7 @@ logger = logging.getLogger(__name__)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Sends a message with 5 inline buttons attached."""
number_list: List[int] = []
number_list: list[int] = []
await update.message.reply_text("Please choose:", reply_markup=build_keyboard(number_list))
@@ -55,7 +55,7 @@ async def clear(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.effective_message.reply_text("All clear!")
def build_keyboard(current_list: List[int]) -> InlineKeyboardMarkup:
def build_keyboard(current_list: list[int]) -> InlineKeyboardMarkup:
"""Helper function to build the next inline keyboard."""
return InlineKeyboardMarkup.from_column(
[InlineKeyboardButton(str(i), callback_data=(i, current_list)) for i in range(1, 6)]
@@ -69,7 +69,7 @@ async def list_button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
# Get the data from the callback_data.
# If you're using a type checker like MyPy, you'll have to use typing.cast
# to make the checker get the expected type of the callback_data
number, number_list = cast(Tuple[int, List[int]], query.data)
number, number_list = cast(tuple[int, list[int]], query.data)
# append the number to the list
number_list.append(number)
+2 -2
View File
@@ -12,7 +12,7 @@ bot.
"""
import logging
from typing import Optional, Tuple
from typing import Optional
from telegram import Chat, ChatMember, ChatMemberUpdated, Update
from telegram.constants import ParseMode
@@ -37,7 +37,7 @@ logging.getLogger("httpx").setLevel(logging.WARNING)
logger = logging.getLogger(__name__)
def extract_status_change(chat_member_update: ChatMemberUpdated) -> Optional[Tuple[bool, bool]]:
def extract_status_change(chat_member_update: ChatMemberUpdated) -> Optional[tuple[bool, bool]]:
"""Takes a ChatMemberUpdated instance and extracts whether the 'old_chat_member' was a member
of the chat and whether the 'new_chat_member' is a member of the chat. Returns None, if
the status didn't change.
+3 -3
View File
@@ -12,7 +12,7 @@ bot.
import logging
from collections import defaultdict
from typing import DefaultDict, Optional, Set
from typing import Optional
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.constants import ParseMode
@@ -40,7 +40,7 @@ class ChatData:
"""Custom class for chat_data. Here we store data per message."""
def __init__(self) -> None:
self.clicks_per_message: DefaultDict[int, int] = defaultdict(int)
self.clicks_per_message: defaultdict[int, int] = defaultdict(int)
# The [ExtBot, dict, ChatData, dict] is for type checkers like mypy
@@ -57,7 +57,7 @@ class CustomContext(CallbackContext[ExtBot, dict, ChatData, dict]):
self._message_id: Optional[int] = None
@property
def bot_user_ids(self) -> Set[int]:
def bot_user_ids(self) -> set[int]:
"""Custom shortcut to access a value stored in the bot_data dict"""
return self.bot_data.setdefault("user_ids", set())
+1 -2
View File
@@ -15,7 +15,6 @@ bot.
"""
import logging
from typing import Dict
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import (
@@ -46,7 +45,7 @@ reply_keyboard = [
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
def facts_to_str(user_data: Dict[str, str]) -> str:
def facts_to_str(user_data: dict[str, str]) -> str:
"""Helper function for formatting the gathered user info."""
facts = [f"{key} - {value}" for key, value in user_data.items()]
return "\n".join(facts).join(["\n", "\n"])
+5 -5
View File
@@ -15,7 +15,7 @@ bot.
"""
import logging
from typing import Any, Dict, Tuple
from typing import Any
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import (
@@ -66,7 +66,7 @@ END = ConversationHandler.END
# Helper
def _name_switcher(level: str) -> Tuple[str, str]:
def _name_switcher(level: str) -> tuple[str, str]:
if level == PARENTS:
return "Father", "Mother"
return "Brother", "Sister"
@@ -122,7 +122,7 @@ async def adding_self(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str
async def show_data(update: Update, context: ContextTypes.DEFAULT_TYPE) -> str:
"""Pretty print gathered data."""
def pretty_print(data: Dict[str, Any], level: str) -> str:
def pretty_print(data: dict[str, Any], level: str) -> str:
people = data.get(level)
if not people:
return "\nNo information yet."
@@ -371,8 +371,8 @@ def main() -> None:
entry_points=[CommandHandler("start", start)],
states={
SHOWING: [CallbackQueryHandler(start, pattern="^" + str(END) + "$")],
SELECTING_ACTION: selection_handlers,
SELECTING_LEVEL: selection_handlers,
SELECTING_ACTION: selection_handlers, # type: ignore[dict-item]
SELECTING_LEVEL: selection_handlers, # type: ignore[dict-item]
DESCRIBING_SELF: [description_conv],
STOPPING: [CommandHandler("start", start)],
},
+10 -10
View File
@@ -47,9 +47,9 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
# Files will be downloaded to current directory
for data in passport_data.decrypted_data: # This is where the data gets decrypted
if data.type == "phone_number":
print("Phone: ", data.phone_number)
logger.info("Phone: %s", data.phone_number)
elif data.type == "email":
print("Email: ", data.email)
logger.info("Email: %s", data.email)
if data.type in (
"personal_details",
"passport",
@@ -58,7 +58,7 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"internal_passport",
"address",
):
print(data.type, data.data)
logger.info(data.type, data.data)
if data.type in (
"utility_bill",
"bank_statement",
@@ -66,28 +66,28 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"passport_registration",
"temporary_registration",
):
print(data.type, len(data.files), "files")
logger.info(data.type, len(data.files), "files")
for file in data.files:
actual_file = await file.get_file()
print(actual_file)
logger.info(actual_file)
await actual_file.download_to_drive()
if (
data.type in ("passport", "driver_license", "identity_card", "internal_passport")
and data.front_side
):
front_file = await data.front_side.get_file()
print(data.type, front_file)
logger.info(data.type, front_file)
await front_file.download_to_drive()
if data.type in ("driver_license" and "identity_card") and data.reverse_side:
reverse_file = await data.reverse_side.get_file()
print(data.type, reverse_file)
logger.info(data.type, reverse_file)
await reverse_file.download_to_drive()
if (
data.type in ("passport", "driver_license", "identity_card", "internal_passport")
and data.selfie
):
selfie_file = await data.selfie.get_file()
print(data.type, selfie_file)
logger.info(data.type, selfie_file)
await selfie_file.download_to_drive()
if data.translation and data.type in (
"passport",
@@ -100,10 +100,10 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"passport_registration",
"temporary_registration",
):
print(data.type, len(data.translation), "translation")
logger.info(data.type, len(data.translation), "translation")
for file in data.translation:
actual_file = await file.get_file()
print(actual_file)
logger.info(actual_file)
await actual_file.download_to_drive()
+47 -42
View File
@@ -2,7 +2,7 @@
# pylint: disable=unused-argument
# This program is dedicated to the public domain under the CC0 license.
"""Basic example for a bot that can receive payment from user."""
"""Basic example for a bot that can receive payments from users."""
import logging
@@ -26,44 +26,44 @@ logging.getLogger("httpx").setLevel(logging.WARNING)
logger = logging.getLogger(__name__)
# Insert the token from your payment provider.
# In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
PAYMENT_PROVIDER_TOKEN = "PAYMENT_PROVIDER_TOKEN"
async def start_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Displays info on how to use the bot."""
"""Provides instructions on how to use the bot."""
msg = (
"Use /shipping to get an invoice for shipping-payment, or /noshipping for an "
"Use /shipping to receive an invoice with shipping included, or /noshipping for an "
"invoice without shipping."
)
await update.message.reply_text(msg)
async def start_with_shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Sends an invoice with shipping-payment."""
"""Sends an invoice which triggers a shipping query."""
chat_id = update.message.chat_id
title = "Payment Example"
description = "Payment Example using python-telegram-bot"
# select a payload just for you to recognize its the donation from your bot
description = "Example of a payment process using the python-telegram-bot library."
# Unique payload to identify this payment request as being from your bot
payload = "Custom-Payload"
# In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
# Set up the currency.
# List of supported currencies: https://core.telegram.org/bots/payments#supported-currencies
currency = "USD"
# price in dollars
# Price in dollars
price = 1
# price * 100 so as to include 2 decimal points
# check https://core.telegram.org/bots/payments#supported-currencies for more details
# Convert price to cents from dollars.
prices = [LabeledPrice("Test", price * 100)]
# optionally pass need_name=True, need_phone_number=True,
# need_email=True, need_shipping_address=True, is_flexible=True
# Optional parameters like need_shipping_address and is_flexible trigger extra user prompts
# https://docs.python-telegram-bot.org/en/stable/telegram.bot.html#telegram.Bot.send_invoice
await context.bot.send_invoice(
chat_id,
title,
description,
payload,
PAYMENT_PROVIDER_TOKEN,
currency,
prices,
provider_token=PAYMENT_PROVIDER_TOKEN,
need_name=True,
need_phone_number=True,
need_email=True,
@@ -75,86 +75,91 @@ async def start_with_shipping_callback(update: Update, context: ContextTypes.DEF
async def start_without_shipping_callback(
update: Update, context: ContextTypes.DEFAULT_TYPE
) -> None:
"""Sends an invoice without shipping-payment."""
"""Sends an invoice without requiring shipping details."""
chat_id = update.message.chat_id
title = "Payment Example"
description = "Payment Example using python-telegram-bot"
# select a payload just for you to recognize its the donation from your bot
description = "Example of a payment process using the python-telegram-bot library."
# Unique payload to identify this payment request as being from your bot
payload = "Custom-Payload"
# In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
currency = "USD"
# price in dollars
# Price in dollars
price = 1
# price * 100 so as to include 2 decimal points
# Convert price to cents from dollars.
prices = [LabeledPrice("Test", price * 100)]
# optionally pass need_name=True, need_phone_number=True,
# need_email=True, need_shipping_address=True, is_flexible=True
await context.bot.send_invoice(
chat_id, title, description, payload, PAYMENT_PROVIDER_TOKEN, currency, prices
chat_id,
title,
description,
payload,
currency,
prices,
provider_token=PAYMENT_PROVIDER_TOKEN,
)
async def shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Answers the ShippingQuery with ShippingOptions"""
"""Handles the ShippingQuery with available shipping options."""
query = update.shipping_query
# check the payload, is this from your bot?
# Verify if the payload matches, ensure it's from your bot
if query.invoice_payload != "Custom-Payload":
# answer False pre_checkout_query
# If not, respond with an error
await query.answer(ok=False, error_message="Something went wrong...")
return
# First option has a single LabeledPrice
# Define available shipping options
# First option with a single price entry
options = [ShippingOption("1", "Shipping Option A", [LabeledPrice("A", 100)])]
# second option has an array of LabeledPrice objects
# Second option with multiple price entries
price_list = [LabeledPrice("B1", 150), LabeledPrice("B2", 200)]
options.append(ShippingOption("2", "Shipping Option B", price_list))
await query.answer(ok=True, shipping_options=options)
# after (optional) shipping, it's the pre-checkout
# After (optional) shipping, process the pre-checkout step
async def precheckout_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Answers the PreQecheckoutQuery"""
"""Responds to the PreCheckoutQuery as the final confirmation for checkout."""
query = update.pre_checkout_query
# check the payload, is this from your bot?
# Verify if the payload matches, ensure it's from your bot
if query.invoice_payload != "Custom-Payload":
# answer False pre_checkout_query
# If not, respond with an error
await query.answer(ok=False, error_message="Something went wrong...")
else:
await query.answer(ok=True)
# finally, after contacting the payment provider...
# Final callback after successful payment
async def successful_payment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Confirms the successful payment."""
# do something after successfully receiving payment?
await update.message.reply_text("Thank you for your payment!")
"""Acknowledges successful payment and thanks the user."""
await update.message.reply_text("Thank you for your payment.")
def main() -> None:
"""Run the bot."""
"""Starts the bot and sets up handlers."""
# Create the Application and pass it your bot's token.
application = Application.builder().token("TOKEN").build()
# simple start function
# Start command to display usage instructions
application.add_handler(CommandHandler("start", start_callback))
# Add command handler to start the payment invoice
# Command handlers for starting the payment process
application.add_handler(CommandHandler("shipping", start_with_shipping_callback))
application.add_handler(CommandHandler("noshipping", start_without_shipping_callback))
# Optional handler if your product requires shipping
# Handler for shipping query (if product requires shipping)
application.add_handler(ShippingQueryHandler(shipping_callback))
# Pre-checkout handler to final check
# Pre-checkout handler for verifying payment details.
application.add_handler(PreCheckoutQueryHandler(precheckout_callback))
# Success! Notify your user!
# Handler for successful payment. Notify the user that the payment was successful.
application.add_handler(
MessageHandler(filters.SUCCESSFUL_PAYMENT, successful_payment_callback)
)
# Run the bot until the user presses Ctrl-C
# Start polling for updates until interrupted (CTRL+C)
application.run_polling(allowed_updates=Update.ALL_TYPES)
+1 -2
View File
@@ -15,7 +15,6 @@ bot.
"""
import logging
from typing import Dict
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import (
@@ -47,7 +46,7 @@ reply_keyboard = [
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
def facts_to_str(user_data: Dict[str, str]) -> str:
def facts_to_str(user_data: dict[str, str]) -> str:
"""Helper function for formatting the gathered user info."""
facts = [f"{key} - {value}" for key, value in user_data.items()]
return "\n".join(facts).join(["\n", "\n"])
+124 -12
View File
@@ -1,7 +1,113 @@
# PACKAGING
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
dynamic = ["version"]
name = "python-telegram-bot"
description = "We have made you a wrapper you can't refuse"
readme = "README.rst"
requires-python = ">=3.9"
license = "LGPL-3.0-only"
license-files = ["LICENSE", "LICENSE.dual", "LICENSE.lesser"]
authors = [
{ name = "Leandro Toledo", email = "devs@python-telegram-bot.org" }
]
keywords = [
"python",
"telegram",
"bot",
"api",
"wrapper",
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Operating System :: OS Independent",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Communications :: Chat",
"Topic :: Internet",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"httpx ~= 0.27",
]
[project.urls]
"Homepage" = "https://python-telegram-bot.org"
"Documentation" = "https://docs.python-telegram-bot.org"
"Bug Tracker" = "https://github.com/python-telegram-bot/python-telegram-bot/issues"
"Source Code" = "https://github.com/python-telegram-bot/python-telegram-bot"
"News" = "https://t.me/pythontelegrambotchannel"
"Changelog" = "https://docs.python-telegram-bot.org/en/stable/changelog.html"
"Support" = "https://t.me/pythontelegrambotgroup"
[project.optional-dependencies]
# Make sure to install those as additional_dependencies in the
# pre-commit hooks for pylint & mypy
# Also update the readme accordingly
#
# When dependencies release new versions and tests succeed, we should try to expand the allowed
# versions and only increase the lower bound if necessary
#
# When adding new groups, make sure to update `ext` and `all` accordingly
# Optional dependencies for production
all = [
"python-telegram-bot[ext,http2,passport,socks]",
]
callback-data = [
# Cachetools doesn't have a strict stability policy. Let's be cautious for now.
"cachetools>=5.3.3,<5.6.0",
]
ext = [
"python-telegram-bot[callback-data,job-queue,rate-limiter,webhooks]",
]
http2 = [
"httpx[http2]",
]
job-queue = [
# APS doesn't have a strict stability policy. Let's be cautious for now.
"APScheduler>=3.10.4,<3.12.0",
]
passport = [
"cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1",
# cffi is a dependency of cryptography and added support for python 3.13 in 1.17.0rc1
"cffi >= 1.17.0rc1; python_version > '3.12'"
]
rate-limiter = [
"aiolimiter>=1.1,<1.3",
]
socks = [
"httpx[socks]",
]
webhooks = [
# tornado is rather stable, but let's not allow the next major release without prior testing
"tornado~=6.4",
]
# HATCH
[tool.hatch.version]
# dynamically evaluates the `__version__` variable in that file
source = "code"
path = "telegram/_version.py"
search-paths = ["telegram"]
[tool.hatch.build]
packages = ["telegram"]
# BLACK:
[tool.black]
line-length = 99
target-version = ['py38', 'py39', 'py310', 'py311']
# ISORT:
[tool.isort] # black config
@@ -11,24 +117,29 @@ line_length = 99
# RUFF:
[tool.ruff]
line-length = 99
target-version = "py38"
show-fixes = true
[tool.ruff.lint]
preview = true
explicit-preview-rules = true
explicit-preview-rules = true # TODO: Drop this when RUF022 and RUF023 are out of preview
ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915", "PERF203"]
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
"G", "ISC", "PT", "ASYNC", "TCH", "SLOT", "PERF", "PYI", "FLY", "AIR", "RUF022",
"RUF023", "Q", "INP", "W", "YTT", "DTZ", "ARG"]
# Add "FURB" after it's out of preview
"RUF023", "Q", "INP", "W", "YTT", "DTZ", "ARG", "T20", "FURB", "DOC", "TRY",
"D100", "D101", "D102", "D103", "D300", "D418", "D419", "S"]
# Add "A (flake8-builtins)" after we drop pylint
[tool.ruff.lint.per-file-ignores]
"tests/*.py" = ["B018"]
"tests/**.py" = ["RUF012", "ASYNC101", "DTZ", "ARG"]
"docs/**.py" = ["INP001", "ARG"]
"examples/**.py" = ["ARG"]
"tests/**.py" = ["RUF012", "ASYNC230", "DTZ", "ARG", "T201", "ASYNC109", "D", "S", "TRY"]
"telegram/**.py" = ["TRY003"]
"telegram/ext/_applicationbuilder.py" = ["TRY004"]
"telegram/ext/filters.py" = ["D102"]
"docs/**.py" = ["INP001", "ARG", "D", "TRY003", "S"]
"examples/**.py" = ["ARG", "D", "S105", "TRY003"]
[tool.ruff.lint.pydocstyle]
convention = "google"
# PYLINT:
[tool.pylint."messages control"]
@@ -36,7 +147,8 @@ enable = ["useless-suppression"]
disable = ["duplicate-code", "too-many-arguments", "too-many-public-methods",
"too-few-public-methods", "broad-exception-caught", "too-many-instance-attributes",
"fixme", "missing-function-docstring", "missing-class-docstring", "too-many-locals",
"too-many-lines", "too-many-branches", "too-many-statements", "cyclic-import"
"too-many-lines", "too-many-branches", "too-many-statements", "cyclic-import",
"too-many-positional-arguments",
]
[tool.pylint.main]
@@ -67,8 +179,8 @@ markers = [
"req",
]
asyncio_mode = "auto"
log_format = "%(funcName)s - Line %(lineno)d - %(message)s"
# log_level = "DEBUG" # uncomment to see DEBUG logs
log_cli_format = "%(funcName)s - Line %(lineno)d - %(message)s"
# log_cli_level = "DEBUG" # uncomment to see DEBUG logs
# MYPY:
[tool.mypy]
@@ -78,7 +190,7 @@ disallow_untyped_defs = true
disallow_incomplete_defs = true
disallow_untyped_decorators = true
show_error_codes = true
python_version = "3.8"
python_version = "3.9"
# For some files, it's easier to just disable strict-optional all together instead of
# cluttering the code with `# type: ignore`s or stuff like
-4
View File
@@ -1,4 +0,0 @@
-r requirements.txt
-r requirements-dev.txt
-r requirements-opts.txt
-r docs/requirements-docs.txt
+5
View File
@@ -0,0 +1,5 @@
-e .[all]
# needed for pre-commit hooks in the git commit command
pre-commit
-r requirements-unit-tests.txt
-r docs/requirements-docs.txt
-11
View File
@@ -1,11 +0,0 @@
pre-commit # needed for pre-commit hooks in the git commit command
# For the test suite
setuptools # required for test_meta
pytest==8.2.1
pytest-asyncio==0.21.2 # needed because pytest doesn't come with native support for coroutines as tests
pytest-xdist==3.6.1 # xdist runs tests in parallel
flaky # Used for flaky tests (flaky decorator)
beautifulsoup4 # used in test_official for parsing tg docs
wheel # required for building the wheels for releases
-27
View File
@@ -1,27 +0,0 @@
# Format:
# package_name==version # req-1, req-2, req-3!ext
# `pip install ptb-raw[req-1/2]` will install `package_name`
# `pip install ptb[req-1/2/3]` will also install `package_name`
# Make sure to install those as additional_dependencies in the
# pre-commit hooks for pylint & mypy
# Also update the readme accordingly
# When dependencies release new versions and tests succeed, we should try to expand the allowed
# versions and only increase the lower bound if necessary
httpx[socks] # socks
httpx[http2] # http2
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1 # passport
aiolimiter~=1.1.0 # rate-limiter!ext
# tornado is rather stable, but let's not allow the next mayor release without prior testing
tornado~=6.4 # webhooks!ext
# Cachetools and APS don't have a strict stability policy.
# Let's be cautious for now.
cachetools~=5.3.3 # callback-data!ext
APScheduler~=3.10.4 # job-queue!ext
# pytz is required by APS and just needs the lower bound due to #2120
pytz>=2018.6 # job-queue!ext
+23
View File
@@ -0,0 +1,23 @@
-e .
# required for building the wheels for releases
build
# For the test suite
pytest==8.3.4
# needed because pytest doesn't come with native support for coroutines as tests
pytest-asyncio==0.21.2
# xdist runs tests in parallel
pytest-xdist==3.6.1
# Used for flaky tests (flaky decorator)
flaky>=3.8.1
# used in test_official for parsing tg docs
beautifulsoup4
# For testing with timezones. Might not be needed on all systems, but to ensure that unit tests
# run correctly on all systems, we include it here.
tzdata
-10
View File
@@ -1,10 +0,0 @@
# Make sure to install those as additional_dependencies in the
# pre-commit hooks for pylint & mypy
# Also update the readme accordingly
# When dependencies release new versions and tests succeed, we should try to expand the allowed
# versions and only increase the lower bound if necessary
# httpx has no stable release yet, but we've had no stability problems since v20.0a0 either
# Since there have been requests to relax the bound a bit, we allow versions < 1.0.0
httpx ~= 0.27
+1 -4
View File
@@ -1,8 +1,5 @@
[metadata]
license_files = LICENSE, LICENSE.dual, LICENSE.lesser
[flake8]
max-line-length = 99
ignore = W503, W605
extend-ignore = E203, E704
exclude = setup.py, setup_raw.py docs/source/conf.py
exclude = docs/source/conf.py
-131
View File
@@ -1,131 +0,0 @@
#!/usr/bin/env python
"""The setup and build script for the python-telegram-bot library."""
import subprocess
import sys
from collections import defaultdict
from pathlib import Path
from typing import Any, Dict, List, Tuple
from setuptools import find_packages, setup
def get_requirements() -> List[str]:
"""Build the requirements list for this project"""
requirements_list = []
with Path("requirements.txt").open(encoding="utf-8") as reqs:
for install in reqs:
if install.startswith("#"):
continue
requirements_list.append(install.strip())
return requirements_list
def get_packages_requirements(raw: bool = False) -> Tuple[List[str], List[str]]:
"""Build the package & requirements list for this project"""
reqs = get_requirements()
exclude = ["tests*", "docs*"]
if raw:
exclude.append("telegram.ext*")
packs = find_packages(exclude=exclude)
return packs, reqs
def get_optional_requirements(raw: bool = False) -> Dict[str, List[str]]:
"""Build the optional dependencies"""
requirements = defaultdict(list)
with Path("requirements-opts.txt").open(encoding="utf-8") as reqs:
for line in reqs:
effective_line = line.strip()
if not effective_line or effective_line.startswith("#"):
continue
dependency, names = effective_line.split("#")
dependency = dependency.strip()
for name in names.split(","):
effective_name = name.strip()
if effective_name.endswith("!ext"):
if raw:
continue
effective_name = effective_name[:-4]
requirements["ext"].append(dependency)
requirements[effective_name].append(dependency)
requirements["all"].append(dependency)
return requirements
def get_setup_kwargs(raw: bool = False) -> Dict[str, Any]:
"""Builds a dictionary of kwargs for the setup function"""
packages, requirements = get_packages_requirements(raw=raw)
raw_ext = "-raw" if raw else ""
readme = Path(f'README{"_RAW" if raw else ""}.rst')
version_file = Path("telegram/_version.py").read_text(encoding="utf-8")
first_part = version_file.split("# SETUP.PY MARKER")[0]
exec(first_part) # pylint: disable=exec-used
return {
"script_name": f"setup{raw_ext}.py",
"name": f"python-telegram-bot{raw_ext}",
"version": locals()["__version__"],
"author": "Leandro Toledo",
"author_email": "devs@python-telegram-bot.org",
"license": "LGPLv3",
"url": "https://python-telegram-bot.org/",
# Keywords supported by PyPI can be found at
# https://github.com/pypa/warehouse/blob/aafc5185e57e67d43487ce4faa95913dd4573e14/
# warehouse/templates/packaging/detail.html#L20-L58
"project_urls": {
"Documentation": "https://docs.python-telegram-bot.org",
"Bug Tracker": "https://github.com/python-telegram-bot/python-telegram-bot/issues",
"Source Code": "https://github.com/python-telegram-bot/python-telegram-bot",
"News": "https://t.me/pythontelegrambotchannel",
"Changelog": "https://docs.python-telegram-bot.org/en/stable/changelog.html",
},
"download_url": f"https://pypi.org/project/python-telegram-bot{raw_ext}/",
"keywords": "python telegram bot api wrapper",
"description": "We have made you a wrapper you can't refuse",
"long_description": readme.read_text(encoding="utf-8"),
"long_description_content_type": "text/x-rst",
"packages": packages,
"install_requires": requirements,
"extras_require": get_optional_requirements(raw=raw),
"include_package_data": True,
"classifiers": [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Operating System :: OS Independent",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Communications :: Chat",
"Topic :: Internet",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
],
"python_requires": ">=3.8",
}
def main() -> None:
# If we're building, build ptb-raw as well
if set(sys.argv[1:]) in [{"bdist_wheel"}, {"sdist"}, {"sdist", "bdist_wheel"}]:
args = ["python", "setup_raw.py"]
args.extend(sys.argv[1:])
subprocess.run(args, check=True, capture_output=True)
setup(**get_setup_kwargs(raw=False))
if __name__ == "__main__":
main()
-8
View File
@@ -1,8 +0,0 @@
#!/usr/bin/env python
"""The setup and build script for the python-telegram-bot-raw library."""
from setuptools import setup
from setup import get_setup_kwargs
setup(**get_setup_kwargs(raw=True))
+73 -31
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -20,6 +20,7 @@
__author__ = "devs@python-telegram-bot.org"
__all__ = (
"AffiliateInfo",
"Animation",
"Audio",
"BackgroundFill",
@@ -81,6 +82,7 @@ __all__ = (
"ChatShared",
"ChosenInlineResult",
"Contact",
"CopyTextButton",
"Credentials",
"DataCredentials",
"Dice",
@@ -100,6 +102,8 @@ __all__ = (
"GameHighScore",
"GeneralForumTopicHidden",
"GeneralForumTopicUnhidden",
"Gift",
"Gifts",
"Giveaway",
"GiveawayCompleted",
"GiveawayCreated",
@@ -142,6 +146,9 @@ __all__ = (
"InputMediaPhoto",
"InputMediaVideo",
"InputMessageContent",
"InputPaidMedia",
"InputPaidMediaPhoto",
"InputPaidMediaVideo",
"InputPollOption",
"InputSticker",
"InputTextMessageContent",
@@ -173,6 +180,12 @@ __all__ = (
"MessageReactionCountUpdated",
"MessageReactionUpdated",
"OrderInfo",
"PaidMedia",
"PaidMediaInfo",
"PaidMediaPhoto",
"PaidMediaPreview",
"PaidMediaPurchased",
"PaidMediaVideo",
"PassportData",
"PassportElementError",
"PassportElementErrorDataField",
@@ -191,15 +204,22 @@ __all__ = (
"PollAnswer",
"PollOption",
"PreCheckoutQuery",
"PreparedInlineMessage",
"ProximityAlertTriggered",
"ReactionCount",
"ReactionType",
"ReactionTypeCustomEmoji",
"ReactionTypeEmoji",
"ReactionTypePaid",
"RefundedPayment",
"ReplyKeyboardMarkup",
"ReplyKeyboardRemove",
"ReplyParameters",
"ResidentialAddress",
"RevenueWithdrawalState",
"RevenueWithdrawalStateFailed",
"RevenueWithdrawalStatePending",
"RevenueWithdrawalStateSucceeded",
"SecureData",
"SecureValue",
"SentWebAppMessage",
@@ -207,6 +227,8 @@ __all__ = (
"ShippingAddress",
"ShippingOption",
"ShippingQuery",
"StarTransaction",
"StarTransactions",
"Sticker",
"StickerSet",
"Story",
@@ -214,6 +236,14 @@ __all__ = (
"SwitchInlineQueryChosenChat",
"TelegramObject",
"TextQuote",
"TransactionPartner",
"TransactionPartnerAffiliateProgram",
"TransactionPartnerChat",
"TransactionPartnerFragment",
"TransactionPartnerOther",
"TransactionPartnerTelegramAds",
"TransactionPartnerTelegramApi",
"TransactionPartnerUser",
"Update",
"User",
"UserChatBoosts",
@@ -242,7 +272,17 @@ __all__ = (
"warnings",
)
from pathlib import Path
from telegram._payment.stars.startransactions import StarTransaction, StarTransactions
from telegram._payment.stars.transactionpartner import (
TransactionPartner,
TransactionPartnerAffiliateProgram,
TransactionPartnerChat,
TransactionPartnerFragment,
TransactionPartnerOther,
TransactionPartnerTelegramAds,
TransactionPartnerTelegramApi,
TransactionPartnerUser,
)
from . import _version, constants, error, helpers, request, warnings
from ._birthdate import Birthdate
@@ -310,6 +350,7 @@ from ._chatmember import (
from ._chatmemberupdated import ChatMemberUpdated
from ._chatpermissions import ChatPermissions
from ._choseninlineresult import ChosenInlineResult
from ._copytextbutton import CopyTextButton
from ._dice import Dice
from ._files.animation import Animation
from ._files.audio import Audio
@@ -325,6 +366,9 @@ from ._files.inputmedia import (
InputMediaDocument,
InputMediaPhoto,
InputMediaVideo,
InputPaidMedia,
InputPaidMediaPhoto,
InputPaidMediaVideo,
)
from ._files.inputsticker import InputSticker
from ._files.location import Location
@@ -347,6 +391,7 @@ from ._forumtopic import (
from ._games.callbackgame import CallbackGame
from ._games.game import Game
from ._games.gamehighscore import GameHighScore
from ._gifts import Gift, Gifts
from ._giveaway import Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners
from ._inline.inlinekeyboardbutton import InlineKeyboardButton
from ._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
@@ -379,6 +424,7 @@ from ._inline.inputlocationmessagecontent import InputLocationMessageContent
from ._inline.inputmessagecontent import InputMessageContent
from ._inline.inputtextmessagecontent import InputTextMessageContent
from ._inline.inputvenuemessagecontent import InputVenueMessageContent
from ._inline.preparedinlinemessage import PreparedInlineMessage
from ._keyboardbutton import KeyboardButton
from ._keyboardbuttonpolltype import KeyboardButtonPollType
from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
@@ -397,6 +443,14 @@ from ._messageorigin import (
MessageOriginUser,
)
from ._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
from ._paidmedia import (
PaidMedia,
PaidMediaInfo,
PaidMediaPhoto,
PaidMediaPreview,
PaidMediaPurchased,
PaidMediaVideo,
)
from ._passport.credentials import (
Credentials,
DataCredentials,
@@ -425,13 +479,27 @@ from ._payment.invoice import Invoice
from ._payment.labeledprice import LabeledPrice
from ._payment.orderinfo import OrderInfo
from ._payment.precheckoutquery import PreCheckoutQuery
from ._payment.refundedpayment import RefundedPayment
from ._payment.shippingaddress import ShippingAddress
from ._payment.shippingoption import ShippingOption
from ._payment.shippingquery import ShippingQuery
from ._payment.stars.affiliateinfo import AffiliateInfo
from ._payment.stars.revenuewithdrawalstate import (
RevenueWithdrawalState,
RevenueWithdrawalStateFailed,
RevenueWithdrawalStatePending,
RevenueWithdrawalStateSucceeded,
)
from ._payment.successfulpayment import SuccessfulPayment
from ._poll import InputPollOption, Poll, PollAnswer, PollOption
from ._proximityalerttriggered import ProximityAlertTriggered
from ._reaction import ReactionCount, ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji
from ._reaction import (
ReactionCount,
ReactionType,
ReactionTypeCustomEmoji,
ReactionTypeEmoji,
ReactionTypePaid,
)
from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
from ._replykeyboardmarkup import ReplyKeyboardMarkup
from ._replykeyboardremove import ReplyKeyboardRemove
@@ -443,7 +511,6 @@ from ._telegramobject import TelegramObject
from ._update import Update
from ._user import User
from ._userprofilephotos import UserProfilePhotos
from ._utils.warnings import warn
from ._videochat import (
VideoChatEnded,
VideoChatParticipantsInvited,
@@ -472,33 +539,8 @@ __version_info__: _version.Version = _version.__version_info__
#:
#: .. versionchanged:: 20.0
#: This constant was previously named ``bot_api_version``.
__bot_api_version__: str = _version.__bot_api_version__
__bot_api_version__: str = constants.BOT_API_VERSION
#: :class:`typing.NamedTuple`: Shortcut for :const:`telegram.constants.BOT_API_VERSION_INFO`.
#:
#: .. versionadded:: 20.0
__bot_api_version_info__: constants._BotAPIVersion = _version.__bot_api_version_info__
if not (Path(__file__).parent.resolve().absolute() / "ext").exists():
_MESSAGE = (
"Hey. You seem to be using the `python-telegram-bot-raw` library. "
"Please note that this libray has been deprecated and will no longer be updated. "
"Please instead use the `python-telegram-bot` library. The change requires no "
"changes in your code and requires no additional dependencies. For additional "
"information, please see the channel post at "
"https://t.me/pythontelegrambotchannel/145."
)
# DeprecationWarning is ignored by default in Python 3.7 and later by default outside
# __main__ modules. We use both warning categories to increase the chance of the user
# seeing the warning.
warn(
warnings.PTBDeprecationWarning(version="21.3", message=_MESSAGE),
stacklevel=2,
)
warn(
message=_MESSAGE,
category=warnings.PTBUserWarning,
stacklevel=2,
)
__bot_api_version_info__: constants._BotAPIVersion = constants.BOT_API_VERSION_INFO
+2 -1
View File
@@ -1,7 +1,7 @@
# !/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -17,6 +17,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
# pylint: disable=missing-module-docstring
# ruff: noqa: T201, D100, S603, S607
import subprocess
import sys
from typing import Optional
+4 -4
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
@@ -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 an object that represents a Telegram Birthday."""
from datetime import date
import datetime as dtm
from typing import Optional
from telegram._telegramobject import TelegramObject
@@ -70,7 +70,7 @@ class Birthdate(TelegramObject):
self._freeze()
def to_date(self, year: Optional[int] = None) -> date:
def to_date(self, year: Optional[int] = None) -> dtm.date:
"""Return the birthdate as a date object.
.. versionchanged:: 21.2
@@ -89,4 +89,4 @@ class Birthdate(TelegramObject):
"The `year` argument is required if the `year` attribute was not present."
)
return date(year or self.year, self.month, self.day) # type: ignore[arg-type]
return dtm.date(year or self.year, self.month, self.day) # type: ignore[arg-type]

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