From e129991fcd830edb222d9e4e840e7a0db4b1fc9e Mon Sep 17 00:00:00 2001 From: Marco Costa Date: Fri, 18 Sep 2026 21:33:12 -0300 Subject: [PATCH] hgjgjgg --- .../encryptedpassportelement.cpython-311.pyc | Bin 13664 -> 0 bytes .../__pycache__/passportdata.cpython-311.pyc | Bin 6376 -> 0 bytes .../passportelementerrors.cpython-311.pyc | Bin 24206 -> 0 bytes .../__pycache__/passportfile.cpython-311.pyc | Bin 9278 -> 0 bytes .../telegram/_passport/credentials.py | 537 -- .../site-packages/telegram/_passport/data.py | 186 - .../_passport/encryptedpassportelement.py | 282 - .../telegram/_passport/passportdata.py | 132 - .../_passport/passportelementerrors.py | 474 -- .../telegram/_passport/passportfile.py | 227 - .../telegram/_payment/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 194 -> 0 bytes .../__pycache__/invoice.cpython-311.pyc | Bin 4496 -> 0 bytes .../__pycache__/labeledprice.cpython-311.pyc | Bin 2768 -> 0 bytes .../__pycache__/orderinfo.cpython-311.pyc | Bin 3449 -> 0 bytes .../precheckoutquery.cpython-311.pyc | Bin 6482 -> 0 bytes .../refundedpayment.cpython-311.pyc | Bin 3868 -> 0 bytes .../shippingaddress.cpython-311.pyc | Bin 2782 -> 0 bytes .../shippingoption.cpython-311.pyc | Bin 2590 -> 0 bytes .../__pycache__/shippingquery.cpython-311.pyc | Bin 5077 -> 0 bytes .../successfulpayment.cpython-311.pyc | Bin 6783 -> 0 bytes .../telegram/_payment/invoice.py | 134 - .../telegram/_payment/labeledprice.py | 65 - .../telegram/_payment/orderinfo.py | 85 - .../telegram/_payment/precheckoutquery.py | 155 - .../telegram/_payment/refundedpayment.py | 93 - .../telegram/_payment/shippingaddress.py | 89 - .../telegram/_payment/shippingoption.py | 76 - .../telegram/_payment/shippingquery.py | 125 - .../telegram/_payment/stars/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 200 -> 0 bytes .../__pycache__/affiliateinfo.cpython-311.pyc | Bin 5478 -> 0 bytes .../revenuewithdrawalstate.cpython-311.pyc | Bin 8625 -> 0 bytes .../startransactions.cpython-311.pyc | Bin 8254 -> 0 bytes .../transactionpartner.cpython-311.pyc | Bin 19198 -> 0 bytes .../telegram/_payment/stars/affiliateinfo.py | 120 - .../_payment/stars/revenuewithdrawalstate.py | 188 - .../_payment/stars/startransactions.py | 172 - .../_payment/stars/transactionpartner.py | 405 -- .../telegram/_payment/successfulpayment.py | 159 - .../site-packages/telegram/_poll.py | 650 --- .../telegram/_proximityalerttriggered.py | 82 - .../site-packages/telegram/_reaction.py | 244 - .../site-packages/telegram/_reply.py | 472 -- .../telegram/_replykeyboardmarkup.py | 360 -- .../telegram/_replykeyboardremove.py | 73 - .../telegram/_sentwebappmessage.py | 56 - .../site-packages/telegram/_shared.py | 268 - .../site-packages/telegram/_story.py | 82 - .../telegram/_switchinlinequerychosenchat.py | 100 - .../site-packages/telegram/_telegramobject.py | 675 --- .../site-packages/telegram/_update.py | 803 --- .../site-packages/telegram/_user.py | 2336 -------- .../telegram/_userprofilephotos.py | 85 - .../site-packages/telegram/_utils/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 192 -> 0 bytes .../argumentparsing.cpython-311.pyc | Bin 2070 -> 0 bytes .../__pycache__/datetime.cpython-311.pyc | Bin 10198 -> 0 bytes .../__pycache__/defaultvalue.cpython-311.pyc | Bin 4879 -> 0 bytes .../__pycache__/entities.cpython-311.pyc | Bin 3210 -> 0 bytes .../_utils/__pycache__/enum.cpython-311.pyc | Bin 3866 -> 0 bytes .../_utils/__pycache__/files.cpython-311.pyc | Bin 6894 -> 0 bytes .../__pycache__/logging.cpython-311.pyc | Bin 1818 -> 0 bytes .../_utils/__pycache__/markup.cpython-311.pyc | Bin 1615 -> 0 bytes .../_utils/__pycache__/repr.cpython-311.pyc | Bin 1861 -> 0 bytes .../__pycache__/strings.cpython-311.pyc | Bin 1811 -> 0 bytes .../_utils/__pycache__/types.cpython-311.pyc | Bin 2431 -> 0 bytes .../__pycache__/warnings.cpython-311.pyc | Bin 1857 -> 0 bytes .../warnings_transition.cpython-311.pyc | Bin 3736 -> 0 bytes .../telegram/_utils/argumentparsing.py | 62 - .../site-packages/telegram/_utils/datetime.py | 226 - .../telegram/_utils/defaultvalue.py | 148 - .../site-packages/telegram/_utils/entities.py | 73 - .../site-packages/telegram/_utils/enum.py | 90 - .../site-packages/telegram/_utils/files.py | 157 - .../site-packages/telegram/_utils/logging.py | 50 - .../site-packages/telegram/_utils/markup.py | 49 - .../site-packages/telegram/_utils/repr.py | 45 - .../site-packages/telegram/_utils/strings.py | 55 - .../site-packages/telegram/_utils/types.py | 93 - .../site-packages/telegram/_utils/warnings.py | 56 - .../telegram/_utils/warnings_transition.py | 114 - .../site-packages/telegram/_version.py | 56 - .../site-packages/telegram/_videochat.py | 195 - .../site-packages/telegram/_webappdata.py | 64 - .../site-packages/telegram/_webappinfo.py | 59 - .../site-packages/telegram/_webhookinfo.py | 186 - .../telegram/_writeaccessallowed.py | 88 - .../site-packages/telegram/constants.py | 3249 ------------ .../site-packages/telegram/error.py | 252 - .../site-packages/telegram/ext/__init__.py | 104 - .../ext/__pycache__/__init__.cpython-311.pyc | Bin 3694 -> 0 bytes .../_aioratelimiter.cpython-311.pyc | Bin 12917 -> 0 bytes .../__pycache__/_application.cpython-311.pyc | Bin 93606 -> 0 bytes .../_applicationbuilder.cpython-311.pyc | Bin 61164 -> 0 bytes .../_basepersistence.cpython-311.pyc | Bin 21219 -> 0 bytes .../_baseratelimiter.cpython-311.pyc | Bin 6874 -> 0 bytes .../_baseupdateprocessor.cpython-311.pyc | Bin 7991 -> 0 bytes .../_callbackcontext.cpython-311.pyc | Bin 19978 -> 0 bytes .../_callbackdatacache.cpython-311.pyc | Bin 21908 -> 0 bytes .../__pycache__/_contexttypes.cpython-311.pyc | Bin 9556 -> 0 bytes .../ext/__pycache__/_defaults.cpython-311.pyc | Bin 19063 -> 0 bytes .../_dictpersistence.cpython-311.pyc | Bin 23514 -> 0 bytes .../ext/__pycache__/_extbot.cpython-311.pyc | Bin 170908 -> 0 bytes .../ext/__pycache__/_jobqueue.cpython-311.pyc | Bin 47335 -> 0 bytes .../_picklepersistence.cpython-311.pyc | Bin 30106 -> 0 bytes .../ext/__pycache__/_updater.cpython-311.pyc | Bin 40422 -> 0 bytes .../ext/__pycache__/filters.cpython-311.pyc | Bin 142602 -> 0 bytes .../telegram/ext/_aioratelimiter.py | 277 - .../telegram/ext/_application.py | 1917 ------- .../telegram/ext/_applicationbuilder.py | 1394 ----- .../telegram/ext/_basepersistence.py | 440 -- .../telegram/ext/_baseratelimiter.py | 142 - .../telegram/ext/_baseupdateprocessor.py | 188 - .../telegram/ext/_callbackcontext.py | 429 -- .../telegram/ext/_callbackdatacache.py | 469 -- .../telegram/ext/_contexttypes.py | 226 - .../site-packages/telegram/ext/_defaults.py | 429 -- .../telegram/ext/_dictpersistence.py | 481 -- .../site-packages/telegram/ext/_extbot.py | 4709 ----------------- .../telegram/ext/_handlers/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 199 -> 0 bytes .../__pycache__/basehandler.cpython-311.pyc | Bin 8010 -> 0 bytes .../businessconnectionhandler.cpython-311.pyc | Bin 4313 -> 0 bytes ...nessmessagesdeletedhandler.cpython-311.pyc | Bin 4360 -> 0 bytes .../callbackqueryhandler.cpython-311.pyc | Bin 9874 -> 0 bytes .../chatboosthandler.cpython-311.pyc | Bin 5579 -> 0 bytes .../chatjoinrequesthandler.cpython-311.pyc | Bin 4941 -> 0 bytes .../chatmemberhandler.cpython-311.pyc | Bin 5455 -> 0 bytes .../choseninlineresulthandler.cpython-311.pyc | Bin 5702 -> 0 bytes .../commandhandler.cpython-311.pyc | Bin 11911 -> 0 bytes .../conversationhandler.cpython-311.pyc | Bin 45687 -> 0 bytes .../inlinequeryhandler.cpython-311.pyc | Bin 6577 -> 0 bytes .../messagehandler.cpython-311.pyc | Bin 5411 -> 0 bytes .../messagereactionhandler.cpython-311.pyc | Bin 8179 -> 0 bytes .../paidmediapurchasedhandler.cpython-311.pyc | Bin 4291 -> 0 bytes .../pollanswerhandler.cpython-311.pyc | Bin 2766 -> 0 bytes .../__pycache__/pollhandler.cpython-311.pyc | Bin 2720 -> 0 bytes .../precheckoutqueryhandler.cpython-311.pyc | Bin 4497 -> 0 bytes .../__pycache__/prefixhandler.cpython-311.pyc | Bin 9564 -> 0 bytes .../shippingqueryhandler.cpython-311.pyc | Bin 2749 -> 0 bytes .../stringcommandhandler.cpython-311.pyc | Bin 5119 -> 0 bytes .../stringregexhandler.cpython-311.pyc | Bin 5296 -> 0 bytes .../__pycache__/typehandler.cpython-311.pyc | Bin 4198 -> 0 bytes .../telegram/ext/_handlers/basehandler.py | 175 - .../_handlers/businessconnectionhandler.py | 95 - .../businessmessagesdeletedhandler.py | 95 - .../ext/_handlers/callbackqueryhandler.py | 208 - .../ext/_handlers/chatboosthandler.py | 130 - .../ext/_handlers/chatjoinrequesthandler.py | 111 - .../ext/_handlers/chatmemberhandler.py | 125 - .../_handlers/choseninlineresulthandler.py | 122 - .../telegram/ext/_handlers/commandhandler.py | 223 - .../ext/_handlers/conversationhandler.py | 958 ---- .../ext/_handlers/inlinequeryhandler.py | 143 - .../telegram/ext/_handlers/messagehandler.py | 111 - .../ext/_handlers/messagereactionhandler.py | 180 - .../_handlers/paidmediapurchasedhandler.py | 95 - .../ext/_handlers/pollanswerhandler.py | 71 - .../telegram/ext/_handlers/pollhandler.py | 71 - .../ext/_handlers/precheckoutqueryhandler.py | 103 - .../telegram/ext/_handlers/prefixhandler.py | 184 - .../ext/_handlers/shippingqueryhandler.py | 70 - .../ext/_handlers/stringcommandhandler.py | 108 - .../ext/_handlers/stringregexhandler.py | 115 - .../telegram/ext/_handlers/typehandler.py | 98 - .../site-packages/telegram/ext/_jobqueue.py | 1013 ---- .../telegram/ext/_picklepersistence.py | 562 -- .../site-packages/telegram/ext/_updater.py | 904 ---- .../telegram/ext/_utils/__init__.py | 17 - .../__pycache__/__init__.cpython-311.pyc | Bin 196 -> 0 bytes .../_update_parsing.cpython-311.pyc | Bin 2116 -> 0 bytes .../_utils/__pycache__/stack.cpython-311.pyc | Bin 2573 -> 0 bytes .../__pycache__/trackingdict.cpython-311.pyc | Bin 6929 -> 0 bytes .../_utils/__pycache__/types.cpython-311.pyc | Bin 2248 -> 0 bytes .../webhookhandler.cpython-311.pyc | Bin 11323 -> 0 bytes .../telegram/ext/_utils/_update_parsing.py | 50 - .../telegram/ext/_utils/stack.py | 76 - .../telegram/ext/_utils/trackingdict.py | 125 - .../telegram/ext/_utils/types.py | 106 - .../telegram/ext/_utils/webhookhandler.py | 223 - .../site-packages/telegram/ext/filters.py | 2939 ---------- .../site-packages/telegram/helpers.py | 201 - .../site-packages/telegram/py.typed | 0 .../telegram/request/__init__.py | 24 - .../__pycache__/__init__.cpython-311.pyc | Bin 533 -> 0 bytes .../__pycache__/_baserequest.cpython-311.pyc | Bin 20242 -> 0 bytes .../__pycache__/_httpxrequest.cpython-311.pyc | Bin 14366 -> 0 bytes .../__pycache__/_requestdata.cpython-311.pyc | Bin 7083 -> 0 bytes .../_requestparameter.cpython-311.pyc | Bin 8296 -> 0 bytes .../telegram/request/_baserequest.py | 457 -- .../telegram/request/_httpxrequest.py | 319 -- .../telegram/request/_requestdata.py | 142 - .../telegram/request/_requestparameter.py | 175 - .../site-packages/telegram/warnings.py | 87 - .../INSTALLER | 1 - .../METADATA | 73 - .../typing_extensions-4.16.0.dist-info/RECORD | 7 - .../typing_extensions-4.16.0.dist-info/WHEEL | 4 - .../licenses/LICENSE | 279 - .../site-packages/typing_extensions.py | 4422 ---------------- venv/pyvenv.cfg | 6 +- 202 files changed, 3 insertions(+), 42362 deletions(-) delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/encryptedpassportelement.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportdata.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportelementerrors.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportfile.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/credentials.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/data.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/encryptedpassportelement.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/passportdata.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/passportelementerrors.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/passportfile.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/invoice.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/labeledprice.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/orderinfo.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/precheckoutquery.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/refundedpayment.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingaddress.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingoption.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingquery.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/successfulpayment.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/invoice.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/labeledprice.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/orderinfo.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/precheckoutquery.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/refundedpayment.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/shippingaddress.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/shippingoption.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/shippingquery.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/affiliateinfo.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/revenuewithdrawalstate.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/startransactions.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/transactionpartner.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/affiliateinfo.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/revenuewithdrawalstate.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/startransactions.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/stars/transactionpartner.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_payment/successfulpayment.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_poll.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_proximityalerttriggered.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_reaction.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_reply.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_replykeyboardmarkup.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_replykeyboardremove.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_sentwebappmessage.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_shared.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_story.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_switchinlinequerychosenchat.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_telegramobject.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_update.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_user.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_userprofilephotos.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/argumentparsing.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/datetime.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/defaultvalue.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/entities.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/enum.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/files.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/logging.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/markup.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/repr.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/strings.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/types.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/warnings.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/warnings_transition.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/argumentparsing.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/datetime.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/defaultvalue.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/entities.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/enum.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/files.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/logging.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/markup.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/repr.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/strings.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/types.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/warnings.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_utils/warnings_transition.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_version.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_videochat.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_webappdata.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_webappinfo.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_webhookinfo.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_writeaccessallowed.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/constants.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/error.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_aioratelimiter.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_application.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_applicationbuilder.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_basepersistence.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseratelimiter.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseupdateprocessor.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackcontext.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackdatacache.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_contexttypes.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_defaults.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_dictpersistence.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_extbot.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_jobqueue.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_picklepersistence.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_updater.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/__pycache__/filters.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_aioratelimiter.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_application.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_applicationbuilder.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_basepersistence.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_baseratelimiter.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_baseupdateprocessor.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_callbackcontext.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_callbackdatacache.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_contexttypes.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_defaults.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_dictpersistence.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_extbot.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/basehandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessconnectionhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessmessagesdeletedhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/callbackqueryhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatboosthandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatjoinrequesthandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatmemberhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/choseninlineresulthandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/commandhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/conversationhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/inlinequeryhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagehandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagereactionhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/paidmediapurchasedhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollanswerhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/precheckoutqueryhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/prefixhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/shippingqueryhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringcommandhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringregexhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/typehandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/basehandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessconnectionhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessmessagesdeletedhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/callbackqueryhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatboosthandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatjoinrequesthandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatmemberhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/choseninlineresulthandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/commandhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/conversationhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/inlinequeryhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagehandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagereactionhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/paidmediapurchasedhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollanswerhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/precheckoutqueryhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/prefixhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/shippingqueryhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringcommandhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringregexhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_handlers/typehandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_jobqueue.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_picklepersistence.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_updater.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/_update_parsing.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/stack.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/trackingdict.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/types.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/webhookhandler.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/_update_parsing.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/stack.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/trackingdict.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/types.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/_utils/webhookhandler.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/ext/filters.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/helpers.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/py.typed delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/__pycache__/_baserequest.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/__pycache__/_httpxrequest.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/__pycache__/_requestdata.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/__pycache__/_requestparameter.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/_baserequest.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/_httpxrequest.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/_requestdata.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/request/_requestparameter.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/warnings.py delete mode 100755 venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/INSTALLER delete mode 100755 venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/METADATA delete mode 100755 venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/RECORD delete mode 100755 venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/WHEEL delete mode 100755 venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/licenses/LICENSE delete mode 100755 venv/lib/python3.11/site-packages/typing_extensions.py mode change 100755 => 100644 venv/pyvenv.cfg diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/encryptedpassportelement.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/encryptedpassportelement.cpython-311.pyc deleted file mode 100755 index f6f2a804a3b1305591b098f1c5d93b47f2ef7d14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13664 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportelementerrors.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportelementerrors.cpython-311.pyc deleted file mode 100755 index 15465fe94d60645e8e8d24e93f80984e3576c037..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24206 zcmeHPU2Ggja-P}WS^iTdB~lWl(T^=tKfBg%Y})6uWSROonevHrB+;>#!<`|y(r|av zGZamM$@xLR$%X&}IUP<8gn&3C3JLka4|yi+xs`WgMD5k#H$BhLj|vac#Xhos^B#euNio& zDtJxAdjWVY6})ERwE}N-1#cDc)&Q@qg7*UP+JU#Wg4ZIi>*YGvU+n1{No(S0RvuFo zF_q2eQaYoF`Uw0`B~4Q>Ea@Usa!k>bj4t*msxr)^QSm)s=dw(HM^#3F@eX5I7XJf^ zwv#UkCv$o_n~_uqH&|It4xUp|I&zQqp6ofCrf_InVi|~QeXsA(VZ2L9!knieHk}zx zna_&8sLw#?-fifyCto7O^pZ_2{lX2bwsC$ zQbtrzOkz4iMOlKeWhsJiQJCWRNIEqlj!T-TjSY^bbzPC^K~U-1NOnw>#X$wi*0Sma z;0;btfn%D&%qked*2L@(aNrRejgS~V<yA=^7vQ4Y(wWfqeK*HGB z>9IIvk1Cob4VM>h)WhUi)rZ!m2gh{fS#CsUuoyL)Rg4&qpcq2=_RR3b8Y!1fo`<(| zSYx&DBC$Fo_%5;rAgK@#ykNBEaBRiTy;bn*m;A3d9b?Vw27KSNesEJRjvdKOhQ8!) z0OzL7Dj62CC?eW}`F5oQ%(pmNNmKUr@XWwm-J7<>-VLSg&07{Ekb)Mv= zqE^`b?QJdSBo0QJKo6^jM4du0tc~RqRuq!SbSAAQlf@u(_A>bvW689f#P>-nMw3HK zQ7$T-kzz!iKViMGNmtBLy|i8cb{{wLi3MYveQr_n3X{}kGOFSJb^&kJpLghW9|o#1w@Wt!b zU%wo>Qu}TD`fGh(v|n$BAF*%OZ=8yLapL+3_)&Lv?S|_+ru4s^$hYr?-wk(#y3gxA ztNXO!O2cLPy9f8;W@=E#8EI4jA=f06hN^>bT{4Lyp2>+OlX5l%(I7)j&FWe*$yPyj zhFySRpP(id>rD}-6jeUN5m-L%#CPV6zh-~P$%qlLHMFH7!ZTrkAitZJnoU|;wu z<8`kGNYxrOEXT^UY7J@C8jn`3E&6tc!;&s_rxjI}8bPWwnxC@31!>5%rj3zi%4QU6 z6qg~BIE1-OJc61r$Fdhd33-(ts9tk47td!FE3A$W#}V#I|mCmVk|=&Jus$JcF@Ivg)RTGvJhq-*tbi`q_WtfslVf6 za;ouokYwf2c@X7teRQ3HV$AL$#TuvU8MwiKURzj!YVm-jYpbVPrpCYSBFNNT5W4e1_iTOh=O2Cc(VhB^LVZVxtBExb znccGM^5H8dXE*PFuO0v!&8=5!XPa8C#*j23X+Tm}s*P-DpfoWnFBLF{Ma|pgIVJmr z?%%)f7wyDpD1qPXJNQQMn>Rv-xae<#JWz(yb0z|D`p-oh744Nl}y3MzOWzQwe)t1Howl(omLg;r|_1Nn)3rw<7s_FltciyV`N>>Qc?z{ z`7We{rXOoY?}w7WR)B@j9dN$vDeAeyO{!vGq@8Z_#rFY{2n#O+lE(Bj+G~=7X;rnL z&!Ch!pVV|oCo_^2%K#4n+L4A~3W*)S4-;8XD9M!JG|WZG3TG7n#eu0$ViVrc#nu5Jjj14cI&`mhj!2YuX!G>>8eBJ>diL(tNp z50~+#40|{T#f3wLLVz)B#PP@&10_coV@7Z=2HS?BBl-CNiSY66M78#Z4*KfUkE*S?bfA#+RqCpF*EOW+~u zBsDV3QMP%aMocx7fJAvwl^O35oY;0S5&R|*I=DCb%>f>$Kb+`9u_O5yKKHH~qHxSI zs}W8hd4+4X5>*5z&b0^vmOT`)%^<@;y%ENF^O`JM$@(>a3XCR?ZvqL^ zU}@kJmkq?gC%9Bow!%~l>ti_pG-&_uz?1`+w#@Y53sW{Ps3B~e@->vD6@eg5S>?qk zYo@kNN53`}ijEY7BYELSnbjj0J4-m_EI+&Bz~#e*x(+u`0g!U$pWnaz`ki-97v4Dy zKj7a2Eml6n7-x9|EoXTIE#7#8yAU-&%fqr5pk?>L*Mi@?7CQK&=x;e5XkRe~o)2S8 z1ABHc!W4asWm2|D3j~5d6+ibr0`e$*xqRjHFTg-|&c4GW_)xq7B~J!=xtYMlS9=vj z>>5?{k*)!I8N%{bFgy$5dNwJ83&#LCMwoW`IK$pB6C}J_jG9RpcBh$;0d0Q-VfGRd zS~m)vSB|3naU@9SC%j?;2Y^9ltXE`OiN4*|mu~jh%(Y&dZ_M z4Vw!a5|=}lKfEKXn{9mIaxEdN6i!gA3;QTZ6xY7IE7dy2n-}^Xc@2zm@XL@l1`VT* zECCLMAN*Z4dc;;F@wh0PzAuX0)g|tEC4RtWqP8K25?l!;Uju+RstV2@*h@r7q!$x> zIW%37WCT%?NT>+BJBG#}jUtXp=fLX(mP#~mjc_Tj2O+%E#ShRF?VI)WVH{o@N+wSF8R1s1y|(4**;15#3TWPpQLxUo zZ&qY?7iESwgu*Q)4#<@8^;H}FTA0*vk%m&BA-w5Y-_(}tXGsST>Zh51p!@^%K?zz())1rN-N4O*E>Ux6qqS<)AT) zjI))cVvJSp^E!1|<`b9PqpddMLbcxtvomk72d~9#rD!I#7ML;1B3;F!EUa$h+^~Ac zebCY|E`PQqT|8cNqVhwOI71-gn%Nk}K^ste{OfGY@?~STs^H~%dFWn$LRw*G;Q;P{Zv(W z39qPlXEU?kj2Jg9!wQ|X&zp84r=A+dW;70oM~Gx zcPOT9UQ6e0T&^jfB-U7YwBAj6&%mQy0X>fZdYW7sgS@ksa)IQ8rUp(Fw!Bqx1=kbAq+_wJvJ)$|8K%h*48 zYZd)Zlj+b9Cov`9>UAg7F*-{!Xo)c=)4A}G~^5mp-Eu60a@riX8BCoK7HL3lSWyjy`KPs3J~ zVC*zM`{M5M&3J_aM{c+LZhgMvPputzR$?Oy?!Y@uJMg^m26rK9?!bFkmPOoQ)7W8= z{07_pOQY@1rX2U-jkqZ%!X^0>of3fe6v7rYPYHmgZ`+Q?0YG5?t7hQXPxGhx3&%b% ze!6p2A2!q^*0ZOxl{P08Be2*6=Oxpoq+*+ep5jR>WSr;A5Tq7ct;l#17j*!E!qB79 zA(!r~1`m&ChJrQPvQ=!hv)b{riz^1@(rHa}#sckYBDZ4lhN1;tGHw#WApy^rj>c;s z;{)Lh<5bQ!nFc>W^qe*b+r~;kp6B79O#Xd7&-LBq*5$qbce%ZJ@Bb{fJ@5UWpXN91pW~1ycSo7`#M*|yqeCzya9@~Sg`2`Zti}e3l CI1o|* diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportfile.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/passportfile.cpython-311.pyc deleted file mode 100755 index de361ef37cdca7fa0afe38c7f5378b540b0bad58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9278 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/credentials.py b/venv/lib/python3.11/site-packages/telegram/_passport/credentials.py deleted file mode 100755 index 8384fde..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/credentials.py +++ /dev/null @@ -1,537 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=missing-module-docstring, redefined-builtin -import json -from base64 import b64decode -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional, no_type_check - -try: - from cryptography.hazmat.backends import default_backend - from cryptography.hazmat.primitives.asymmetric.padding import MGF1, OAEP - from cryptography.hazmat.primitives.ciphers import Cipher - from cryptography.hazmat.primitives.ciphers.algorithms import AES - from cryptography.hazmat.primitives.ciphers.modes import CBC - from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512, Hash - - CRYPTO_INSTALLED = True -except ImportError: - default_backend = None # type: ignore[assignment] - MGF1, OAEP, Cipher, AES, CBC = (None, None, None, None, None) # type: ignore[misc,assignment] - SHA1, SHA256, SHA512, Hash = (None, None, None, None) # type: ignore[misc,assignment] - - CRYPTO_INSTALLED = False - -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.strings import TextEncoding -from telegram._utils.types import JSONDict -from telegram.error import PassportDecryptionError - -if TYPE_CHECKING: - from telegram import Bot - - -@no_type_check -def decrypt(secret, hash, data): - """ - Decrypt per telegram docs at https://core.telegram.org/passport. - - Args: - secret (:obj:`str` or :obj:`bytes`): The encryption secret, either as bytes or as a - base64 encoded string. - hash (:obj:`str` or :obj:`bytes`): The hash, either as bytes or as a - base64 encoded string. - data (:obj:`str` or :obj:`bytes`): The data to decrypt, either as bytes or as a - base64 encoded string. - file (:obj:`bool`): Force data to be treated as raw data, instead of trying to - b64decode it. - - Raises: - :class:`PassportDecryptionError`: Given hash does not match hash of decrypted data. - - Returns: - :obj:`bytes`: The decrypted data as bytes. - - """ - if not CRYPTO_INSTALLED: - raise RuntimeError( - "To use Telegram Passports, PTB must be installed via `pip install " - '"python-telegram-bot[passport]"`.' - ) - # Make a SHA512 hash of secret + update - digest = Hash(SHA512(), backend=default_backend()) - digest.update(secret + hash) - secret_hash_hash = digest.finalize() - # First 32 chars is our key, next 16 is the initialisation vector - key, init_vector = secret_hash_hash[:32], secret_hash_hash[32 : 32 + 16] - # Init a AES-CBC cipher and decrypt the data - cipher = Cipher(AES(key), CBC(init_vector), backend=default_backend()) - decryptor = cipher.decryptor() - data = decryptor.update(data) + decryptor.finalize() - # Calculate SHA256 hash of the decrypted data - digest = Hash(SHA256(), backend=default_backend()) - digest.update(data) - data_hash = digest.finalize() - # If the newly calculated hash did not match the one telegram gave us - if data_hash != hash: - # Raise a error that is caught inside telegram.PassportData and transformed into a warning - raise PassportDecryptionError(f"Hashes are not equal! {data_hash} != {hash}") - # Return data without padding - return data[data[0] :] - - -@no_type_check -def decrypt_json(secret, hash, data): - """Decrypts data using secret and hash and then decodes utf-8 string and loads json""" - return json.loads(decrypt(secret, hash, data).decode(TextEncoding.UTF_8)) - - -class EncryptedCredentials(TelegramObject): - """Contains data required for decrypting and authenticating EncryptedPassportElement. See the - Telegram Passport Documentation for a complete description of the data decryption and - authentication processes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`data`, :attr:`hash` and :attr:`secret` are equal. - - Note: - This object is decrypted only when originating from - :attr:`telegram.PassportData.decrypted_credentials`. - - Args: - data (:class:`telegram.Credentials` | :obj:`str`): Decrypted data with unique user's - nonce, data hashes and secrets used for EncryptedPassportElement decryption and - authentication or base64 encrypted data. - hash (:obj:`str`): Base64-encoded data hash for data authentication. - secret (:obj:`str`): Decrypted or encrypted secret used for decryption. - - Attributes: - data (:class:`telegram.Credentials` | :obj:`str`): Decrypted data with unique user's - nonce, data hashes and secrets used for EncryptedPassportElement decryption and - authentication or base64 encrypted data. - hash (:obj:`str`): Base64-encoded data hash for data authentication. - secret (:obj:`str`): Decrypted or encrypted secret used for decryption. - - """ - - __slots__ = ( - "_decrypted_data", - "_decrypted_secret", - "data", - "hash", - "secret", - ) - - def __init__( - self, - data: str, - hash: str, - secret: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.data: str = data - self.hash: str = hash - self.secret: str = secret - - self._id_attrs = (self.data, self.hash, self.secret) - - self._decrypted_secret: Optional[bytes] = None - self._decrypted_data: Optional[Credentials] = None - - self._freeze() - - @property - def decrypted_secret(self) -> bytes: - """ - :obj:`bytes`: Lazily decrypt and return secret. - - Raises: - telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad - private/public key but can also suggest malformed/tampered data. - """ - if self._decrypted_secret is None: - if not CRYPTO_INSTALLED: - raise RuntimeError( - "To use Telegram Passports, PTB must be installed via `pip install " - '"python-telegram-bot[passport]"`.' - ) - # Try decrypting according to step 1 at - # https://core.telegram.org/passport#decrypting-data - # We make sure to base64 decode the secret first. - # Telegram says to use OAEP padding so we do that. The Mask Generation Function - # is the default for OAEP, the algorithm is the default for PHP which is what - # Telegram's backend servers run. - try: - self._decrypted_secret = self.get_bot().private_key.decrypt( # type: ignore - b64decode(self.secret), - OAEP(mgf=MGF1(algorithm=SHA1()), algorithm=SHA1(), label=None), # skipcq - ) - except ValueError as exception: - # If decryption fails raise exception - raise PassportDecryptionError(exception) from exception - return self._decrypted_secret - - @property - def decrypted_data(self) -> "Credentials": - """ - :class:`telegram.Credentials`: Lazily decrypt and return credentials data. This object - also contains the user specified nonce as - `decrypted_data.nonce`. - - Raises: - telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad - private/public key but can also suggest malformed/tampered data. - """ - if self._decrypted_data is None: - self._decrypted_data = Credentials.de_json( - decrypt_json(self.decrypted_secret, b64decode(self.hash), b64decode(self.data)), - self.get_bot(), - ) - return self._decrypted_data # type: ignore[return-value] - - -class Credentials(TelegramObject): - """ - Attributes: - secure_data (:class:`telegram.SecureData`): Credentials for encrypted data - nonce (:obj:`str`): Bot-specified nonce - """ - - __slots__ = ("nonce", "secure_data") - - def __init__( - self, - secure_data: "SecureData", - nonce: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.secure_data: SecureData = secure_data - self.nonce: str = nonce - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["Credentials"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["secure_data"] = SecureData.de_json(data.get("secure_data"), bot=bot) - - return super().de_json(data=data, bot=bot) - - -class SecureData(TelegramObject): - """ - This object represents the credentials that were used to decrypt the encrypted data. - All fields are optional and depend on fields that were requested. - - Args: - personal_details (:class:`telegram.SecureValue`, optional): Credentials for encrypted - personal details. - passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted passport. - internal_passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted - internal passport. - driver_license (:class:`telegram.SecureValue`, optional): Credentials for encrypted - driver license. - identity_card (:class:`telegram.SecureValue`, optional): Credentials for encrypted ID card - address (:class:`telegram.SecureValue`, optional): Credentials for encrypted - residential address. - utility_bill (:class:`telegram.SecureValue`, optional): Credentials for encrypted - utility bill. - bank_statement (:class:`telegram.SecureValue`, optional): Credentials for encrypted - bank statement. - rental_agreement (:class:`telegram.SecureValue`, optional): Credentials for encrypted - rental agreement. - passport_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted - registration from internal passport. - temporary_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted - temporary registration. - - Attributes: - personal_details (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - personal details. - passport (:class:`telegram.SecureValue`): Optional. Credentials for encrypted passport. - internal_passport (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - internal passport. - driver_license (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - driver license. - identity_card (:class:`telegram.SecureValue`): Optional. Credentials for encrypted ID card - address (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - residential address. - utility_bill (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - utility bill. - bank_statement (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - bank statement. - rental_agreement (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - rental agreement. - passport_registration (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - registration from internal passport. - temporary_registration (:class:`telegram.SecureValue`): Optional. Credentials for encrypted - temporary registration. - """ - - __slots__ = ( - "address", - "bank_statement", - "driver_license", - "identity_card", - "internal_passport", - "passport", - "passport_registration", - "personal_details", - "rental_agreement", - "temporary_registration", - "utility_bill", - ) - - def __init__( - self, - personal_details: Optional["SecureValue"] = None, - passport: Optional["SecureValue"] = None, - internal_passport: Optional["SecureValue"] = None, - driver_license: Optional["SecureValue"] = None, - identity_card: Optional["SecureValue"] = None, - address: Optional["SecureValue"] = None, - utility_bill: Optional["SecureValue"] = None, - bank_statement: Optional["SecureValue"] = None, - rental_agreement: Optional["SecureValue"] = None, - passport_registration: Optional["SecureValue"] = None, - temporary_registration: Optional["SecureValue"] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Optionals - self.temporary_registration: Optional[SecureValue] = temporary_registration - self.passport_registration: Optional[SecureValue] = passport_registration - self.rental_agreement: Optional[SecureValue] = rental_agreement - self.bank_statement: Optional[SecureValue] = bank_statement - self.utility_bill: Optional[SecureValue] = utility_bill - self.address: Optional[SecureValue] = address - self.identity_card: Optional[SecureValue] = identity_card - self.driver_license: Optional[SecureValue] = driver_license - self.internal_passport: Optional[SecureValue] = internal_passport - self.passport: Optional[SecureValue] = passport - self.personal_details: Optional[SecureValue] = personal_details - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["SecureData"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["temporary_registration"] = SecureValue.de_json( - data.get("temporary_registration"), bot=bot - ) - data["passport_registration"] = SecureValue.de_json( - data.get("passport_registration"), bot=bot - ) - data["rental_agreement"] = SecureValue.de_json(data.get("rental_agreement"), bot=bot) - data["bank_statement"] = SecureValue.de_json(data.get("bank_statement"), bot=bot) - data["utility_bill"] = SecureValue.de_json(data.get("utility_bill"), bot=bot) - data["address"] = SecureValue.de_json(data.get("address"), bot=bot) - data["identity_card"] = SecureValue.de_json(data.get("identity_card"), bot=bot) - data["driver_license"] = SecureValue.de_json(data.get("driver_license"), bot=bot) - data["internal_passport"] = SecureValue.de_json(data.get("internal_passport"), bot=bot) - data["passport"] = SecureValue.de_json(data.get("passport"), bot=bot) - data["personal_details"] = SecureValue.de_json(data.get("personal_details"), bot=bot) - - return super().de_json(data=data, bot=bot) - - -class SecureValue(TelegramObject): - """ - This object represents the credentials that were used to decrypt the encrypted value. - All fields are optional and depend on the type of field. - - Args: - data (:class:`telegram.DataCredentials`, optional): Credentials for encrypted Telegram - Passport data. Available for "personal_details", "passport", "driver_license", - "identity_card", "identity_passport" and "address" types. - front_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted - document's front side. Available for "passport", "driver_license", "identity_card" - and "internal_passport". - reverse_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted - document's reverse side. Available for "driver_license" and "identity_card". - selfie (:class:`telegram.FileCredentials`, optional): Credentials for encrypted selfie - of the user with a document. Can be available for "passport", "driver_license", - "identity_card" and "internal_passport". - translation (list[:class:`telegram.FileCredentials`], optional): Credentials for an - encrypted translation of the document. Available for "passport", "driver_license", - "identity_card", "internal_passport", "utility_bill", "bank_statement", - "rental_agreement", "passport_registration" and "temporary_registration". - files (list[:class:`telegram.FileCredentials`], optional): Credentials for encrypted - files. Available for "utility_bill", "bank_statement", "rental_agreement", - "passport_registration" and "temporary_registration" types. - - Attributes: - data (:class:`telegram.DataCredentials`): Optional. Credentials for encrypted Telegram - Passport data. Available for "personal_details", "passport", "driver_license", - "identity_card", "identity_passport" and "address" types. - front_side (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted - document's front side. Available for "passport", "driver_license", "identity_card" - and "internal_passport". - reverse_side (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted - document's reverse side. Available for "driver_license" and "identity_card". - selfie (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted selfie - of the user with a document. Can be available for "passport", "driver_license", - "identity_card" and "internal_passport". - translation (tuple[:class:`telegram.FileCredentials`]): Optional. Credentials for an - encrypted translation of the document. Available for "passport", "driver_license", - "identity_card", "internal_passport", "utility_bill", "bank_statement", - "rental_agreement", "passport_registration" and "temporary_registration". - - .. versionchanged:: 20.0 - |tupleclassattrs| - - files (tuple[:class:`telegram.FileCredentials`]): Optional. Credentials for encrypted - files. Available for "utility_bill", "bank_statement", "rental_agreement", - "passport_registration" and "temporary_registration" types. - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - - """ - - __slots__ = ("data", "files", "front_side", "reverse_side", "selfie", "translation") - - def __init__( - self, - data: Optional["DataCredentials"] = None, - front_side: Optional["FileCredentials"] = None, - reverse_side: Optional["FileCredentials"] = None, - selfie: Optional["FileCredentials"] = None, - files: Optional[Sequence["FileCredentials"]] = None, - translation: Optional[Sequence["FileCredentials"]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.data: Optional[DataCredentials] = data - self.front_side: Optional[FileCredentials] = front_side - self.reverse_side: Optional[FileCredentials] = reverse_side - self.selfie: Optional[FileCredentials] = selfie - self.files: tuple[FileCredentials, ...] = parse_sequence_arg(files) - self.translation: tuple[FileCredentials, ...] = parse_sequence_arg(translation) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["SecureValue"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["data"] = DataCredentials.de_json(data.get("data"), bot=bot) - data["front_side"] = FileCredentials.de_json(data.get("front_side"), bot=bot) - data["reverse_side"] = FileCredentials.de_json(data.get("reverse_side"), bot=bot) - data["selfie"] = FileCredentials.de_json(data.get("selfie"), bot=bot) - data["files"] = FileCredentials.de_list(data.get("files"), bot=bot) - data["translation"] = FileCredentials.de_list(data.get("translation"), bot=bot) - - return super().de_json(data=data, bot=bot) - - -class _CredentialsBase(TelegramObject): - """Base class for DataCredentials and FileCredentials.""" - - __slots__ = ("data_hash", "file_hash", "hash", "secret") - - def __init__( - self, - hash: str, - secret: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - with self._unfrozen(): - self.hash: str = hash - self.secret: str = secret - - # Aliases just to be sure - self.file_hash: str = self.hash - self.data_hash: str = self.hash - - -class DataCredentials(_CredentialsBase): - """ - These credentials can be used to decrypt encrypted data from the data field in - EncryptedPassportData. - - Args: - data_hash (:obj:`str`): Checksum of encrypted data - secret (:obj:`str`): Secret of encrypted data - - Attributes: - hash (:obj:`str`): Checksum of encrypted data - secret (:obj:`str`): Secret of encrypted data - """ - - __slots__ = () - - def __init__(self, data_hash: str, secret: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(hash=data_hash, secret=secret, api_kwargs=api_kwargs) - self._freeze() - - -class FileCredentials(_CredentialsBase): - """ - These credentials can be used to decrypt encrypted files from the front_side, - reverse_side, selfie and files fields in EncryptedPassportData. - - Args: - file_hash (:obj:`str`): Checksum of encrypted file - secret (:obj:`str`): Secret of encrypted file - - Attributes: - hash (:obj:`str`): Checksum of encrypted file - secret (:obj:`str`): Secret of encrypted file - """ - - __slots__ = () - - def __init__(self, file_hash: str, secret: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(hash=file_hash, secret=secret, api_kwargs=api_kwargs) - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/data.py b/venv/lib/python3.11/site-packages/telegram/_passport/data.py deleted file mode 100755 index 5cbd5c7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/data.py +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=missing-module-docstring -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class PersonalDetails(TelegramObject): - """ - This object represents personal details. - - Args: - first_name (:obj:`str`): First Name. - middle_name (:obj:`str`): Optional. First Name. - last_name (:obj:`str`): Last Name. - birth_date (:obj:`str`): Date of birth in DD.MM.YYYY format. - gender (:obj:`str`): Gender, male or female. - country_code (:obj:`str`): Citizenship (ISO 3166-1 alpha-2 country code). - residence_country_code (:obj:`str`): Country of residence (ISO 3166-1 alpha-2 country - code). - first_name_native (:obj:`str`): First Name in the language of the user's country of - residence. - middle_name_native (:obj:`str`): Optional. Middle Name in the language of the user's - country of residence. - last_name_native (:obj:`str`): Last Name in the language of the user's country of - residence. - - Attributes: - first_name (:obj:`str`): First Name. - middle_name (:obj:`str`): Optional. First Name. - last_name (:obj:`str`): Last Name. - birth_date (:obj:`str`): Date of birth in DD.MM.YYYY format. - gender (:obj:`str`): Gender, male or female. - country_code (:obj:`str`): Citizenship (ISO 3166-1 alpha-2 country code). - residence_country_code (:obj:`str`): Country of residence (ISO 3166-1 alpha-2 country - code). - first_name_native (:obj:`str`): First Name in the language of the user's country of - residence. - middle_name_native (:obj:`str`): Optional. Middle Name in the language of the user's - country of residence. - last_name_native (:obj:`str`): Last Name in the language of the user's country of - residence. - """ - - __slots__ = ( - "birth_date", - "country_code", - "first_name", - "first_name_native", - "gender", - "last_name", - "last_name_native", - "middle_name", - "middle_name_native", - "residence_country_code", - ) - - def __init__( - self, - first_name: str, - last_name: str, - birth_date: str, - gender: str, - country_code: str, - residence_country_code: str, - first_name_native: Optional[str] = None, - last_name_native: Optional[str] = None, - middle_name: Optional[str] = None, - middle_name_native: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.first_name: str = first_name - self.last_name: str = last_name - self.middle_name: Optional[str] = middle_name - self.birth_date: str = birth_date - self.gender: str = gender - self.country_code: str = country_code - self.residence_country_code: str = residence_country_code - self.first_name_native: Optional[str] = first_name_native - self.last_name_native: Optional[str] = last_name_native - self.middle_name_native: Optional[str] = middle_name_native - - self._freeze() - - -class ResidentialAddress(TelegramObject): - """ - This object represents a residential address. - - Args: - street_line1 (:obj:`str`): First line for the address. - street_line2 (:obj:`str`): Optional. Second line for the address. - city (:obj:`str`): City. - state (:obj:`str`): Optional. State. - country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. - post_code (:obj:`str`): Address post code. - - Attributes: - street_line1 (:obj:`str`): First line for the address. - street_line2 (:obj:`str`): Optional. Second line for the address. - city (:obj:`str`): City. - state (:obj:`str`): Optional. State. - country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. - post_code (:obj:`str`): Address post code. - """ - - __slots__ = ( - "city", - "country_code", - "post_code", - "state", - "street_line1", - "street_line2", - ) - - def __init__( - self, - street_line1: str, - street_line2: str, - city: str, - state: str, - country_code: str, - post_code: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.street_line1: str = street_line1 - self.street_line2: str = street_line2 - self.city: str = city - self.state: str = state - self.country_code: str = country_code - self.post_code: str = post_code - - self._freeze() - - -class IdDocumentData(TelegramObject): - """ - This object represents the data of an identity document. - - Args: - document_no (:obj:`str`): Document number. - expiry_date (:obj:`str`): Optional. Date of expiry, in DD.MM.YYYY format. - - Attributes: - document_no (:obj:`str`): Document number. - expiry_date (:obj:`str`): Optional. Date of expiry, in DD.MM.YYYY format. - """ - - __slots__ = ("document_no", "expiry_date") - - def __init__( - self, - document_no: str, - expiry_date: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.document_no: str = document_no - self.expiry_date: str = expiry_date - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/encryptedpassportelement.py b/venv/lib/python3.11/site-packages/telegram/_passport/encryptedpassportelement.py deleted file mode 100755 index aa646df..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/encryptedpassportelement.py +++ /dev/null @@ -1,282 +0,0 @@ -#!/usr/bin/env python -# flake8: noqa: E501 -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram EncryptedPassportElement.""" -from base64 import b64decode -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional, Union - -from telegram._passport.credentials import decrypt_json -from telegram._passport.data import IdDocumentData, PersonalDetails, ResidentialAddress -from telegram._passport.passportfile import PassportFile -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot, Credentials - - -class EncryptedPassportElement(TelegramObject): - """ - Contains information about documents or other Telegram Passport elements shared with the bot - by the user. The data has been automatically decrypted by python-telegram-bot. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type`, :attr:`data`, :attr:`phone_number`, :attr:`email`, - :attr:`files`, :attr:`front_side`, :attr:`reverse_side` and :attr:`selfie` are equal. - - Note: - This object is decrypted only when originating from - :attr:`telegram.PassportData.decrypted_data`. - - Args: - type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license", - "identity_card", "internal_passport", "address", "utility_bill", "bank_statement", - "rental_agreement", "passport_registration", "temporary_registration", "phone_number", - "email". - hash (:obj:`str`): Base64-encoded element hash for using in - :class:`telegram.PassportElementErrorUnspecified`. - data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \ - :class:`telegram.ResidentialAddress` | :obj:`str`, optional): - Decrypted or encrypted data; available only for "personal_details", "passport", - "driver_license", "identity_card", "internal_passport" and "address" types. - phone_number (:obj:`str`, optional): User's verified phone number; available only for - "phone_number" type. - email (:obj:`str`, optional): User's verified email address; available only for "email" - type. - files (Sequence[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted - files with documents provided by the user; available only for "utility_bill", - "bank_statement", "rental_agreement", "passport_registration" and - "temporary_registration" types. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - front_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - front side of the document, provided by the user; Available only for "passport", - "driver_license", "identity_card" and "internal_passport". - reverse_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - reverse side of the document, provided by the user; Available only for - "driver_license" and "identity_card". - selfie (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - selfie of the user holding a document, provided by the user; available if requested for - "passport", "driver_license", "identity_card" and "internal_passport". - translation (Sequence[:class:`telegram.PassportFile`], optional): Array of - encrypted/decrypted files with translated versions of documents provided by the user; - available if requested requested for "passport", "driver_license", "identity_card", - "internal_passport", "utility_bill", "bank_statement", "rental_agreement", - "passport_registration" and "temporary_registration" types. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - Attributes: - type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license", - "identity_card", "internal_passport", "address", "utility_bill", "bank_statement", - "rental_agreement", "passport_registration", "temporary_registration", "phone_number", - "email". - hash (:obj:`str`): Base64-encoded element hash for using in - :class:`telegram.PassportElementErrorUnspecified`. - data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \ - :class:`telegram.ResidentialAddress` | :obj:`str`): - Optional. Decrypted or encrypted data; available only for "personal_details", - "passport", "driver_license", "identity_card", "internal_passport" and "address" types. - phone_number (:obj:`str`): Optional. User's verified phone number; available only for - "phone_number" type. - email (:obj:`str`): Optional. User's verified email address; available only for "email" - type. - files (tuple[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted - files with documents provided by the user; available only for "utility_bill", - "bank_statement", "rental_agreement", "passport_registration" and - "temporary_registration" types. - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - - front_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - front side of the document, provided by the user; available only for "passport", - "driver_license", "identity_card" and "internal_passport". - reverse_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - reverse side of the document, provided by the user; available only for "driver_license" - and "identity_card". - selfie (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - selfie of the user holding a document, provided by the user; available if requested for - "passport", "driver_license", "identity_card" and "internal_passport". - translation (tuple[:class:`telegram.PassportFile`]): Optional. Array of - encrypted/decrypted files with translated versions of documents provided by the user; - available if requested for "passport", "driver_license", "identity_card", - "internal_passport", "utility_bill", "bank_statement", "rental_agreement", - "passport_registration" and "temporary_registration" types. - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - - """ - - __slots__ = ( - "data", - "email", - "files", - "front_side", - "hash", - "phone_number", - "reverse_side", - "selfie", - "translation", - "type", - ) - - def __init__( - self, - type: str, # pylint: disable=redefined-builtin - hash: str, # pylint: disable=redefined-builtin - data: Optional[Union[PersonalDetails, IdDocumentData, ResidentialAddress]] = None, - phone_number: Optional[str] = None, - email: Optional[str] = None, - files: Optional[Sequence[PassportFile]] = None, - front_side: Optional[PassportFile] = None, - reverse_side: Optional[PassportFile] = None, - selfie: Optional[PassportFile] = None, - translation: Optional[Sequence[PassportFile]] = None, - # TODO: Remove the credentials argument in 22.0 or later - credentials: Optional[ # pylint: disable=unused-argument # noqa: ARG002 - "Credentials" - ] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.type: str = type - # Optionals - self.data: Optional[Union[PersonalDetails, IdDocumentData, ResidentialAddress]] = data - self.phone_number: Optional[str] = phone_number - self.email: Optional[str] = email - self.files: tuple[PassportFile, ...] = parse_sequence_arg(files) - self.front_side: Optional[PassportFile] = front_side - self.reverse_side: Optional[PassportFile] = reverse_side - self.selfie: Optional[PassportFile] = selfie - self.translation: tuple[PassportFile, ...] = parse_sequence_arg(translation) - self.hash: str = hash - - self._id_attrs = ( - self.type, - self.data, - self.phone_number, - self.email, - self.files, - self.front_side, - self.reverse_side, - self.selfie, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["EncryptedPassportElement"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["files"] = PassportFile.de_list(data.get("files"), bot) or None - data["front_side"] = PassportFile.de_json(data.get("front_side"), bot) - data["reverse_side"] = PassportFile.de_json(data.get("reverse_side"), bot) - data["selfie"] = PassportFile.de_json(data.get("selfie"), bot) - data["translation"] = PassportFile.de_list(data.get("translation"), bot) or None - - return super().de_json(data=data, bot=bot) - - @classmethod - def de_json_decrypted( - cls, data: Optional[JSONDict], bot: Optional["Bot"], credentials: "Credentials" - ) -> Optional["EncryptedPassportElement"]: - """Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account - passport credentials. - - Args: - data (dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object. - May be :obj:`None`, in which case shortcut methods will not be available. - - .. versionchanged:: 21.4 - :paramref:`bot` is now optional and defaults to :obj:`None` - - .. deprecated:: 21.4 - This argument will be converted to an optional argument in future versions. - credentials (:class:`telegram.FileCredentials`): The credentials - - Returns: - :class:`telegram.EncryptedPassportElement`: - - """ - if not data: - return None - - if data["type"] not in ("phone_number", "email"): - secure_data = getattr(credentials.secure_data, data["type"]) - - if secure_data.data is not None: - # If not already decrypted - if not isinstance(data["data"], dict): - data["data"] = decrypt_json( - b64decode(secure_data.data.secret), - b64decode(secure_data.data.hash), - b64decode(data["data"]), - ) - if data["type"] == "personal_details": - data["data"] = PersonalDetails.de_json(data["data"], bot=bot) - elif data["type"] in ( - "passport", - "internal_passport", - "driver_license", - "identity_card", - ): - data["data"] = IdDocumentData.de_json(data["data"], bot=bot) - elif data["type"] == "address": - data["data"] = ResidentialAddress.de_json(data["data"], bot=bot) - - data["files"] = ( - PassportFile.de_list_decrypted(data.get("files"), bot, secure_data.files) or None - ) - data["front_side"] = PassportFile.de_json_decrypted( - data.get("front_side"), bot, secure_data.front_side - ) - data["reverse_side"] = PassportFile.de_json_decrypted( - data.get("reverse_side"), bot, secure_data.reverse_side - ) - data["selfie"] = PassportFile.de_json_decrypted( - data.get("selfie"), bot, secure_data.selfie - ) - data["translation"] = ( - PassportFile.de_list_decrypted( - data.get("translation"), bot, secure_data.translation - ) - or None - ) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/passportdata.py b/venv/lib/python3.11/site-packages/telegram/_passport/passportdata.py deleted file mode 100755 index 200a458..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/passportdata.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""Contains information about Telegram Passport data shared with the bot by the user.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._passport.credentials import EncryptedCredentials -from telegram._passport.encryptedpassportelement import EncryptedPassportElement -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot, Credentials - - -class PassportData(TelegramObject): - """Contains information about Telegram Passport data shared with the bot by the user. - - Note: - To be able to decrypt this object, you must pass your ``private_key`` to either - :class:`telegram.ext.Updater` or :class:`telegram.Bot`. Decrypted data is then found in - :attr:`decrypted_data` and the payload can be found in :attr:`decrypted_credentials`'s - attribute :attr:`telegram.Credentials.nonce`. - - Args: - data (Sequence[:class:`telegram.EncryptedPassportElement`]): Array with encrypted - information about documents and other Telegram Passport elements that was shared with - the bot. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - credentials (:class:`telegram.EncryptedCredentials`)): Encrypted credentials. - - Attributes: - data (tuple[:class:`telegram.EncryptedPassportElement`]): Array with encrypted - information about documents and other Telegram Passport elements that was shared with - the bot. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - credentials (:class:`telegram.EncryptedCredentials`): Encrypted credentials. - - - """ - - __slots__ = ("_decrypted_data", "credentials", "data") - - def __init__( - self, - data: Sequence[EncryptedPassportElement], - credentials: EncryptedCredentials, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.data: tuple[EncryptedPassportElement, ...] = parse_sequence_arg(data) - self.credentials: EncryptedCredentials = credentials - - self._decrypted_data: Optional[tuple[EncryptedPassportElement]] = None - self._id_attrs = tuple([x.type for x in data] + [credentials.hash]) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PassportData"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["data"] = EncryptedPassportElement.de_list(data.get("data"), bot) - data["credentials"] = EncryptedCredentials.de_json(data.get("credentials"), bot) - - return super().de_json(data=data, bot=bot) - - @property - def decrypted_data(self) -> tuple[EncryptedPassportElement, ...]: - """ - tuple[:class:`telegram.EncryptedPassportElement`]: Lazily decrypt and return information - about documents and other Telegram Passport elements which were shared with the bot. - - .. versionchanged:: 20.0 - Returns a tuple instead of a list. - - Raises: - telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad - private/public key but can also suggest malformed/tampered data. - """ - if self._decrypted_data is None: - self._decrypted_data = tuple( # type: ignore[assignment] - EncryptedPassportElement.de_json_decrypted( - element.to_dict(), self.get_bot(), self.decrypted_credentials - ) - for element in self.data - ) - return self._decrypted_data # type: ignore[return-value] - - @property - def decrypted_credentials(self) -> "Credentials": - """ - :class:`telegram.Credentials`: Lazily decrypt and return credentials that were used - to decrypt the data. This object also contains the user specified payload as - `decrypted_data.payload`. - - Raises: - telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad - private/public key but can also suggest malformed/tampered data. - """ - return self.credentials.decrypted_data diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/passportelementerrors.py b/venv/lib/python3.11/site-packages/telegram/_passport/passportelementerrors.py deleted file mode 100755 index d5a7446..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/passportelementerrors.py +++ /dev/null @@ -1,474 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=redefined-builtin -"""This module contains the classes that represent Telegram PassportElementError.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn -from telegram.warnings import PTBDeprecationWarning - - -class PassportElementError(TelegramObject): - """Baseclass for the PassportElementError* classes. - - This object represents an error in the Telegram Passport element which was submitted that - should be resolved by the user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source` and :attr:`type` are equal. - - Args: - source (:obj:`str`): Error source. - type (:obj:`str`): The section of the user's Telegram Passport which has the error. - message (:obj:`str`): Error message. - - Attributes: - source (:obj:`str`): Error source. - type (:obj:`str`): The section of the user's Telegram Passport which has the error. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("message", "source", "type") - - def __init__( - self, source: str, type: str, message: str, *, api_kwargs: Optional[JSONDict] = None - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.source: str = str(source) - self.type: str = str(type) - self.message: str = str(message) - - self._id_attrs = (self.source, self.type) - - self._freeze() - - -class PassportElementErrorDataField(PassportElementError): - """ - Represents an issue in one of the data fields that was provided by the user. The error is - considered resolved when the field's value changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`field_name`, :attr:`data_hash` and :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of - ``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"address"``. - field_name (:obj:`str`): Name of the data field which has the error. - data_hash (:obj:`str`): Base64-encoded data hash. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of - ``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"address"``. - field_name (:obj:`str`): Name of the data field which has the error. - data_hash (:obj:`str`): Base64-encoded data hash. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("data_hash", "field_name") - - def __init__( - self, - type: str, - field_name: str, - data_hash: str, - message: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__("data", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self.field_name: str = field_name - self.data_hash: str = data_hash - - self._id_attrs = ( - self.source, - self.type, - self.field_name, - self.data_hash, - self.message, - ) - - -class PassportElementErrorFile(PassportElementError): - """ - Represents an issue with a document scan. The error is considered resolved when the file with - the document scan changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`file_hash`, and :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, - ``"passport_registration"``, ``"temporary_registration"``. - file_hash (:obj:`str`): Base64-encoded file hash. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, - ``"passport_registration"``, ``"temporary_registration"``. - file_hash (:obj:`str`): Base64-encoded file hash. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("file_hash",) - - def __init__( - self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None - ): - # Required - super().__init__("file", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self.file_hash: str = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorFiles(PassportElementError): - """ - Represents an issue with a list of scans. The error is considered resolved when the list of - files with the document scans changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`file_hashes`, and :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, - ``"passport_registration"``, ``"temporary_registration"``. - file_hashes (list[:obj:`str`]): List of base64-encoded file hashes. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, - ``"passport_registration"``, ``"temporary_registration"``. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("_file_hashes",) - - def __init__( - self, - type: str, - file_hashes: list[str], - message: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__("files", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self._file_hashes: list[str] = file_hashes - - self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes)) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict` for details.""" - data = super().to_dict(recursive) - data["file_hashes"] = self._file_hashes - return data - - @property - def file_hashes(self) -> list[str]: - """List of base64-encoded file hashes. - - .. deprecated:: 20.6 - This attribute will return a tuple instead of a list in future major versions. - """ - warn( - PTBDeprecationWarning( - "20.6", - "The attribute `file_hashes` will return a tuple instead of a list in future major" - " versions.", - ), - stacklevel=2, - ) - return self._file_hashes - - -class PassportElementErrorFrontSide(PassportElementError): - """ - Represents an issue with the front side of a document. The error is considered resolved when - the file with the front side of the document changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`file_hash`, and :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the - document. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the - document. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("file_hash",) - - def __init__( - self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None - ): - # Required - super().__init__("front_side", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self.file_hash: str = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorReverseSide(PassportElementError): - """ - Represents an issue with the reverse side of a document. The error is considered resolved when - the file with the reverse side of the document changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`file_hash`, and :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"driver_license"``, ``"identity_card"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the - document. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"driver_license"``, ``"identity_card"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the - document. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("file_hash",) - - def __init__( - self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None - ): - # Required - super().__init__("reverse_side", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self.file_hash: str = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorSelfie(PassportElementError): - """ - Represents an issue with the selfie with a document. The error is considered resolved when - the file with the selfie changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`file_hash`, and :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("file_hash",) - - def __init__( - self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None - ): - # Required - super().__init__("selfie", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self.file_hash: str = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorTranslationFile(PassportElementError): - """ - Represents an issue with one of the files that constitute the translation of a document. - The error is considered resolved when the file changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`file_hash`, and :attr:`message` are equal. - - Args: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, - one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, - ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. - file_hash (:obj:`str`): Base64-encoded hash of the file. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, - one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, - ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. - file_hash (:obj:`str`): Base64-encoded hash of the file. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("file_hash",) - - def __init__( - self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None - ): - # Required - super().__init__("translation_file", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self.file_hash: str = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorTranslationFiles(PassportElementError): - """ - Represents an issue with the translated version of a document. The error is considered - resolved when a file with the document translation changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`file_hashes`, and :attr:`message` are equal. - - Args: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, - one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, - ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. - file_hashes (list[:obj:`str`]): List of base64-encoded file hashes. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, - one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, - ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("_file_hashes",) - - def __init__( - self, - type: str, - file_hashes: list[str], - message: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__("translation_files", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self._file_hashes: list[str] = file_hashes - - self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes)) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict` for details.""" - data = super().to_dict(recursive) - data["file_hashes"] = self._file_hashes - return data - - @property - def file_hashes(self) -> list[str]: - """List of base64-encoded file hashes. - - .. deprecated:: 20.6 - This attribute will return a tuple instead of a list in future major versions. - """ - warn( - PTBDeprecationWarning( - "20.6", - "The attribute `file_hashes` will return a tuple instead of a list in future major" - " versions. See the stability policy:" - " https://docs.python-telegram-bot.org/en/stable/stability_policy.html", - ), - stacklevel=2, - ) - return self._file_hashes - - -class PassportElementErrorUnspecified(PassportElementError): - """ - Represents an issue in an unspecified place. The error is considered resolved when new - data is added. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`, - :attr:`element_hash`, and :attr:`message` are equal. - - Args: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue. - element_hash (:obj:`str`): Base64-encoded element hash. - message (:obj:`str`): Error message. - - Attributes: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue. - element_hash (:obj:`str`): Base64-encoded element hash. - message (:obj:`str`): Error message. - - """ - - __slots__ = ("element_hash",) - - def __init__( - self, type: str, element_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None - ): - # Required - super().__init__("unspecified", type, message, api_kwargs=api_kwargs) - with self._unfrozen(): - self.element_hash: str = element_hash - - self._id_attrs = (self.source, self.type, self.element_hash, self.message) diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/passportfile.py b/venv/lib/python3.11/site-packages/telegram/_passport/passportfile.py deleted file mode 100755 index c9516e7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_passport/passportfile.py +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Encrypted PassportFile.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram._utils.warnings import warn -from telegram.warnings import PTBDeprecationWarning - -if TYPE_CHECKING: - from telegram import Bot, File, FileCredentials - - -class PassportFile(TelegramObject): - """ - This object represents a file uploaded to Telegram Passport. Currently all Telegram Passport - files are in JPEG format when decrypted and don't exceed 10MB. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - file_size (:obj:`int`): File size in bytes. - file_date (:obj:`int`): Unix time when the file was uploaded. - - .. deprecated:: 20.6 - This argument will only accept a datetime instead of an integer in future - major versions. - - Attributes: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - file_size (:obj:`int`): File size in bytes. - """ - - __slots__ = ( - "_credentials", - "_file_date", - "file_id", - "file_size", - "file_unique_id", - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - file_date: int, - file_size: int, - credentials: Optional["FileCredentials"] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.file_id: str = file_id - self.file_unique_id: str = file_unique_id - self.file_size: int = file_size - self._file_date: int = file_date - # Optionals - - self._credentials: Optional[FileCredentials] = credentials - - self._id_attrs = (self.file_unique_id,) - - self._freeze() - - def to_dict(self, recursive: bool = True) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict` for details.""" - data = super().to_dict(recursive) - data["file_date"] = self._file_date - return data - - @property - def file_date(self) -> int: - """:obj:`int`: Unix time when the file was uploaded. - - .. deprecated:: 20.6 - This attribute will return a datetime instead of a integer in future major versions. - """ - warn( - PTBDeprecationWarning( - "20.6", - "The attribute `file_date` will return a datetime instead of an integer in future" - " major versions.", - ), - stacklevel=2, - ) - return self._file_date - - @classmethod - def de_json_decrypted( - cls, data: Optional[JSONDict], bot: Optional["Bot"], credentials: "FileCredentials" - ) -> Optional["PassportFile"]: - """Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account - passport credentials. - - Args: - data (dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object. - May be :obj:`None`, in which case shortcut methods will not be available. - - .. versionchanged:: 21.4 - :paramref:`bot` is now optional and defaults to :obj:`None` - - .. deprecated:: 21.4 - This argument will be converted to an optional argument in future versions. - credentials (:class:`telegram.FileCredentials`): The credentials - - Returns: - :class:`telegram.PassportFile`: - - """ - data = cls._parse_data(data) - - if not data: - return None - - data["credentials"] = credentials - - return super().de_json(data=data, bot=bot) - - @classmethod - def de_list_decrypted( - cls, - data: Optional[list[JSONDict]], - bot: Optional["Bot"], - credentials: list["FileCredentials"], - ) -> tuple[Optional["PassportFile"], ...]: - """Variant of :meth:`telegram.TelegramObject.de_list` that also takes into account - passport credentials. - - .. versionchanged:: 20.0 - - * Returns a tuple instead of a list. - * Filters out any :obj:`None` values - - Args: - data (list[dict[:obj:`str`, ...]]): The JSON data. - bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object. - May be :obj:`None`, in which case shortcut methods will not be available. - - .. versionchanged:: 21.4 - :paramref:`bot` is now optional and defaults to :obj:`None` - - .. deprecated:: 21.4 - This argument will be converted to an optional argument in future versions. - credentials (:class:`telegram.FileCredentials`): The credentials - - Returns: - tuple[:class:`telegram.PassportFile`]: - - """ - if not data: - return () - - return tuple( - obj - for obj in ( - cls.de_json_decrypted(passport_file, bot, credentials[i]) - for i, passport_file in enumerate(data) - ) - if obj is not None - ) - - async def get_file( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "File": - """ - Wrapper over :meth:`telegram.Bot.get_file`. Will automatically assign the correct - credentials to the returned :class:`telegram.File` if originating from - :attr:`telegram.PassportData.decrypted_data`. - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - file = await self.get_bot().get_file( - file_id=self.file_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - if self._credentials: - file.set_credentials(self._credentials) - return file diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__init__.py b/venv/lib/python3.11/site-packages/telegram/_payment/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index d365b757be14ce33315833a0a13e14cc54563dc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmZ3^%ge<81UIM5$^y}kK?DpiLK&agfQ;!3DGb33nv8xc8H$*I{LdiCU!nRL`MIh3 zxrs%|`TAb@>G{U`i3J7vWvO{(`Z<|N`URCG8Tom}dWMGj#hE3kx&?{J*@@|?#rh?w zIjQMIiMjgm1&Nipsd**(@$s2?nI-Y@dIgogIBatBQ%ZAE?TT1|wt(DG%nu|!Ff%eT MeqewRMa)1k0Mb-3zyJUM diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/invoice.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/invoice.cpython-311.pyc deleted file mode 100755 index a09eddf4ed1d3b1bd49d0c3b0329743ea32f28d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4496 zcmeHK&2JmW6`v)SJB?jJ)11gh@IKu^7~a0?VU^}QvR6eSt%AK>9~_}^b z8Py!yQw`gts!g4Z3e!C5ZK)pRtjd|oY!7;9ftjq#Rf{g$4;({dxqqU`Y{ZX!V%Vzb zORH7Sa6rlmeiAIYo(cm&84O3R2Bx7!T3K7o-!L>!>$nyC40e=Pe-;S&62fPsD8Ld# z)*1Rr8ss1KZ^KW@<=G21rnX{6CEn3Und9&2-RUvmrxt3YiQK4Hyv)N zNDr!RI5iK6W^`zjN>M0nZn)Ih1nL1ZHB)tgbsWiQRaLHT08b5@dW>5EihW*FO~c#H z(ZWNg!`f4Z2gZ?&hR!(CX)tVt8aNFzI9*UZk1v!w!!ucFCRBCiYTO9;jEy+I#o6XU z2}sR7CD0kTQkn_ucZ_H?&Y7)kmmoYnH03#-YAUMb)NBtrAfUj7Ts!PVUUnA(8@LF8 z7xdZ!tRhauOW6f_hr=0#18J)k%XN`Q9DEJ_2%J^=QpD;KdgZ5?I*TTY3#fvNGfCoo~lQ>GZVic+=B#({xl% z)}0#AHJhWKfT!${YE?~$0NqwQbAi=TX?^W7oy&dja|o%5Y%i7CG@-wxbJ*I80H;}F zxU39N>`^rs0;EI|g5!NlQ0n+~r?o z`vCxlS!%`MaH7#<&y#F;QsA5#8#Rx;Juh$1%iHtv#`BVm`BM1O@&}IG2L8~oTfmP6 z_l}=F`ku^xFZe07YAE*~s&Gf~4BY%2vnY-U6vq^nW5UKU-_hbwVS&VrU=EA<<|`4j zKMCIw4_iCsIsCo|74qyzPq&fO<9`*NL(hwDuR!WTohXqIQ;&d#a|ERx1x@T~B4}YA zP3kewLhneORC+c@rDuUudgDo@H=0zsV>i(fq&e+UC(oo%KKk1qA7teO5~WCOeo`@X1#=VEPbiykKR#wz$roK_ZoYO8ai-Cc1nbx41@D>kKx!^`vdd*N{E3N&X9-EUMjLQqqv z_ihK`RBIqUnF9D=YnUW6U#I_={%UYs6qXCOZYsBK=07bgLCfO3 z{+4mX+_<^+@n_3-3d^hc5IK&>Q`$!ne`oOzw^kQ#gxFEU9%~zF&vZvwyuG@fFRW$9 zar-fwQxrd?DDA&sAg2`tQ`$~XLQ!-_gJ#%H*MwUd#3-bMeiZIhj%?*f#$f$964p<5 zHsO|G86Ka+P9(TLq$sKl*-4OogBku4?7D!}6jtwG^)6NvDnHYqkH$<>QL+L*2dyq1 z#gF&|)I1qhXu|yxdSH`#pH}2zOllFVmW237d}p~u$#kwYaz1vhMZ)Uk&}b`$N}Pd(E+{#|-sMwxwT?%d^c(ziwVyX^3Or zu>FspR2m}4D+l6AD-s2-r2hjkJ>Sg!u9>~t5GVImP?KPfiEC3p_RrM3xz@pLPW z|7C;i$!7=nWl;RMw_Sw{J|IFs8ea-ebDK01p_)@dsr?s@>rA%R+-Jy(AYKr#&ypJB|M5kjyvw epF=X;=zm)AiXgxeoL=wR{|b8k{hI#3_x}Nk^2AI4 diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/labeledprice.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/labeledprice.cpython-311.pyc deleted file mode 100755 index dd41c5cdb21eed5a98607f8e61fa9712c3197233..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2768 zcmeHJ&5ImG6tAAo-pTHQAHhumT7eKUOYCN|3Npskh$grso5-%9bLp<>u9@jgcUN0g zlk9{&=HOj>x~pHk_p0js ze(!bFd^IyuLva24$>-}|fb^^Cd{KtE;GPUOTte4Fryu-wP@BSS(2p3ru3nTI?96!Tmi=oA|-FQp<>>JEcv;HM64G}P(cWKP!{N$8zf3XDjIrb6?%ij{f2vq z^drb8ew|5tnr2Q`GSs%1Tylp%&+yK^v3gy6q5&K>Tp_tzZ{SNAciLu+mKg?=`vwr3 z^3}wSScam53R5%z=^`Q_1S)Ya4xr95C$GmjjlDiT0aMTpCS%h8L_CUUXfYsI<9m7VIl{L21Vz)Do+d>iArj zZX|jL)INp8Lf{jzxLK?LRLQ!4YC7GOG7$~i_86y@%sv~7@s14)3p-<5*nbW2T0ObHg#IrBRXP8uGN>2Q%J3^m%R2ol_l&eglEArqmB1dsr(iqg zY9r?dpz-p9#(<8J)wB04G@lx`kyP63x(o07c?WIpvy7Bzv-pj17cBQjRs(Gso5(5T zKAQ#Tpbjk^QNA1uetvYQ^=`~s}rzJtd_Sj4F1FnufGaN^#Ak;>4{n2}NmqpZ$2=|!1 z%sOn*CP`vnq45L)up~BAh7Td}86kF$r`uZfZl0Kh> zMXnt@zyHL}0W`oQEi<}_SWo{{_VkpsD4246vKY$IBCsshJQ0a zo^~8{AZC`TCP&pa)Ey{KQ`ZG3M&c=heE z`QJ+X={$~=y2sTlI05Z*(> z1r+2*=IJ4`OZ+Hw6&GRyn%$yd7`w-jv0@C+g&lNcFnRBw#lhtL5X}!J@7>CA1IYPj Q^YPN}O8duSOggf^0P$iAIRF3v diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/orderinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/orderinfo.cpython-311.pyc deleted file mode 100755 index 9cfe5337659b1685d7319af6c0667a7d9577382d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3449 zcmb^zU2ogg^OnBS)p{@+PZ6#Z1w=V?V_!qY4O^oON!bh z-OPrH_R4|^V#gbt=PqXFrx**%PwB|)l2G&ue|i)<%@GKd-8nUHSC&Z7O*BJYNbp@}-6Oxmly?0xrH_yVYQ~{4X02_q%}n0lY*|1%syq9altMs7OiFfAle3 z)TNKG9wRXlKRmFZ$M?{QJ+usTVn{v-v>eeZsU}*%dg?~Lk|e1l(#Q4msDz#&F+Ce; z=sBQKM6blTh5U`|9oW^~!Okk_Ci*?DWFR6FUUJ}9?Ht65$0rEJP#g^KJGC_CUqxHC zH(VYw7Lj5qrNHPr)luvfh#`cyYHALIkFqFRb&YDv5OAZWxP)3WF{o13T$h%YYMMos&V*Eb&8`u(wqY$38gYrG8Rimf zT<1muO(#ecRqJO82*9TKGQrWFr>jnxtFVKzm6XTJ;G*)9<1+Jhn0965RfkY6Q5?t* z@8yAdk2wmLRr>pmEbx6lP*vd~k;dLLfijOrdC3i`sko;;4md_=LHY6M*{AwF_+-D$@9;@M@?ty$p2X6_%M1tI8w<6<6r1}Ldnv7M zsBd1?Ah#&AXGB@Qp=kzk42%J&hJ6|XA;FLJ)BFDf@IL+kxr`f((fV!;&4dyNHDdSh z9hkX0n8m1p8%PyGnT7xqTZ4~=2ozhjPf0+9`#}w~9%-TVNC&M)8fbkWzrwWR16!z- z2=U?n(Nn-(gP=nRb2JY^1=))^8+AfGSyhdi;i~FEe)E#5p{uMXI9@_sp@eLaLc)_A zVy+w{&;1NaDz6V!b=byOnJdcmZ(l2|*%m2T8m-!;OZKWgQ_|}7(p#kVR>?G$OZ80` z8qG}csi#Vg;gTQKwd$MNDsf6-m6g=GwrRmdREWKFbK-=veU#@583?-s)Yod>>S z0Qk>!^zR9j%-u|EC;lc+{Z*c7U24lyyK<=`m)dfvJN;Nw+D>+#_;FL}$cMWp3P7g1 z7cMjMSntTA9~D}Qos;K3lm3$WVzx7TrG2;p61kq7c{lS;=4Ng?*W}NASPXfRuDO~g zF551Z86Bs@-JrGVAgsV-q2%fJB_J&Q8mI->{?XWzWN+gJc2WY!kA`;vxkL7c(h0YQ z_>p~mkKKlF2U75El!jQx&w{v{jC4j!v#Jh5szksdt+ zT!$4AOF=pX2t5v9Ydp%Az{*7?8KjG!LSvKfUVG=-j=P&b(aE1^O1=D~k8tvEck+>2 zGw+?deXjY7ucyy;rpuo_{rNM0ex^P9+U|wdI~QJWU-|9s^c$V&H=0sAdwf?`zRo{% z^Xm3hX00{*Nws-xH-EO1KiihiQub|8kmg_%@LVCwYLPWORrOM;+W)EpJfo`Yat~$_ zs;b*nU_+HTrtLaVx$JzN2-hd~3uQ&etHMk3I%H0_b$)Iy8`Nf%n5L>0aNj|!hyASY z9rl?^8DMU5@-PGC6F$B$5tDtyz~gBA=lJ?XUq;8LyQfZf0iG}W>G9YhKZi~i{XD}^ z2zt3kZaLeQA7hL-I&^%;xo!CgM#*SwYDe6D+fOnog^o_Qe%d)Q6PkMX*v_vz51ra$ zFS6XnPNDdC@3|LzF&&%n5rFRG(VbU1lP5W+d*Q zjR>}G{Kgl)W1dHidk8{CPlA`cxVye`!#Un%_=Y}3{mrp7|5kpspFz*jCxK)UcK!&!7cs{E zDTFWMHoDY9r`rd;J@k|I=-Wjz?a{ZpPq8PCL5<*JUFiqy(btck#}JtP;8yM%#{Jg; IQ~WId1tD^K0RR91 diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/precheckoutquery.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/precheckoutquery.cpython-311.pyc deleted file mode 100755 index 55fe169831d2d3c8f8174d9f670a6b90e770fe4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6482 zcmeHL-ESP#6~D8ev+G^2KjRNk)TzoL{%RA(566;;E_lE1RGgmJ5no46;k_9X;7%t^3-$g?96&MPT{Ff z%+B7qXYRe{oO|x?oO|y4DVdBDxc+?o_vimOK*-;a@UC#9a`$bh+#o8+6IDusEJ*p>4$$YZZneP+`4X_CC z5cO24E8iuM0C|R}v8zOl)9CFWA$Q>KUiogdV~(T~YiH+|HB%}XYE`FF(I{JrRyHN2 zEEx;uY0;9bWyO*htuSiRvIQ;DJk{wEQ%chFjGkJi#S2E&dZ9|$YUUrvI~}l-^RGNV zC7*hB>eSiknP+Tqwqj{US<%yi9h+q;Wz*$F1BgzK)hw36fOp&j^IP14gDKFMy!~s*n$= zfqW=NVnlsF4XUAAf*Ph_H9{k56rLiDsxf%RsYt^^K2Nm+=-4hg0d%}cFLteyML|to zP31di0(g(8ovl686cyF3<_NVLXwsw?Bb-Ce)#PoEddHWXPa-$k>Ha|D-dka{kEYcA zHVyaDF52DXrw+8ygKhLs8{IY|&@Z*vr4C<>=6lx3B_ZDnFd4PG+80~-k4Ol|P6H@D zb~IRAR#I@uC1nA?foRgoMWdvZmm~nvM6rPy=?xB>cwBo9H%9$DfkE#+MHZEx>hH6a8DVD`@ z1x+nTAeFafT#aT7i{|)n)Ni^hJ-=!#!=!Q-=<15W)Ldba86`eU0T%(}UIhNwl92$% zQVz8)F}mn>l&jDKdY4U$Dr!TF$w!-=i-tLDUGr*b6QOa#vD9}q4J_Ht>qRHA!P-y6?Q8RPi1ROoKY*`gEm(3OpMl=4h8Eh%L zU|43>vt_nz;K_pAI!n!x%w=Q6f1w;dIRj>)~i#Wl) zO(y2DR;fUMkPW_B$gQpbIP><9oHXtGfrkQbaHE%0Ts8pf(!wfQq-9>{gH55}s+7qX zu=a2tf2S(6NawF%9x$fDjEmruYD19ZGUxK1grK4=R4w|WcmL?!KYF+4pnH2a1bi<= z%>4hoyG8o9WtrD_ydOXwE!M6&&6cfM71$X;MbM!ewkf1N;F$iSkcIyF_w(u zS*23RUZmxVSzTMmR(OVaJTp0&H8qP)RFvWcWr>!EAW z`u?Nv=&X+(f=9Cc(8PLZTO6t%JdV$i`s68m?yqNm3eBmV;RkOWxjBpjcErT{iT4uk zc3$gT=fArklh`3uu@pN9xee<;I>M+`W#ys|BY25G;m{oe=pl4#WCLE^d)3+i`le75 zOgQJw5o;H}CZKA<#;*5GekzQ)4Y0f8L$4NSqv25g7!0s{IFemJ1-?Gin_LM|L#+<9 z2iFkinrx10h4Y55QL_iQrceuf5^mKHKp$Bf$3!#-ndkDZBS7l`JEKw=GtWY1#tvc7 zasvwnk#vAb@L&&NJ!*FV%$P}KTrr03YDXJm?O?^IFr2a-T%r~m!~r2YSk%oX2Q~_C zO$-Qt`z!20sIbFOtPS3S%?4XUrFj(!fTj~CUA^yLe(&;4Yb$kdJ9Th9w3F&}h!7jB z_YQn;;_DIV)^i{BeLDE@;Ae+FKe&~CVmtlB7rk2}Q`;j`>!I~mx5S~pj2_+|&3tHm zdgT(j=wG{IDnbV$bqFGIq!xt; z50UqdAAR2*WLqm<1R z$f6-0$zDK`c|towKJKp|oaFq&L0Yu??^P5w1C{|}vMd&RtQ}wHnRL*Of-}fq z4twan_Tc+RT4W>0>-)KyxHO)-g#x_IcfrO!L?9c*u97B(>!~BHLPGCLR*nW#t*JU{^xX}pR z<7aLt!jQ|bz-VWF0WA=9yq^UwobG|}fYV2y){iyf z6+4NP6GkFJ`UagS)tU*7IJ+$NBYCiD|QlH zP8f*@8I(4H*WdI;4eY;Jy>2)i*p|Sy@b$}15~)ryd|>0yt^H04sV>s!*^N{W+JR4; zi|HfrPNyFme1Z3^aVYX7ok{nwpTM%(5o;B{CotUgIjHOhyd)~)B~clknez{pd`BB> z_V8-%*G-0biQVbF%!j_f&k06clp7uzu_(4-lv_<|G&e* B<5BMwTp zl3sNW6{MhSA)-|K;0#Ervh%QN?d^O;rzqsi>6kvPGf zU%a~Tj%{)?RwcTP#e?k{5TAmH1XU$4Gi6EDw3Vu6hLBaX(pKg>$;y%}7?iW}aF^j4 zB0wGKOS1|vmUqVW;u@+;*6`i2>d+dxB~=Sx_((XmOMSzV5sJWwE$@R-Gnj2++pGK3 zHH2l@sQE1pP|z3w9K;Y53K&|?R)+mLzz67>j==yqDgbr^gBmr!+V(If)Qx75k6VUg z^R|MQR{a?HXDp9|gIdhC2qhMdmQ7(>Y(s2{D+cGZqVw26TCA03HVxV!nr-PAw24+J zJxvt_uMoPdTxsV>vcq zmvjx#v&adO}ZoB@HPLFg1N zmpz}C%ee0N23IY=1rbqF@Vj6exn;P419pOO5Mn{J8$^<>f4F!OgLlsB`qY3}T^~^X zO*|v!D0q<&5g52kZUtosQOH>$++=%$%XdIlmKj9%^ZH5MwGdo1sF=+$Yx=7!(!y)G zHP{?1vFrvw1quObLO+X`HlTuUK7t-mDw1E06 zB6IC+t-FVZ!M*S)XR7wI~1a3xhtd}jQQbcJIu zsd$vOKv=k^4eAS}F@nl3 zwLnK;W@#wQLY+ZqC~KMxXSb&93sX1*wUZ`_D;DOpI#fKjNl6Yfj5zgu7e&~@N-e7X zG>r)rMHK+;&XbSSrtcEfHK^&U^M1phRgEA}SBSTwI(AJB+Pvv|v&zhj%4|-i1H-&& zGze3Z5KxmCP?I7w4rC>0(}S?p?TK9lu9Da}2V6#=`{xe&`w$u$y_dhA|5cv&MV@#t zzb;SwEUO!`x-P4m$4{+g?vHG~I=zPll)o`2uW6QV!ec;= zIZze?nT8`fOha)%Mc7ag1(Av2NQ|yY97oei5*-H?6Os28eOb&BArf^*1w+Ix*qr>j zsS{bbi$pgsFp~I8iyr5(>dAvI$ zr~*25raLUCB04qwV3LUkx$`x@=(!Q+;*4(YYFS2CvbU$dK(C!p2!z_{!cZW{K7p>AmL#cr u8c82W>*(4RI=Vji-$JwNga1ubULX8-b5|q@V0?D}h4*K~`D-73q~pJkjA(rT diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingaddress.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingaddress.cpython-311.pyc deleted file mode 100755 index e3d9ea01e25afb3d32072af2eaf1a84e9329e4d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2782 zcmeHJ&2QX96d&)Gz1!VQo3{Dr7e=ZITQzHvNIgVQQGr0sApxaAXoWO!?AgRyuWiPY zwu$zTLnTra2@aql#Gzb@s`AGK6p7TQN*oY3qkx2Z;=NgWce5>p14m|ep5L1{@6CI^ zd7klil}d>~d;G=Mt#6MI@-qr)%O}jiJTUi&O&Y{j?2N0lGmVUbeAdmjbB&zjb8fy} zXcQEZA@349e}~uwmV1yTh=Q4d1q&4c5%5 znRGThZC3C3kiicbFJVG5eKQDL$3j^97MS0V!CMINfXiND(?b*Aad;?n1VV569MRRy zq?Dg$J~L###9))`f3WYtH)Nc=Gdk)M5agOyVQZb0b;15e_CH3pR)}&~Em3)}QlnyT zhoZbJzo&2a5$?8*N~KvRFL3F&PRY)DiCZ6^a6A| zfe+4s^rdo-2pmn?19(141#*8t(;Flm^?T(3Xdd;n3h5{vLNn={P6i}gL$*#9q+CzR zft21Pq>~2;Ba*FC04a@?bV#f3k+k~$NUQISwEDhCtM7@ldVZSd6`|>_LGB}9&$Ppt z!wp8@u+A*-D$J~vU|ZG$#v_eV$8!XwFGf8oQpcuvLWYq_oAB~)vRX09h0JZf*i!Bn zm{WO>QyOBhc(P&Jdis&E=C_&AHo4^+^Zu$oYruhI++^NO!*y1SU_-3=-fVq(+6W!N zrUKKtVXm^!5XpUM(7@bi!zF5j$;FwTHo*oTg|#*(hOVc2n(`Z<4R?V2xkdgMBgN`n zbw~Y4oA^tMg>+5K$8CA%vfHF36j^;V}-42@p*Ew9v?rGACE~&o{UY#c@zrd=W~H%d;P{p!QL6BmYD_MQJN$0yRj7itwc1OeBq*#>0q6%3&#!XV9UZTa0tmm(p>;CdaAwN-GwXsJctNhcpFHZ yRTL$@K$Q2DUGm-&a(egh{|TAhJ^bG%7k3Z;MCeBV diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingoption.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/shippingoption.cpython-311.pyc deleted file mode 100755 index 0555c4f946d9c1537be6c23857035c535d530d7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2590 zcmcgt&2JM&6rc6y+OZu2MF~j299kNqvJR!{!9u8oB1&2%krGwKs9mpj$Iiljb!Hq0 z@__?VLq*jdT7fDKoTw1}6ME>MU{Iu{D^-frQ*W-)N)@NRncX!u&@1EJ=Qr~{X5R0; zee+|vTtqN_`|gL!VF95(#3UKnnAu$i<_@w@6IqItauhe!Oeum-J83u5%(&TRR?ag{ z&doRTlFvG-TWA&}pL2@tRC7u}Btvsxmv>5Txmi|F3Y|xmdJ|a%l7Em!=n=fpXjZJ^ z3aU+Azp%PyGwk|S&mq|KJ#N?@!-j|b_GMyn%-0N#DG4ZH#N!~rtHdE)YPfi1%?<+F z>n;V{_C4)S;kl-S>I(UyM?90%Qek=Z;_^BD?1$&hesp2+e5gjMh68Gq#Ltr42v+t6 z24zHNvAJ&0u5h=ovb6YtZF1mC9~*7h-CCx$Nz6DD`6popZub))Ujm#2H5Gs~Whu?H zm1<_Jw3WH1SXq*_a`5I!&QcGIJP3fu*u0}|qK;w}Z&sRxO>|9ZO0dGpWXQ%|z*FKE zgEfYe?-9&mfUqASR4if`QM?TM9RL@wHywiku2jJ90t7}IGGTj|6Y5GWz{7BCzM&@QMJGCU&2R&Uu!eLY&e$-# zjYezP*l;1~_>9l-DH1DbLA2WT`RP_<|32-G+1eJKYXBgP7UQ&4YmDk7h5^I*JZ^Vv zLbcI`+~yGVq+L`jSc;x$1|s(i&m~oMsUZPuw0K;X+IW$)K7#{%Y%?z4mZmuHsi;>L z2QR`EL(}j&p$sJEn&EYc)o9?i=e7CK5hFE>`$>VyeW6HMKZXJDwc9;D4&*BWgZChR zuO11xZ3F|vp5RbRhbh|%b5W+ktW4nILnSO4fvsP;Dj=gJ`1WW;kg_1q91*PoF*88K zP~a8qO1!&IfPAmqL0qiH;{p6XN+#(3m}Inw`k9}U2OxPgk}9aL^pT!Qbowcni9O`t z;vDhlrzb5zFKOARk1mfqbcDa$$O_%hC;a&TiH8sq#UO;H5>bmXO zT-V3&5$+^NVL`VoU3|qX%{rZC6^-tD~AgHesZ@uo=?Rv1m*L?4!cH%^x*_<2?4D*W7C9Ix&V0Ari0rjN8 z#r-YVp!;B->ob#WQcHq51wwWa$iFwxKUGwy+{)k1|EkVDQD^Tj4Aj}jYJE$s57he3 z%z@3!?fmw^Bk))Jeg4cZ?>?Si*qUE}>D11_!}s32dl1;lj#~Pr^i}Cr<#uIL{&vAR z+-d?x&v1#ZhechFE;ryyx-MF2EXnJ-<(se!FfqsH4A?ZZEGnvjid0io5D`*Xj-fP( z=R1{TsBw5t-9=9E)!ROr**M_*w zg(p$J;r{2fU>m|Dz@eJRqAnnie2Ah03uvFJr=kp=rgJbAn6saO4AY9D438pZSs9?E zZS?wJ^4Uhm1}}Sd(8<<`C9o}>Ax#u3<`#T@>Z)33tg6ppjes%p1T?qYyGTs$vG@kz&8V`|za!BD6pT_CF zoR6bzzvkEZ9Ipp*0mk!MP!HuotR2tE}?hk zIyr=S5(S-MtxNCDb+hq^)}#04dO74nZy=@P4pO2x{Me7s6ZpATu1|?gqhx&P+~s-I z6m>%>Ygo)1MN3wTrYILhWA-}ETcR~DTOz?Ff=yhsU_`u(H9SXTU7Vg*OC_~9_v11q zi>ZH6#YxTdT2Up$|E!xpAWmTDAb4a5@O>{E&Yx=rYc zdzz=%($K?SF)@K>^vvYhQ&--+EM=#%lb~0)Fg=w$qvkD8dFJZ*VySF_l>f9rA8}8! zyIQ{S#_ZACV4k1g5c&{K2csMZC*)JOoL}+fc*U>qE1VL*0VRloN(i0;4k=+Q;PAGl zrb1*H6*whwC!UMojxbV&l#X@@*l|ILwPq-B;8BY&1eu1!o!Dd0`lP8j7Y!rOw;jja zKd`5BC7^WSxY7+PB$S?(j#f+Qg|WZ}z7Kcet_^(uCVpTOKe&nC^uAzyywI&|yA#TF zFQcDvxgNmIupRSunjt{`1klCM)PPPCO=_`V5M8EcFUqq<*`oMTi+Mu_^oV8yMk2rl za1@D%aJdjLMWX-+1c2r>*#z(ric!5J6L}Wksuo2H6P-x`=wwZ`7E|Ko1)~ApEv7T& zV3?^Ym|#U@)5b-WE`wDfW@O7EnHg1?5n)v}+OQ~VSUAI`Q~S;r#Y>CUJiJim23}k+ zh?1Ep5JP9vWN;V&?oH57M^YldSj}QmX*dDr^uYyT0>RD{TbNH z%#3M~nPf)1QdD7&+oGZ@Ueqt3Fqm`iYF^JWLuVahbqagdv9To2cAX%Xxi4& z?kN!)O1xcyBT{F}7XJTU{or0PSR{En+=PYgQx!Y0>45D{Z=b!x%6`t-5xJyFHx^_- zB!LWvNGB!Tl=M*22PE&MItZqSrWX2p{udy>Ra^`Lcv& zjHF-(%yJ16TaYBRs9KV=)t=a4NmV2oKukL%6$r*lI2p2e6KjR7*l`#$b3p!c8~wW*h2wWa_d;I_gI@`Q zs~4)m;F^%G3F)ekt`BTm=I@2-Bm3bIukSvx%-4kB`k_JNR;wHf~_(s=9}jWo%GZgrp5ph6jK$n3SHm7Dw~k= zK3CyPNb1wb+Mut6i3+#6p}(b1fjN%>IZvACsrWYWP`(|530Al@t4(hcgROCd6uuqV zTWIB()>vy+J0e$`7PTb6XSj;*X`tOgz-@48d>TW_(XlnZAqBM8S1AQc*G;21lgipW z4H2%3Q}0gt$Ot@$NZTR11E54qEYTAq0`%FT#$4N9GD?IVlkK0w78#%uc-x=X%$5c+ z4811xQ~>vFvI81q50It4b_h0fUZT<;0s#a%5!Bi9@vV<;J+jskyK9Nv%lvwx$3a|p zu--Fpf8v{Aapld=dVfFoyTLE^ez|)sd9s!~`RAUs;mO+Y~m=J?VIuyd-#3TuQWQ>vnl#Bz(dy$Ufs{?)?!0&kl$VJ3KA^RfF*o2~HY=w!< zYh$#eh=RzYC4!Tu8&9$x$O+9&Tlc<<}JSH9|drM`35%3M9sRo`*2KD4jCZ4afx2WVs9 zC8r1VXP%)*f8<+A92DvNK@yI*Zo_3EiDr|%G;?6PkXgeOb(5QHD_T6Z-AVl9=7WQYQ^_hQeYBq5ERiZ5j;hlkq6Gh3F>u?|VQGNeJJ$caSqrJ!@>(NdpK$#%gKDv6eI)1D+ zdb~Dt!U@q%0S$_){s-@Sss=_Ll^+;RjE=?WSm41eCqcPRG_-4V&&r6?MY(R&knEvc zZ*xc3+WjaJcLwM{(~1|i7~a^qWt08nD4d-QL0QuvD8qNBnUZJo3=wwFTBQHAAT*#d zJlQXKHB-u~nVJEq@#W#BxWSg3*K$8~39a1hxYwCt-(YU09Ny4rshSB{w;-1_>!z&1 z=PpBQ-)0do5SuQ_8GHp#z^#sBU$y p`#T-v<6h(H{BX7XuJb3W?Y9%maU8&8YkEKXjE#Kzf^oJ<{{;blGl>8I diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/successfulpayment.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/__pycache__/successfulpayment.cpython-311.pyc deleted file mode 100755 index 8ad1be2b76a765df56da555c8aecdf11a7a7fd32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6783 zcmeGg+in}jb(Ys9MN&7*l4YyeG`>-hxz(j0wciC*3K>5qNzuEZvBq4uA#4mBLa_{F*d5`F%NOVDum_jiE@2DBA z#EP*>ycieod(2E!lEoyi$4#-4DyDcnVWuks#eqtunBjQR%vN&6oIq%dC19Lr4pxSW zLjsAA=ZK!VLG(0D-HsA+2maks9M&VtBtLNN`zvL`mMWHBH>spqRYx_dwxm`iYjuNa zj^vb8M`EJrl_yI5Vb0Ll5pE^%%!@(8`^FjaFD=b8b1lr?5m6rHZA zbyU@s69qzk0Sc$2D1g#I*~O?H zDaKO7|LF(ys2+P?(Bm|&Cul-X!drxY3jS#dm`{uleE@K=2hRYW+TdnKjy)||Xc_3i zb9?YXz%ya{+QBWdCg?*q28&smOA&osAMWp=kI_-N@bsN$z+G zAf!0BMXn0PAu#%cJG{?ys+%E%yMkx;z!g?i+t4Jm1*@oNMM+(?>JB)99oS#0c@B_H zOHjJTv?Xf|+y}f%GgTWrhoOU2YARD#!PktcwN2^dB4})}WIL>sUzAqLjM7skbzpAN#pO%V!rbh4!p@qd z(;3NPQmORH%1fn^1X}f#XM;)t^2nm$tSjK=%x)Bd?~diDrlMA?de!k+8&!w1#wMx8 z46Uo&GL`I#YMKx#QoU+G>~ed65dzU+BweR$CLoV&r>CoyGd(S>nU?Cvx>W~jSPUE* zNrsZ-LoFE9%N7_4{SMTu`=<1~2=dq|y9TV+3~+O=FZv1g4T;$GRa;{Q&#ek*(qKG5 z65^SV9alX2GwNzytk!yeORy#z}l!*Gc*&*30KfK1W7zRz`I_bY81!ZhDb| zCdN`INS7(IG4ty>)fX3~x!J{1Ox4H_@y61gzVXg)U{`;;dk{4;?6ovS8)zw-EmfUJ7Hpe5!klq<-Q)q5avm zcV?JH{Vj$U&JyHkZ-Swy56<0tsJ-YV`M^lM)VMC5fpx=JtvmGV1pjq{|366Z5JLWr zyU>&1`{KSQ+4m)>FC)SC$@di{_-w7yePVv-rfGvhk~0{Yliar z6*$eqJ74J~(qR)I8x22mn@pGE{Q6st;-+9zr{JO0c9U?^LFqM`&$=<2nrnNhg)~CC z{nWU9fuzFs{fc7aq;L!Bm+N2rL@rwuDpypdS@QGNx-~DWwVHgHRxit@u`1U#ow8M( zFU-!$w&BoIHC20EU8lC}JE`n%-Q@7_@9ohFwM}*yI9{9FcezmTRaAj?`&R(|ah-hr z4U)>emAsk!vpDf5abo-VrZ}-9$}LfDigJ7E*jDUjw*By_tyoJu)IK_o?<4Kmv-p0f zEk6OxgKhaDq9=m)xf0^}_RQn>KGdE&$Gh)Nexo({#K#M*CyUKPuffRNu9$fz^LFN~ z+|Aq;|J?(jh#P}NQFWtml4R&nZh}##&Z=7A!0-_r7V&#$!09n)zCrI6ZP2x;sHgKw$0}^G4JOf&y9}#3{Om zQ}k|ZAFn9q)e|uNVX_^_70v)THX?W9{j?yM64z$%Dqs=L{^juArr>Y?yZ1;1oho?t zFBO);v%0b`rp~L;GFaV{#Lk?cV|b5AUSO(C9mFzWwGc zXJ_zeYw+k+Y*9o>3IMne$qbilT#Z6wEQU3AZg!jlzwE8-=?OhH1U4@Tl%oToLz|cbK)wF26FD6h zI|M;P7#L1mzt}lRPR+Kb3+<=Rwog3TJ~i7JpNfxnCdqW6a~NyH2fHIU&LkQ4F;_T5J7 z`036lemFqJAG+ndTkVV?b`Zy|yuaj217lxl9XP&6q)@nS?F>l_@1A+K6CH`qcL;#? z=;2!zTBFDKm-fuUM=#&K#Ou4M;pWJ(R_b^s?)T*bLhxx6h~0Rt6L~;8_Y1D*{0Ng# z=?e(v0YJEI;%x-O9L0_89`;v-g1;)jJseyg@VjCjdJ|y}zt+88X1LJ1J -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Invoice.""" - -from typing import Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class Invoice(TelegramObject): - """This object contains basic information about an invoice. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`title`, :attr:`description`, :paramref:`start_parameter`, - :attr:`currency` and :attr:`total_amount` are equal. - - Args: - title (:obj:`str`): Product name. - description (:obj:`str`): Product description. - start_parameter (:obj:`str`): Unique bot deep-linking parameter that can be used to - generate this invoice. - currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in - |tg_stars|. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, - **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. - See the ``exp`` parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - - Attributes: - title (:obj:`str`): Product name. - description (:obj:`str`): Product description. - start_parameter (:obj:`str`): Unique bot deep-linking parameter that can be used to - generate this invoice. - currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in - |tg_stars|. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, - **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. - See the ``exp`` parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - - """ - - __slots__ = ( - "currency", - "description", - "start_parameter", - "title", - "total_amount", - ) - - def __init__( - self, - title: str, - description: str, - start_parameter: str, - currency: str, - total_amount: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.title: str = title - self.description: str = description - self.start_parameter: str = start_parameter - self.currency: str = currency - self.total_amount: int = total_amount - - self._id_attrs = ( - self.title, - self.description, - self.start_parameter, - self.currency, - self.total_amount, - ) - - self._freeze() - - MIN_TITLE_LENGTH: Final[int] = constants.InvoiceLimit.MIN_TITLE_LENGTH - """:const:`telegram.constants.InvoiceLimit.MIN_TITLE_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_TITLE_LENGTH: Final[int] = constants.InvoiceLimit.MAX_TITLE_LENGTH - """:const:`telegram.constants.InvoiceLimit.MAX_TITLE_LENGTH` - - .. versionadded:: 20.0 - """ - MIN_DESCRIPTION_LENGTH: Final[int] = constants.InvoiceLimit.MIN_DESCRIPTION_LENGTH - """:const:`telegram.constants.InvoiceLimit.MIN_DESCRIPTION_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_DESCRIPTION_LENGTH: Final[int] = constants.InvoiceLimit.MAX_DESCRIPTION_LENGTH - """:const:`telegram.constants.InvoiceLimit.MAX_DESCRIPTION_LENGTH` - - .. versionadded:: 20.0 - """ - MIN_PAYLOAD_LENGTH: Final[int] = constants.InvoiceLimit.MIN_PAYLOAD_LENGTH - """:const:`telegram.constants.InvoiceLimit.MIN_PAYLOAD_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_PAYLOAD_LENGTH: Final[int] = constants.InvoiceLimit.MAX_PAYLOAD_LENGTH - """:const:`telegram.constants.InvoiceLimit.MAX_PAYLOAD_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_TIP_AMOUNTS: Final[int] = constants.InvoiceLimit.MAX_TIP_AMOUNTS - """:const:`telegram.constants.InvoiceLimit.MAX_TIP_AMOUNTS` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/labeledprice.py b/venv/lib/python3.11/site-packages/telegram/_payment/labeledprice.py deleted file mode 100755 index 3aa7091..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/labeledprice.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram LabeledPrice.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class LabeledPrice(TelegramObject): - """This object represents a portion of the price for goods or services. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`label` and :attr:`amount` are equal. - - Examples: - :any:`Payment Bot ` - - Args: - label (:obj:`str`): Portion label. - amount (:obj:`int`): Price of the product in the smallest units of the currency (integer, - **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. - See the ``exp`` parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - - Attributes: - label (:obj:`str`): Portion label. - amount (:obj:`int`): Price of the product in the smallest units of the currency (integer, - **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. - See the ``exp`` parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - - """ - - __slots__ = ("amount", "label") - - def __init__(self, label: str, amount: int, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.label: str = label - self.amount: int = amount - - self._id_attrs = (self.label, self.amount) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/orderinfo.py b/venv/lib/python3.11/site-packages/telegram/_payment/orderinfo.py deleted file mode 100755 index ddd7aef..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/orderinfo.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram OrderInfo.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._payment.shippingaddress import ShippingAddress -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class OrderInfo(TelegramObject): - """This object represents information about an order. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`name`, :attr:`phone_number`, :attr:`email` and - :attr:`shipping_address` are equal. - - Args: - name (:obj:`str`, optional): User name. - phone_number (:obj:`str`, optional): User's phone number. - email (:obj:`str`, optional): User email. - shipping_address (:class:`telegram.ShippingAddress`, optional): User shipping address. - - Attributes: - name (:obj:`str`): Optional. User name. - phone_number (:obj:`str`): Optional. User's phone number. - email (:obj:`str`): Optional. User email. - shipping_address (:class:`telegram.ShippingAddress`): Optional. User shipping address. - - """ - - __slots__ = ("email", "name", "phone_number", "shipping_address") - - def __init__( - self, - name: Optional[str] = None, - phone_number: Optional[str] = None, - email: Optional[str] = None, - shipping_address: Optional[ShippingAddress] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.name: Optional[str] = name - self.phone_number: Optional[str] = phone_number - self.email: Optional[str] = email - self.shipping_address: Optional[ShippingAddress] = shipping_address - - self._id_attrs = (self.name, self.phone_number, self.email, self.shipping_address) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["OrderInfo"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return cls() - - data["shipping_address"] = ShippingAddress.de_json(data.get("shipping_address"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/precheckoutquery.py b/venv/lib/python3.11/site-packages/telegram/_payment/precheckoutquery.py deleted file mode 100755 index 766f2a4..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/precheckoutquery.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram PreCheckoutQuery.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._payment.orderinfo import OrderInfo -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot - - -class PreCheckoutQuery(TelegramObject): - """This object contains information about an incoming pre-checkout query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Note: - In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - - Args: - id (:obj:`str`): Unique query identifier. - from_user (:class:`telegram.User`): User who sent the query. - currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in - |tg_stars|. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, - **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. - See the ``exp`` parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - invoice_payload (:obj:`str`): Bot-specified invoice payload. - shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the - user. - order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user. - - Attributes: - id (:obj:`str`): Unique query identifier. - from_user (:class:`telegram.User`): User who sent the query. - currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in - |tg_stars|. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, - **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. - See the ``exp`` parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - invoice_payload (:obj:`str`): Bot-specified invoice payload. - shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the - user. - order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user. - - - """ - - __slots__ = ( - "currency", - "from_user", - "id", - "invoice_payload", - "order_info", - "shipping_option_id", - "total_amount", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - from_user: User, - currency: str, - total_amount: int, - invoice_payload: str, - shipping_option_id: Optional[str] = None, - order_info: Optional[OrderInfo] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.id: str = id - self.from_user: User = from_user - self.currency: str = currency - self.total_amount: int = total_amount - self.invoice_payload: str = invoice_payload - self.shipping_option_id: Optional[str] = shipping_option_id - self.order_info: Optional[OrderInfo] = order_info - - self._id_attrs = (self.id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PreCheckoutQuery"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["from_user"] = User.de_json(data.pop("from", None), bot) - data["order_info"] = OrderInfo.de_json(data.get("order_info"), bot) - - return super().de_json(data=data, bot=bot) - - async def answer( - self, - ok: bool, - error_message: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.answer_pre_checkout_query(update.pre_checkout_query.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.answer_pre_checkout_query`. - - """ - return await self.get_bot().answer_pre_checkout_query( - pre_checkout_query_id=self.id, - ok=ok, - error_message=error_message, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/refundedpayment.py b/venv/lib/python3.11/site-packages/telegram/_payment/refundedpayment.py deleted file mode 100755 index 46ef4e3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/refundedpayment.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram RefundedPayment.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class RefundedPayment(TelegramObject): - """This object contains basic information about a refunded payment. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`telegram_payment_charge_id` is equal. - - .. versionadded:: 21.4 - - Args: - currency (:obj:`str`): Three-letter ISO 4217 `currency - `_ code, or ``XTR`` for - payments in |tg_stars|. Currently, always ``XTR``. - total_amount (:obj:`int`): Total refunded price in the *smallest units* of the currency - (integer, **not** float/double). For example, for a price of ``US$ 1.45``, - ``total_amount = 145``. See the *exp* parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - invoice_payload (:obj:`str`): Bot-specified invoice payload. - telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. - provider_payment_charge_id (:obj:`str`, optional): Provider payment identifier. - - Attributes: - currency (:obj:`str`): Three-letter ISO 4217 `currency - `_ code, or ``XTR`` for - payments in |tg_stars|. Currently, always ``XTR``. - total_amount (:obj:`int`): Total refunded price in the *smallest units* of the currency - (integer, **not** float/double). For example, for a price of ``US$ 1.45``, - ``total_amount = 145``. See the *exp* parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - invoice_payload (:obj:`str`): Bot-specified invoice payload. - telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. - provider_payment_charge_id (:obj:`str`): Optional. Provider payment identifier. - - """ - - __slots__ = ( - "currency", - "invoice_payload", - "provider_payment_charge_id", - "telegram_payment_charge_id", - "total_amount", - ) - - def __init__( - self, - currency: str, - total_amount: int, - invoice_payload: str, - telegram_payment_charge_id: str, - provider_payment_charge_id: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.currency: str = currency - self.total_amount: int = total_amount - self.invoice_payload: str = invoice_payload - self.telegram_payment_charge_id: str = telegram_payment_charge_id - # Optional - self.provider_payment_charge_id: Optional[str] = provider_payment_charge_id - - self._id_attrs = (self.telegram_payment_charge_id,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/shippingaddress.py b/venv/lib/python3.11/site-packages/telegram/_payment/shippingaddress.py deleted file mode 100755 index ed97e02..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/shippingaddress.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ShippingAddress.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class ShippingAddress(TelegramObject): - """This object represents a Telegram ShippingAddress. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`country_code`, :attr:`state`, :attr:`city`, - :attr:`street_line1`, :attr:`street_line2` and :attr:`post_code` are equal. - - Args: - country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. - state (:obj:`str`): State, if applicable. - city (:obj:`str`): City. - street_line1 (:obj:`str`): First line for the address. - street_line2 (:obj:`str`): Second line for the address. - post_code (:obj:`str`): Address post code. - - Attributes: - country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. - state (:obj:`str`): State, if applicable. - city (:obj:`str`): City. - street_line1 (:obj:`str`): First line for the address. - street_line2 (:obj:`str`): Second line for the address. - post_code (:obj:`str`): Address post code. - - """ - - __slots__ = ( - "city", - "country_code", - "post_code", - "state", - "street_line1", - "street_line2", - ) - - def __init__( - self, - country_code: str, - state: str, - city: str, - street_line1: str, - street_line2: str, - post_code: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.country_code: str = country_code - self.state: str = state - self.city: str = city - self.street_line1: str = street_line1 - self.street_line2: str = street_line2 - self.post_code: str = post_code - - self._id_attrs = ( - self.country_code, - self.state, - self.city, - self.street_line1, - self.street_line2, - self.post_code, - ) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/shippingoption.py b/venv/lib/python3.11/site-packages/telegram/_payment/shippingoption.py deleted file mode 100755 index 341dbbe..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/shippingoption.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ShippingOption.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import LabeledPrice - - -class ShippingOption(TelegramObject): - """This object represents one shipping option. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Examples: - :any:`Payment Bot ` - - Args: - id (:obj:`str`): Shipping option identifier. - title (:obj:`str`): Option title. - prices (Sequence[:class:`telegram.LabeledPrice`]): List of price portions. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - Attributes: - id (:obj:`str`): Shipping option identifier. - title (:obj:`str`): Option title. - prices (tuple[:class:`telegram.LabeledPrice`]): List of price portions. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - """ - - __slots__ = ("id", "prices", "title") - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - title: str, - prices: Sequence["LabeledPrice"], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.id: str = id - self.title: str = title - self.prices: tuple[LabeledPrice, ...] = parse_sequence_arg(prices) - - self._id_attrs = (self.id,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/shippingquery.py b/venv/lib/python3.11/site-packages/telegram/_payment/shippingquery.py deleted file mode 100755 index fadf88c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/shippingquery.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ShippingQuery.""" - -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._payment.shippingaddress import ShippingAddress -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot - from telegram._payment.shippingoption import ShippingOption - - -class ShippingQuery(TelegramObject): - """This object contains information about an incoming shipping query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Note: - In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - - Args: - id (:obj:`str`): Unique query identifier. - from_user (:class:`telegram.User`): User who sent the query. - invoice_payload (:obj:`str`): Bot-specified invoice payload. - shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address. - - Attributes: - id (:obj:`str`): Unique query identifier. - from_user (:class:`telegram.User`): User who sent the query. - invoice_payload (:obj:`str`): Bot-specified invoice payload. - shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address. - - - """ - - __slots__ = ("from_user", "id", "invoice_payload", "shipping_address") - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - from_user: User, - invoice_payload: str, - shipping_address: ShippingAddress, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.id: str = id - self.from_user: User = from_user - self.invoice_payload: str = invoice_payload - self.shipping_address: ShippingAddress = shipping_address - - self._id_attrs = (self.id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ShippingQuery"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["from_user"] = User.de_json(data.pop("from", None), bot) - data["shipping_address"] = ShippingAddress.de_json(data.get("shipping_address"), bot) - - return super().de_json(data=data, bot=bot) - - async def answer( - self, - ok: bool, - shipping_options: Optional[Sequence["ShippingOption"]] = None, - error_message: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.answer_shipping_query(update.shipping_query.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.answer_shipping_query`. - - """ - return await self.get_bot().answer_shipping_query( - shipping_query_id=self.id, - ok=ok, - shipping_options=shipping_options, - error_message=error_message, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__init__.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index ba34f9e4c21e9164bc7eb4bdeaf30bd346115e27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200 zcmZ3^%ge<81UIM5$^y}kK?DpiLK&agfQ;!3DGb33nv8xc8H$*I{LdiCU(xy*`MIh3 zxrs%|`TAb@>G{U`i3J7vWvO{(`Z<|N`URCG8Tom}dWMGj#hE3kx&?{J*@@|?#rh?w zIjQMIiMjgm1&Nipsd**(#U+VF#rpB_nR%Hd@$q^EmA^P_a`RJ4b5iY!Sb=tdTvN;s SBt9@RGBSQ(fDuK^KrsM6Q#2v~ diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/affiliateinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/affiliateinfo.cpython-311.pyc deleted file mode 100755 index 6481cd6a9fe9ed342256f81abcc01f4669bf7b39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5478 zcmeHL&2QYs6(8;=_gk_gN3kuNO5((u%3RqpP;~94RUFrrldRfEE|TqmqL#A~Wqxdj zlvD}Z+9+I94g|!97BPw(bO@ZJHqibRMUSgsfo=&D5K!dM8w0mMkyGCcm*lP_H*wKJ zQDl}J&YOAj=FNM*c{8&g<#K5R>CeCV&C1p=LVu-%pW@xZ<25L}j}%lz3a3OgPLEV0 zdbAqlC>_;edb}EE<(QVxlhq_E$2DG0Ra2~-(9(LQn&A+RkOcHeYFRy3&2cD#t|EoM zgOn6bK8Pap5MD1;^GbRS6*HUPnO{~dK{u6E4GT5Xuw~V-1bZ0>O|~p-33ZbQ^H{@6 zMAn5lTPBtu*XydL$~LydzfpO`h?ARt=lfTr%h#@4eto8L)!}CwwrU!(R^*)65rkn-L zT=qSoLJiSnYD__1G*@lro4^4;$+kdn4XbNd5oB$g2^0sNOvY2P-LkJ zCZG@NHX*2V7_1VZEZa6IF9hmKs{nw7iG%eunAXAs6W8q%PE2ZGBI&B8;hvtlxoSWU zK{ga$njsse1$dQYuaV7@9vSgLn_|#tg3JYh- z%wXjOySpw#3S=1F^if|H=3xmfnzjI|hpr|%Q7H5|%LwH6jnV5vu$*cO>#`O4cyR;V z+?6adxq+BaO=`bG)TAr%pqh+%zi#221MyVL&<)h9hw4Vf1${#P&~2a?AgH{cg2#%U zrHoa55ex))^n*k<)CACmX;V7}Qw&C+TG1GV<=V1vZgO(+%S2Gy)rqNtN$Z$Um{R9h zfj|!~`;?q9Y`g>-b{n5UQEx2JJs5y$+_NSp1Ong%01CD#OkNafvLP&D!N5zf?AI`x z9HY6b82KQ=n`wouw<)E-(BnfHA9(4ciiFpq~%ph9y>}E3R_W{UlnT9}>Z%=T_2x`PntpTkMrD2h%=q6F zJpHyW_+p>ff9EE~I1RB*U0j7-@@WGJEDC@Bgn;`$8%PeQ`E?-qe+ncA-1~JPd8&}P zKSKQ{frM@q#ki9Xwmpfiv0j?)T~5N=mYm_kwp*vLZ?~v?!Z~TVp-MN`WjN-L0vt<8 zo@P0kC25wW8NH$qdj2LyAafD~+pEN=C4iubgO{?ehPrv5YUPEU)^ zflxE?hifOJx`#eVNfJAYN|HrYq>e zE|Z#Bx^6C+Qzg04D6L^*t)!`orN)N6Y#LMIxpO5;wei`8T)QbRVXNey1xivw-q5jO zm*^SVDg_9nHxjY2L5{+3n@6X6uP&lL(;q;a^>fJnc^my>7^U)eliSHZ@uQ#eqdV7I z{OB%UYV)NQU+RdLwqkAmc%f6evo8QiFvEO6R0y!~7wq+*@M?aDRx)y)|hycQ80D=_4;BKfs zn40^5`ctmSS#S-VLw1k69?)?+J@uhHCDIT0X5;|?^~WIaUQTog+g=bFp}a9CTGOnsGdTve7G28}^5i%a z$T(!1BmJoCin~d;ecwsBHR~T{;mm2L1J#+8EXXB?o zJn^yeyXD_5x4wCGSG?91ul@1)-SJ9$ys{N*<;HgTlYjXNJf9VY@2+pJ(~)*w`?$7s zYqxN|T{z$3&yy3NNikZfREk`sn59v|kaa9cPFj+@|6`z>l_Yxe?zSW)Nil0s4XfVL zOxuED6mC(3+JMmY&sL?AVIhHf##ER^oLo0d)Uc*WQjzmaM?>y+J-bm*5SpEW*BXNs zu#*3CBQM2y7t!o3E-{$6J>!m|iOJ44N}b|aH#Zu8#vMQ}i|!yTAwSzYIqt?OkwAmP zZjzRG^z8V~(e~&WH$};GKxQbJMaQ1odH#bjU*gEv{kPl0FM48+pmg3HqHMtc`%4#4 zVsP)3SKVkfKIJ0FIzz|rUuzGYW;LCO3%|edXqJ`tQiJzO?bLH_+-GI{VfJ|xWZn6Z z8+k%I^B%KTrC1;@fz6zRz0pvOB|?`xbBL4oW2wk?ZH8oLG_3SX-rp&NZa%$z=+5pf zh!LMtlvZt3vqTsQTg>4O@3*nQ##H(QdFs&x@dba$1Jf&H3P|d4>kp8*QI6x>7ZLY8 zu7$32(95mEo;`G`)&F$RRIC5#^fLheL1}x@0a#nySSNO()&IDOcQ_8bb$EWS@;Phy K`xDyPJpTpe1oZs? diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/revenuewithdrawalstate.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/revenuewithdrawalstate.cpython-311.pyc deleted file mode 100755 index 712e73d1a31cd6545c26af5d4ea6c4d1f29779c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8625 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/startransactions.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/startransactions.cpython-311.pyc deleted file mode 100755 index c0ee5e8a53cc57260a44f41a868681897554209c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8254 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 DkI|Xd diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/transactionpartner.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_payment/stars/__pycache__/transactionpartner.cpython-311.pyc deleted file mode 100755 index 599d219f0ee17a1a893f1d0a1287c3cf29293398..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19198 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 Q?Mw(M+ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes for Telegram Stars affiliates.""" -from typing import TYPE_CHECKING, Optional - -from telegram._chat import Chat -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class AffiliateInfo(TelegramObject): - """Contains information about the affiliate that received a commission via this transaction. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`affiliate_user`, :attr:`affiliate_chat`, - :attr:`commission_per_mille`, :attr:`amount`, and :attr:`nanostar_amount` are equal. - - .. versionadded:: 21.9 - - Args: - affiliate_user (:class:`telegram.User`, optional): The bot or the user that received an - affiliate commission if it was received by a bot or a user - affiliate_chat (:class:`telegram.Chat`, optional): The chat that received an affiliate - commission if it was received by a chat - commission_per_mille (:obj:`int`): The number of Telegram Stars received by the affiliate - for each 1000 Telegram Stars received by the bot from referred users - amount (:obj:`int`): Integer amount of Telegram Stars received by the affiliate from the - transaction, rounded to 0; can be negative for refunds - nanostar_amount (:obj:`int`, optional): The number of - :tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram - Stars received by the affiliate; from - :tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MIN_AMOUNT` to - :tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`; - can be negative for refunds - - Attributes: - affiliate_user (:class:`telegram.User`): Optional. The bot or the user that received an - affiliate commission if it was received by a bot or a user - affiliate_chat (:class:`telegram.Chat`): Optional. The chat that received an affiliate - commission if it was received by a chat - commission_per_mille (:obj:`int`): The number of Telegram Stars received by the affiliate - for each 1000 Telegram Stars received by the bot from referred users - amount (:obj:`int`): Integer amount of Telegram Stars received by the affiliate from the - transaction, rounded to 0; can be negative for refunds - nanostar_amount (:obj:`int`): Optional. The number of - :tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram - Stars received by the affiliate; from - :tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MIN_AMOUNT` to - :tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT`; - can be negative for refunds - """ - - __slots__ = ( - "affiliate_chat", - "affiliate_user", - "amount", - "commission_per_mille", - "nanostar_amount", - ) - - def __init__( - self, - commission_per_mille: int, - amount: int, - affiliate_user: Optional["User"] = None, - affiliate_chat: Optional["Chat"] = None, - nanostar_amount: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.affiliate_user: Optional[User] = affiliate_user - self.affiliate_chat: Optional[Chat] = affiliate_chat - self.commission_per_mille: int = commission_per_mille - self.amount: int = amount - self.nanostar_amount: Optional[int] = nanostar_amount - - self._id_attrs = ( - self.affiliate_user, - self.affiliate_chat, - self.commission_per_mille, - self.amount, - self.nanostar_amount, - ) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["AffiliateInfo"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["affiliate_user"] = User.de_json(data.get("affiliate_user"), bot) - data["affiliate_chat"] = Chat.de_json(data.get("affiliate_chat"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/revenuewithdrawalstate.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/revenuewithdrawalstate.py deleted file mode 100755 index be75ae4..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/stars/revenuewithdrawalstate.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=redefined-builtin -"""This module contains the classes for Telegram Stars Revenue Withdrawals.""" -import datetime as dtm -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class RevenueWithdrawalState(TelegramObject): - """This object describes the state of a revenue withdrawal operation. Currently, it can be one - of: - - * :class:`telegram.RevenueWithdrawalStatePending` - * :class:`telegram.RevenueWithdrawalStateSucceeded` - * :class:`telegram.RevenueWithdrawalStateFailed` - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` is equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): The type of the state. - - Attributes: - type (:obj:`str`): The type of the state. - """ - - __slots__ = ("type",) - - PENDING: Final[str] = constants.RevenueWithdrawalStateType.PENDING - """:const:`telegram.constants.RevenueWithdrawalStateType.PENDING`""" - SUCCEEDED: Final[str] = constants.RevenueWithdrawalStateType.SUCCEEDED - """:const:`telegram.constants.RevenueWithdrawalStateType.SUCCEEDED`""" - FAILED: Final[str] = constants.RevenueWithdrawalStateType.FAILED - """:const:`telegram.constants.RevenueWithdrawalStateType.FAILED`""" - - def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(api_kwargs=api_kwargs) - self.type: str = enum.get_member(constants.RevenueWithdrawalStateType, type, type) - - self._id_attrs = (self.type,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["RevenueWithdrawalState"]: - """Converts JSON data to the appropriate :class:`RevenueWithdrawalState` object, i.e. takes - care of selecting the correct subclass. - - Args: - data (dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`): The bot associated with this object. - - Returns: - The Telegram object. - - """ - data = cls._parse_data(data) - - if (cls is RevenueWithdrawalState and not data) or data is None: - return None - - _class_mapping: dict[str, type[RevenueWithdrawalState]] = { - cls.PENDING: RevenueWithdrawalStatePending, - cls.SUCCEEDED: RevenueWithdrawalStateSucceeded, - cls.FAILED: RevenueWithdrawalStateFailed, - } - - if cls is RevenueWithdrawalState and data.get("type") in _class_mapping: - return _class_mapping[data.pop("type")].de_json(data=data, bot=bot) - - return super().de_json(data=data, bot=bot) - - -class RevenueWithdrawalStatePending(RevenueWithdrawalState): - """The withdrawal is in progress. - - .. versionadded:: 21.4 - - Attributes: - type (:obj:`str`): The type of the state, always - :tg-const:`telegram.RevenueWithdrawalState.PENDING`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(type=RevenueWithdrawalState.PENDING, api_kwargs=api_kwargs) - self._freeze() - - -class RevenueWithdrawalStateSucceeded(RevenueWithdrawalState): - """The withdrawal succeeded. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`date` are equal. - - .. versionadded:: 21.4 - - Args: - date (:obj:`datetime.datetime`): Date the withdrawal was completed as a datetime object. - url (:obj:`str`): An HTTPS URL that can be used to see transaction details. - - Attributes: - type (:obj:`str`): The type of the state, always - :tg-const:`telegram.RevenueWithdrawalState.SUCCEEDED`. - date (:obj:`datetime.datetime`): Date the withdrawal was completed as a datetime object. - url (:obj:`str`): An HTTPS URL that can be used to see transaction details. - """ - - __slots__ = ("date", "url") - - def __init__( - self, - date: dtm.datetime, - url: str, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=RevenueWithdrawalState.SUCCEEDED, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.date: dtm.datetime = date - self.url: str = url - self._id_attrs = ( - self.type, - self.date, - ) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["RevenueWithdrawalStateSucceeded"]: - """See :meth:`telegram.RevenueWithdrawalState.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo) - - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class RevenueWithdrawalStateFailed(RevenueWithdrawalState): - """The withdrawal failed and the transaction was refunded. - - .. versionadded:: 21.4 - - Attributes: - type (:obj:`str`): The type of the state, always - :tg-const:`telegram.RevenueWithdrawalState.FAILED`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(type=RevenueWithdrawalState.FAILED, api_kwargs=api_kwargs) - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/startransactions.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/startransactions.py deleted file mode 100755 index f53a0d1..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/stars/startransactions.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=redefined-builtin -"""This module contains the classes for Telegram Stars transactions.""" - -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.types import JSONDict - -from .transactionpartner import TransactionPartner - -if TYPE_CHECKING: - from telegram import Bot - - -class StarTransaction(TelegramObject): - """Describes a Telegram Star transaction. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id`, :attr:`source`, and :attr:`receiver` are equal. - - .. versionadded:: 21.4 - - Args: - id (:obj:`str`): Unique identifier of the transaction. Coincides with the identifer - of the original transaction for refund transactions. - Coincides with :attr:`SuccessfulPayment.telegram_payment_charge_id` for - successful incoming payments from users. - amount (:obj:`int`): Integer amount of Telegram Stars transferred by the transaction. - nanostar_amount (:obj:`int`, optional): The number of - :tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram - Stars transferred by the transaction; from 0 to - :tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT` - - .. versionadded:: 21.9 - date (:obj:`datetime.datetime`): Date the transaction was created as a datetime object. - source (:class:`telegram.TransactionPartner`, optional): Source of an incoming transaction - (e.g., a user purchasing goods or services, Fragment refunding a failed withdrawal). - Only for incoming transactions. - receiver (:class:`telegram.TransactionPartner`, optional): Receiver of an outgoing - transaction (e.g., a user for a purchase refund, Fragment for a withdrawal). Only for - outgoing transactions. - - Attributes: - id (:obj:`str`): Unique identifier of the transaction. Coincides with the identifer - of the original transaction for refund transactions. - Coincides with :attr:`SuccessfulPayment.telegram_payment_charge_id` for - successful incoming payments from users. - amount (:obj:`int`): Integer amount of Telegram Stars transferred by the transaction. - nanostar_amount (:obj:`int`): Optional. The number of - :tg-const:`~telegram.constants.StarTransactions.NANOSTAR_VALUE` shares of Telegram - Stars transferred by the transaction; from 0 to - :tg-const:`~telegram.constants.StarTransactionsLimit.NANOSTAR_MAX_AMOUNT` - - .. versionadded:: 21.9 - date (:obj:`datetime.datetime`): Date the transaction was created as a datetime object. - source (:class:`telegram.TransactionPartner`): Optional. Source of an incoming transaction - (e.g., a user purchasing goods or services, Fragment refunding a failed withdrawal). - Only for incoming transactions. - receiver (:class:`telegram.TransactionPartner`): Optional. Receiver of an outgoing - transaction (e.g., a user for a purchase refund, Fragment for a withdrawal). Only for - outgoing transactions. - """ - - __slots__ = ("amount", "date", "id", "nanostar_amount", "receiver", "source") - - def __init__( - self, - id: str, - amount: int, - date: dtm.datetime, - source: Optional[TransactionPartner] = None, - receiver: Optional[TransactionPartner] = None, - nanostar_amount: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.id: str = id - self.amount: int = amount - self.date: dtm.datetime = date - self.source: Optional[TransactionPartner] = source - self.receiver: Optional[TransactionPartner] = receiver - self.nanostar_amount: Optional[int] = nanostar_amount - - self._id_attrs = ( - self.id, - self.source, - self.receiver, - ) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["StarTransaction"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo) - - data["source"] = TransactionPartner.de_json(data.get("source"), bot) - data["receiver"] = TransactionPartner.de_json(data.get("receiver"), bot) - - return super().de_json(data=data, bot=bot) - - -class StarTransactions(TelegramObject): - """ - Contains a list of Telegram Star transactions. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`transactions` are equal. - - .. versionadded:: 21.4 - - Args: - transactions (Sequence[:class:`telegram.StarTransaction`]): The list of transactions. - - Attributes: - transactions (tuple[:class:`telegram.StarTransaction`]): The list of transactions. - """ - - __slots__ = ("transactions",) - - def __init__( - self, transactions: Sequence[StarTransaction], *, api_kwargs: Optional[JSONDict] = None - ): - super().__init__(api_kwargs=api_kwargs) - self.transactions: tuple[StarTransaction, ...] = parse_sequence_arg(transactions) - - self._id_attrs = (self.transactions,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["StarTransactions"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - data["transactions"] = StarTransaction.de_list(data.get("transactions"), bot) - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/stars/transactionpartner.py b/venv/lib/python3.11/site-packages/telegram/_payment/stars/transactionpartner.py deleted file mode 100755 index 7c82bf0..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/stars/transactionpartner.py +++ /dev/null @@ -1,405 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=redefined-builtin -"""This module contains the classes for Telegram Stars transaction partners.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._gifts import Gift -from telegram._paidmedia import PaidMedia -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils import enum -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -from .affiliateinfo import AffiliateInfo -from .revenuewithdrawalstate import RevenueWithdrawalState - -if TYPE_CHECKING: - from telegram import Bot - - -class TransactionPartner(TelegramObject): - """This object describes the source of a transaction, or its recipient for outgoing - transactions. Currently, it can be one of: - - * :class:`TransactionPartnerUser` - * :class:`TransactionPartnerAffiliateProgram` - * :class:`TransactionPartnerFragment` - * :class:`TransactionPartnerTelegramAds` - * :class:`TransactionPartnerTelegramApi` - * :class:`TransactionPartnerOther` - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` is equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): The type of the transaction partner. - - Attributes: - type (:obj:`str`): The type of the transaction partner. - """ - - __slots__ = ("type",) - - AFFILIATE_PROGRAM: Final[str] = constants.TransactionPartnerType.AFFILIATE_PROGRAM - """:const:`telegram.constants.TransactionPartnerType.AFFILIATE_PROGRAM` - - .. versionadded:: 21.9 - """ - FRAGMENT: Final[str] = constants.TransactionPartnerType.FRAGMENT - """:const:`telegram.constants.TransactionPartnerType.FRAGMENT`""" - OTHER: Final[str] = constants.TransactionPartnerType.OTHER - """:const:`telegram.constants.TransactionPartnerType.OTHER`""" - TELEGRAM_ADS: Final[str] = constants.TransactionPartnerType.TELEGRAM_ADS - """:const:`telegram.constants.TransactionPartnerType.TELEGRAM_ADS`""" - TELEGRAM_API: Final[str] = constants.TransactionPartnerType.TELEGRAM_API - """:const:`telegram.constants.TransactionPartnerType.TELEGRAM_API`""" - USER: Final[str] = constants.TransactionPartnerType.USER - """:const:`telegram.constants.TransactionPartnerType.USER`""" - - def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(api_kwargs=api_kwargs) - self.type: str = enum.get_member(constants.TransactionPartnerType, type, type) - - self._id_attrs = (self.type,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["TransactionPartner"]: - """Converts JSON data to the appropriate :class:`TransactionPartner` object, i.e. takes - care of selecting the correct subclass. - - Args: - data (dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`): The bot associated with this object. - - Returns: - The Telegram object. - - """ - data = cls._parse_data(data) - - if (cls is TransactionPartner and not data) or data is None: - return None - - _class_mapping: dict[str, type[TransactionPartner]] = { - cls.AFFILIATE_PROGRAM: TransactionPartnerAffiliateProgram, - cls.FRAGMENT: TransactionPartnerFragment, - cls.USER: TransactionPartnerUser, - cls.TELEGRAM_ADS: TransactionPartnerTelegramAds, - cls.TELEGRAM_API: TransactionPartnerTelegramApi, - cls.OTHER: TransactionPartnerOther, - } - - if cls is TransactionPartner and data.get("type") in _class_mapping: - return _class_mapping[data.pop("type")].de_json(data=data, bot=bot) - - return super().de_json(data=data, bot=bot) - - -class TransactionPartnerAffiliateProgram(TransactionPartner): - """Describes the affiliate program that issued the affiliate commission received via this - transaction. - - This object is comparable in terms of equality. Two objects of this class are considered equal, - if their :attr:`commission_per_mille` are equal. - - .. versionadded:: 21.9 - - Args: - sponsor_user (:class:`telegram.User`, optional): Information about the bot that sponsored - the affiliate program - commission_per_mille (:obj:`int`): The number of Telegram Stars received by the bot for - each 1000 Telegram Stars received by the affiliate program sponsor from referred users. - - Attributes: - type (:obj:`str`): The type of the transaction partner, - always :tg-const:`telegram.TransactionPartner.AFFILIATE_PROGRAM`. - sponsor_user (:class:`telegram.User`): Optional. Information about the bot that sponsored - the affiliate program - commission_per_mille (:obj:`int`): The number of Telegram Stars received by the bot for - each 1000 Telegram Stars received by the affiliate program sponsor from referred users. - """ - - __slots__ = ("commission_per_mille", "sponsor_user") - - def __init__( - self, - commission_per_mille: int, - sponsor_user: Optional["User"] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=TransactionPartner.AFFILIATE_PROGRAM, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.sponsor_user: Optional[User] = sponsor_user - self.commission_per_mille: int = commission_per_mille - self._id_attrs = ( - self.type, - self.commission_per_mille, - ) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["TransactionPartnerAffiliateProgram"]: - """See :meth:`telegram.TransactionPartner.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["sponsor_user"] = User.de_json(data.get("sponsor_user"), bot) - - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class TransactionPartnerFragment(TransactionPartner): - """Describes a withdrawal transaction with Fragment. - - .. versionadded:: 21.4 - - Args: - withdrawal_state (:class:`telegram.RevenueWithdrawalState`, optional): State of the - transaction if the transaction is outgoing. - - Attributes: - type (:obj:`str`): The type of the transaction partner, - always :tg-const:`telegram.TransactionPartner.FRAGMENT`. - withdrawal_state (:class:`telegram.RevenueWithdrawalState`): Optional. State of the - transaction if the transaction is outgoing. - """ - - __slots__ = ("withdrawal_state",) - - def __init__( - self, - withdrawal_state: Optional["RevenueWithdrawalState"] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=TransactionPartner.FRAGMENT, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.withdrawal_state: Optional[RevenueWithdrawalState] = withdrawal_state - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["TransactionPartnerFragment"]: - """See :meth:`telegram.TransactionPartner.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - data["withdrawal_state"] = RevenueWithdrawalState.de_json( - data.get("withdrawal_state"), bot - ) - - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class TransactionPartnerUser(TransactionPartner): - """Describes a transaction with a user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`user` are equal. - - .. versionadded:: 21.4 - - Args: - user (:class:`telegram.User`): Information about the user. - affiliate (:class:`telegram.AffiliateInfo`, optional): Information about the affiliate that - received a commission via this transaction - - .. versionadded:: 21.9 - invoice_payload (:obj:`str`, optional): Bot-specified invoice payload. - subscription_period (:class:`datetime.timedelta`, optional): The duration of the paid - subscription - - .. versionadded:: 21.8 - paid_media (Sequence[:class:`telegram.PaidMedia`], optional): Information about the paid - media bought by the user. - - .. versionadded:: 21.5 - paid_media_payload (:obj:`str`, optional): Bot-specified paid media payload. - - .. versionadded:: 21.6 - gift (:class:`telegram.Gift`, optional): The gift sent to the user by the bot - - .. versionadded:: 21.8 - - Attributes: - type (:obj:`str`): The type of the transaction partner, - always :tg-const:`telegram.TransactionPartner.USER`. - user (:class:`telegram.User`): Information about the user. - affiliate (:class:`telegram.AffiliateInfo`): Optional. Information about the affiliate that - received a commission via this transaction - - .. versionadded:: 21.9 - invoice_payload (:obj:`str`): Optional. Bot-specified invoice payload. - subscription_period (:class:`datetime.timedelta`): Optional. The duration of the paid - subscription - - .. versionadded:: 21.8 - paid_media (tuple[:class:`telegram.PaidMedia`]): Optional. Information about the paid - media bought by the user. - - .. versionadded:: 21.5 - paid_media_payload (:obj:`str`): Optional. Bot-specified paid media payload. - - .. versionadded:: 21.6 - gift (:class:`telegram.Gift`): Optional. The gift sent to the user by the bot - - .. versionadded:: 21.8 - - """ - - __slots__ = ( - "affiliate", - "gift", - "invoice_payload", - "paid_media", - "paid_media_payload", - "subscription_period", - "user", - ) - - def __init__( - self, - user: "User", - invoice_payload: Optional[str] = None, - paid_media: Optional[Sequence[PaidMedia]] = None, - paid_media_payload: Optional[str] = None, - subscription_period: Optional[dtm.timedelta] = None, - gift: Optional[Gift] = None, - affiliate: Optional[AffiliateInfo] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=TransactionPartner.USER, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.user: User = user - self.affiliate: Optional[AffiliateInfo] = affiliate - self.invoice_payload: Optional[str] = invoice_payload - self.paid_media: Optional[tuple[PaidMedia, ...]] = parse_sequence_arg(paid_media) - self.paid_media_payload: Optional[str] = paid_media_payload - self.subscription_period: Optional[dtm.timedelta] = subscription_period - self.gift: Optional[Gift] = gift - - self._id_attrs = ( - self.type, - self.user, - ) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["TransactionPartnerUser"]: - """See :meth:`telegram.TransactionPartner.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["user"] = User.de_json(data.get("user"), bot) - data["affiliate"] = AffiliateInfo.de_json(data.get("affiliate"), bot) - data["paid_media"] = PaidMedia.de_list(data.get("paid_media"), bot=bot) - data["subscription_period"] = ( - dtm.timedelta(seconds=sp) - if (sp := data.get("subscription_period")) is not None - else None - ) - data["gift"] = Gift.de_json(data.get("gift"), bot) - - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class TransactionPartnerOther(TransactionPartner): - """Describes a transaction with an unknown partner. - - .. versionadded:: 21.4 - - Attributes: - type (:obj:`str`): The type of the transaction partner, - always :tg-const:`telegram.TransactionPartner.OTHER`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(type=TransactionPartner.OTHER, api_kwargs=api_kwargs) - self._freeze() - - -class TransactionPartnerTelegramAds(TransactionPartner): - """Describes a withdrawal transaction to the Telegram Ads platform. - - .. versionadded:: 21.4 - - Attributes: - type (:obj:`str`): The type of the transaction partner, - always :tg-const:`telegram.TransactionPartner.TELEGRAM_ADS`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(type=TransactionPartner.TELEGRAM_ADS, api_kwargs=api_kwargs) - self._freeze() - - -class TransactionPartnerTelegramApi(TransactionPartner): - """Describes a transaction with payment for - `paid broadcasting `_. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`request_count` is equal. - - .. versionadded:: 21.7 - - Args: - request_count (:obj:`int`): The number of successful requests that exceeded regular limits - and were therefore billed. - - Attributes: - type (:obj:`str`): The type of the transaction partner, - always :tg-const:`telegram.TransactionPartner.TELEGRAM_API`. - request_count (:obj:`int`): The number of successful requests that exceeded regular limits - and were therefore billed. - """ - - __slots__ = ("request_count",) - - def __init__(self, request_count: int, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(type=TransactionPartner.TELEGRAM_API, api_kwargs=api_kwargs) - with self._unfrozen(): - self.request_count: int = request_count - self._id_attrs = (self.request_count,) diff --git a/venv/lib/python3.11/site-packages/telegram/_payment/successfulpayment.py b/venv/lib/python3.11/site-packages/telegram/_payment/successfulpayment.py deleted file mode 100755 index 0642e30..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_payment/successfulpayment.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram SuccessfulPayment.""" - -import datetime as dtm -from typing import TYPE_CHECKING, Optional - -from telegram._payment.orderinfo import OrderInfo -from telegram._telegramobject import TelegramObject -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class SuccessfulPayment(TelegramObject): - """This object contains basic information about a successful payment. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`telegram_payment_charge_id` and - :attr:`provider_payment_charge_id` are equal. - - Args: - currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in - |tg_stars|. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, - **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. - See the ``exp`` parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - invoice_payload (:obj:`str`): Bot-specified invoice payload. - subscription_expiration_date (:class:`datetime.datetime`, optional): Expiration date of the - subscription; for recurring payments only. - - .. versionadded:: 21.8 - is_recurring (:obj:`bool`, optional): True, if the payment is for a subscription. - - .. versionadded:: 21.8 - is_first_recurring (:obj:`bool`, optional): True, if the payment is the first payment of a - subscription. - - .. versionadded:: 21.8 - shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the - user. - order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user. - telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. - provider_payment_charge_id (:obj:`str`): Provider payment identifier. - - Attributes: - currency (:obj:`str`): Three-letter ISO 4217 currency code, or ``XTR`` for payments in - |tg_stars|. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, - **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. - See the ``exp`` parameter in - `currencies.json `_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - invoice_payload (:obj:`str`): Bot-specified invoice payload. - subscription_expiration_date (:class:`datetime.datetime`): Optional. Expiration - date of the subscription; for recurring payments only. - - .. versionadded:: 21.8 - is_recurring (:obj:`bool`): Optional. True, if the payment is for a subscription. - - .. versionadded:: 21.8 - is_first_recurring (:obj:`bool`): Optional. True, if the payment is the first payment of a - subscription. - - .. versionadded:: 21.8 - shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the - user. - order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user. - telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. - provider_payment_charge_id (:obj:`str`): Provider payment identifier. - - """ - - __slots__ = ( - "currency", - "invoice_payload", - "is_first_recurring", - "is_recurring", - "order_info", - "provider_payment_charge_id", - "shipping_option_id", - "subscription_expiration_date", - "telegram_payment_charge_id", - "total_amount", - ) - - def __init__( - self, - currency: str, - total_amount: int, - invoice_payload: str, - telegram_payment_charge_id: str, - provider_payment_charge_id: str, - shipping_option_id: Optional[str] = None, - order_info: Optional[OrderInfo] = None, - subscription_expiration_date: Optional[dtm.datetime] = None, - is_recurring: Optional[bool] = None, - is_first_recurring: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.currency: str = currency - self.total_amount: int = total_amount - self.invoice_payload: str = invoice_payload - self.shipping_option_id: Optional[str] = shipping_option_id - self.order_info: Optional[OrderInfo] = order_info - self.telegram_payment_charge_id: str = telegram_payment_charge_id - self.provider_payment_charge_id: str = provider_payment_charge_id - self.subscription_expiration_date: Optional[dtm.datetime] = subscription_expiration_date - self.is_recurring: Optional[bool] = is_recurring - self.is_first_recurring: Optional[bool] = is_first_recurring - - self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["SuccessfulPayment"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["order_info"] = OrderInfo.de_json(data.get("order_info"), bot) - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["subscription_expiration_date"] = from_timestamp( - data.get("subscription_expiration_date"), tzinfo=loc_tzinfo - ) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_poll.py b/venv/lib/python3.11/site-packages/telegram/_poll.py deleted file mode 100755 index f26ac84..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_poll.py +++ /dev/null @@ -1,650 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Poll.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._chat import Chat -from telegram._messageentity import MessageEntity -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils import enum -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.entities import parse_message_entities, parse_message_entity -from telegram._utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot - - -class InputPollOption(TelegramObject): - """ - This object contains information about one answer option in a poll to be sent. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text` is equal. - - .. versionadded:: 21.2 - - Args: - text (:obj:`str`): Option text, - :tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH` - characters. - text_parse_mode (:obj:`str`, optional): |parse_mode| - Currently, only custom emoji entities are allowed. - text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities - that appear in the option :paramref:`text`. It can be specified instead of - :paramref:`text_parse_mode`. - Currently, only custom emoji entities are allowed. - This list is empty if the text does not contain entities. - - Attributes: - text (:obj:`str`): Option text, - :tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH` - characters. - text_parse_mode (:obj:`str`): Optional. |parse_mode| - Currently, only custom emoji entities are allowed. - text_entities (Sequence[:class:`telegram.MessageEntity`]): Special entities - that appear in the option :paramref:`text`. It can be specified instead of - :paramref:`text_parse_mode`. - Currently, only custom emoji entities are allowed. - This list is empty if the text does not contain entities. - """ - - __slots__ = ("text", "text_entities", "text_parse_mode") - - def __init__( - self, - text: str, - text_parse_mode: ODVInput[str] = DEFAULT_NONE, - text_entities: Optional[Sequence[MessageEntity]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.text: str = text - self.text_parse_mode: ODVInput[str] = text_parse_mode - self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities) - - self._id_attrs = (self.text,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["InputPollOption"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot) - - return super().de_json(data=data, bot=bot) - - -class PollOption(TelegramObject): - """ - This object contains information about one answer option in a poll. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text` and :attr:`voter_count` are equal. - - Args: - text (:obj:`str`): Option text, - :tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH` - characters. - voter_count (:obj:`int`): Number of users that voted for this option. - text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities - that appear in the option text. Currently, only custom emoji entities are allowed in - poll option texts. - - .. versionadded:: 21.2 - - Attributes: - text (:obj:`str`): Option text, - :tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH` - characters. - voter_count (:obj:`int`): Number of users that voted for this option. - text_entities (tuple[:class:`telegram.MessageEntity`]): Special entities - that appear in the option text. Currently, only custom emoji entities are allowed in - poll option texts. - This list is empty if the question does not contain entities. - - .. versionadded:: 21.2 - - """ - - __slots__ = ("text", "text_entities", "voter_count") - - def __init__( - self, - text: str, - voter_count: int, - text_entities: Optional[Sequence[MessageEntity]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.text: str = text - self.voter_count: int = voter_count - self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities) - - self._id_attrs = (self.text, self.voter_count) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PollOption"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot) - - return super().de_json(data=data, bot=bot) - - def parse_entity(self, entity: MessageEntity) -> str: - """Returns the text in :attr:`text` - from a given :class:`telegram.MessageEntity` of :attr:`text_entities`. - - Note: - This method is present because Telegram calculates the offset and length in - UTF-16 codepoint pairs, which some versions of Python don't handle automatically. - (That is, you can't just slice ``Message.text`` with the offset and length.) - - .. versionadded:: 21.2 - - Args: - entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must - be an entity that belongs to :attr:`text_entities`. - - Returns: - :obj:`str`: The text of the given entity. - """ - return parse_message_entity(self.text, entity) - - def parse_entities(self, types: Optional[list[str]] = None) -> dict[MessageEntity, str]: - """ - Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. - It contains entities from this polls question filtered by their ``type`` attribute as - the key, and the text that each entity belongs to as the value of the :obj:`dict`. - - Note: - This method should always be used instead of the :attr:`text_entities` - attribute, since it calculates the correct substring from the message text based on - UTF-16 codepoints. See :attr:`parse_entity` for more info. - - .. versionadded:: 21.2 - - Args: - types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the - ``type`` attribute of an entity is contained in this list, it will be returned. - Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`. - - Returns: - dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to - the text that belongs to them, calculated based on UTF-16 codepoints. - """ - return parse_message_entities(self.text, self.text_entities, types) - - MIN_LENGTH: Final[int] = constants.PollLimit.MIN_OPTION_LENGTH - """:const:`telegram.constants.PollLimit.MIN_OPTION_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_LENGTH: Final[int] = constants.PollLimit.MAX_OPTION_LENGTH - """:const:`telegram.constants.PollLimit.MAX_OPTION_LENGTH` - - .. versionadded:: 20.0 - """ - - -class PollAnswer(TelegramObject): - """ - This object represents an answer of a user in a non-anonymous poll. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`poll_id`, :attr:`user` and :attr:`option_ids` are equal. - - .. versionchanged:: 20.5 - The order of :paramref:`option_ids` and :paramref:`user` is changed in - 20.5 as the latter one became optional. - - .. versionchanged:: 20.6 - Backward compatiblity for changed order of :paramref:`option_ids` and :paramref:`user` - was removed. - - Args: - poll_id (:obj:`str`): Unique poll identifier. - option_ids (Sequence[:obj:`int`]): Identifiers of answer options, chosen by the user. May - be empty if the user retracted their vote. - - .. versionchanged:: 20.0 - |sequenceclassargs| - user (:class:`telegram.User`, optional): The user that changed the answer to the poll, - if the voter isn't anonymous. If the voter is anonymous, this field will contain the - user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility. - - .. versionchanged:: 20.5 - :paramref:`user` became optional. - voter_chat (:class:`telegram.Chat`, optional): The chat that changed the answer to the - poll, if the voter is anonymous. - - .. versionadded:: 20.5 - - Attributes: - poll_id (:obj:`str`): Unique poll identifier. - option_ids (tuple[:obj:`int`]): Identifiers of answer options, chosen by the user. May - be empty if the user retracted their vote. - - .. versionchanged:: 20.0 - |tupleclassattrs| - user (:class:`telegram.User`): Optional. The user, who changed the answer to the - poll, if the voter isn't anonymous. If the voter is anonymous, this field will contain - the user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility - - .. versionchanged:: 20.5 - :paramref:`user` became optional. - voter_chat (:class:`telegram.Chat`): Optional. The chat that changed the answer to the - poll, if the voter is anonymous. - - .. versionadded:: 20.5 - - """ - - __slots__ = ("option_ids", "poll_id", "user", "voter_chat") - - def __init__( - self, - poll_id: str, - option_ids: Sequence[int], - user: Optional[User] = None, - voter_chat: Optional[Chat] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.poll_id: str = poll_id - self.voter_chat: Optional[Chat] = voter_chat - self.option_ids: tuple[int, ...] = parse_sequence_arg(option_ids) - self.user: Optional[User] = user - - self._id_attrs = ( - self.poll_id, - self.option_ids, - self.user, - self.voter_chat, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PollAnswer"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["user"] = User.de_json(data.get("user"), bot) - data["voter_chat"] = Chat.de_json(data.get("voter_chat"), bot) - - return super().de_json(data=data, bot=bot) - - -class Poll(TelegramObject): - """ - This object contains information about a poll. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Examples: - :any:`Poll Bot ` - - Args: - id (:obj:`str`): Unique poll identifier. - question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`- - :tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters. - options (Sequence[:class:`~telegram.PollOption`]): List of poll options. - - .. versionchanged:: 20.0 - |sequenceclassargs| - is_closed (:obj:`bool`): :obj:`True`, if the poll is closed. - is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous. - type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`. - allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers. - correct_option_id (:obj:`int`, optional): A zero based identifier of the correct answer - option. Available only for closed polls in the quiz mode, which were sent - (not forwarded), by the bot or to a private chat with the bot. - explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect - answer or taps on the lamp icon in a quiz-style poll, - 0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters. - explanation_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special - entities like usernames, URLs, bot commands, etc. that appear in the - :attr:`explanation`. This list is empty if the message does not contain explanation - entities. - - .. versionchanged:: 20.0 - - * This attribute is now always a (possibly empty) list and never :obj:`None`. - * |sequenceclassargs| - open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active - after creation. - close_date (:obj:`datetime.datetime`, optional): Point in time (Unix timestamp) when the - poll will be automatically closed. Converted to :obj:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - question_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities - that appear in the :attr:`question`. Currently, only custom emoji entities are allowed - in poll questions. - - .. versionadded:: 21.2 - - Attributes: - id (:obj:`str`): Unique poll identifier. - question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`- - :tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters. - options (tuple[:class:`~telegram.PollOption`]): List of poll options. - - .. versionchanged:: 20.0 - |tupleclassattrs| - total_voter_count (:obj:`int`): Total number of users that voted in the poll. - is_closed (:obj:`bool`): :obj:`True`, if the poll is closed. - is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous. - type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`. - allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers. - correct_option_id (:obj:`int`): Optional. A zero based identifier of the correct answer - option. Available only for closed polls in the quiz mode, which were sent - (not forwarded), by the bot or to a private chat with the bot. - explanation (:obj:`str`): Optional. Text that is shown when a user chooses an incorrect - answer or taps on the lamp icon in a quiz-style poll, - 0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters. - explanation_entities (tuple[:class:`telegram.MessageEntity`]): Special entities - like usernames, URLs, bot commands, etc. that appear in the :attr:`explanation`. - This list is empty if the message does not contain explanation entities. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - .. versionchanged:: 20.0 - This attribute is now always a (possibly empty) list and never :obj:`None`. - open_period (:obj:`int`): Optional. Amount of time in seconds the poll will be active - after creation. - close_date (:obj:`datetime.datetime`): Optional. Point in time when the poll will be - automatically closed. - - .. versionchanged:: 20.3 - |datetime_localization| - question_entities (tuple[:class:`telegram.MessageEntity`]): Special entities - that appear in the :attr:`question`. Currently, only custom emoji entities are allowed - in poll questions. - This list is empty if the question does not contain entities. - - .. versionadded:: 21.2 - - """ - - __slots__ = ( - "allows_multiple_answers", - "close_date", - "correct_option_id", - "explanation", - "explanation_entities", - "id", - "is_anonymous", - "is_closed", - "open_period", - "options", - "question", - "question_entities", - "total_voter_count", - "type", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - question: str, - options: Sequence[PollOption], - total_voter_count: int, - is_closed: bool, - is_anonymous: bool, - type: str, # pylint: disable=redefined-builtin - allows_multiple_answers: bool, - correct_option_id: Optional[int] = None, - explanation: Optional[str] = None, - explanation_entities: Optional[Sequence[MessageEntity]] = None, - open_period: Optional[int] = None, - close_date: Optional[dtm.datetime] = None, - question_entities: Optional[Sequence[MessageEntity]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.id: str = id - self.question: str = question - self.options: tuple[PollOption, ...] = parse_sequence_arg(options) - self.total_voter_count: int = total_voter_count - self.is_closed: bool = is_closed - self.is_anonymous: bool = is_anonymous - self.type: str = enum.get_member(constants.PollType, type, type) - self.allows_multiple_answers: bool = allows_multiple_answers - self.correct_option_id: Optional[int] = correct_option_id - self.explanation: Optional[str] = explanation - self.explanation_entities: tuple[MessageEntity, ...] = parse_sequence_arg( - explanation_entities - ) - self.open_period: Optional[int] = open_period - self.close_date: Optional[dtm.datetime] = close_date - self.question_entities: tuple[MessageEntity, ...] = parse_sequence_arg(question_entities) - - self._id_attrs = (self.id,) - - self._freeze() - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Poll"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["options"] = [PollOption.de_json(option, bot) for option in data["options"]] - data["explanation_entities"] = MessageEntity.de_list(data.get("explanation_entities"), bot) - data["close_date"] = from_timestamp(data.get("close_date"), tzinfo=loc_tzinfo) - data["question_entities"] = MessageEntity.de_list(data.get("question_entities"), bot) - - return super().de_json(data=data, bot=bot) - - def parse_explanation_entity(self, entity: MessageEntity) -> str: - """Returns the text in :attr:`explanation` from a given :class:`telegram.MessageEntity` of - :attr:`explanation_entities`. - - Note: - This method is present because Telegram calculates the offset and length in - UTF-16 codepoint pairs, which some versions of Python don't handle automatically. - (That is, you can't just slice ``Message.text`` with the offset and length.) - - Args: - entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must - be an entity that belongs to :attr:`explanation_entities`. - - Returns: - :obj:`str`: The text of the given entity. - - Raises: - RuntimeError: If the poll has no explanation. - - """ - if not self.explanation: - raise RuntimeError("This Poll has no 'explanation'.") - - return parse_message_entity(self.explanation, entity) - - def parse_explanation_entities( - self, types: Optional[list[str]] = None - ) -> dict[MessageEntity, str]: - """ - Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. - It contains entities from this polls explanation filtered by their ``type`` attribute as - the key, and the text that each entity belongs to as the value of the :obj:`dict`. - - Note: - This method should always be used instead of the :attr:`explanation_entities` - attribute, since it calculates the correct substring from the message text based on - UTF-16 codepoints. See :attr:`parse_explanation_entity` for more info. - - Args: - types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the - ``type`` attribute of an entity is contained in this list, it will be returned. - Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`. - - Returns: - dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to - the text that belongs to them, calculated based on UTF-16 codepoints. - - Raises: - RuntimeError: If the poll has no explanation. - - """ - if not self.explanation: - raise RuntimeError("This Poll has no 'explanation'.") - - return parse_message_entities(self.explanation, self.explanation_entities, types) - - def parse_question_entity(self, entity: MessageEntity) -> str: - """Returns the text in :attr:`question` from a given :class:`telegram.MessageEntity` of - :attr:`question_entities`. - - .. versionadded:: 21.2 - - Note: - This method is present because Telegram calculates the offset and length in - UTF-16 codepoint pairs, which some versions of Python don't handle automatically. - (That is, you can't just slice ``Message.text`` with the offset and length.) - - Args: - entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must - be an entity that belongs to :attr:`question_entities`. - - Returns: - :obj:`str`: The text of the given entity. - """ - return parse_message_entity(self.question, entity) - - def parse_question_entities( - self, types: Optional[list[str]] = None - ) -> dict[MessageEntity, str]: - """ - Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. - It contains entities from this polls question filtered by their ``type`` attribute as - the key, and the text that each entity belongs to as the value of the :obj:`dict`. - - .. versionadded:: 21.2 - - Note: - This method should always be used instead of the :attr:`question_entities` - attribute, since it calculates the correct substring from the message text based on - UTF-16 codepoints. See :attr:`parse_question_entity` for more info. - - Args: - types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the - ``type`` attribute of an entity is contained in this list, it will be returned. - Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`. - - Returns: - dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to - the text that belongs to them, calculated based on UTF-16 codepoints. - - """ - return parse_message_entities(self.question, self.question_entities, types) - - REGULAR: Final[str] = constants.PollType.REGULAR - """:const:`telegram.constants.PollType.REGULAR`""" - QUIZ: Final[str] = constants.PollType.QUIZ - """:const:`telegram.constants.PollType.QUIZ`""" - MAX_EXPLANATION_LENGTH: Final[int] = constants.PollLimit.MAX_EXPLANATION_LENGTH - """:const:`telegram.constants.PollLimit.MAX_EXPLANATION_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_EXPLANATION_LINE_FEEDS: Final[int] = constants.PollLimit.MAX_EXPLANATION_LINE_FEEDS - """:const:`telegram.constants.PollLimit.MAX_EXPLANATION_LINE_FEEDS` - - .. versionadded:: 20.0 - """ - MIN_OPEN_PERIOD: Final[int] = constants.PollLimit.MIN_OPEN_PERIOD - """:const:`telegram.constants.PollLimit.MIN_OPEN_PERIOD` - - .. versionadded:: 20.0 - """ - MAX_OPEN_PERIOD: Final[int] = constants.PollLimit.MAX_OPEN_PERIOD - """:const:`telegram.constants.PollLimit.MAX_OPEN_PERIOD` - - .. versionadded:: 20.0 - """ - MIN_QUESTION_LENGTH: Final[int] = constants.PollLimit.MIN_QUESTION_LENGTH - """:const:`telegram.constants.PollLimit.MIN_QUESTION_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_QUESTION_LENGTH: Final[int] = constants.PollLimit.MAX_QUESTION_LENGTH - """:const:`telegram.constants.PollLimit.MAX_QUESTION_LENGTH` - - .. versionadded:: 20.0 - """ - MIN_OPTION_LENGTH: Final[int] = constants.PollLimit.MIN_OPTION_LENGTH - """:const:`telegram.constants.PollLimit.MIN_OPTION_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_OPTION_LENGTH: Final[int] = constants.PollLimit.MAX_OPTION_LENGTH - """:const:`telegram.constants.PollLimit.MAX_OPTION_LENGTH` - - .. versionadded:: 20.0 - """ - MIN_OPTION_NUMBER: Final[int] = constants.PollLimit.MIN_OPTION_NUMBER - """:const:`telegram.constants.PollLimit.MIN_OPTION_NUMBER` - - .. versionadded:: 20.0 - """ - MAX_OPTION_NUMBER: Final[int] = constants.PollLimit.MAX_OPTION_NUMBER - """:const:`telegram.constants.PollLimit.MAX_OPTION_NUMBER` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_proximityalerttriggered.py b/venv/lib/python3.11/site-packages/telegram/_proximityalerttriggered.py deleted file mode 100755 index b4ea6a2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_proximityalerttriggered.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Proximity Alert.""" -from typing import TYPE_CHECKING, Optional - -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ProximityAlertTriggered(TelegramObject): - """ - This object represents the content of a service message, sent whenever a user in the chat - triggers a proximity alert set by another user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`traveler`, :attr:`watcher` and :attr:`distance` are equal. - - Args: - traveler (:class:`telegram.User`): User that triggered the alert - watcher (:class:`telegram.User`): User that set the alert - distance (:obj:`int`): The distance between the users - - Attributes: - traveler (:class:`telegram.User`): User that triggered the alert - watcher (:class:`telegram.User`): User that set the alert - distance (:obj:`int`): The distance between the users - - """ - - __slots__ = ("distance", "traveler", "watcher") - - def __init__( - self, - traveler: User, - watcher: User, - distance: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.traveler: User = traveler - self.watcher: User = watcher - self.distance: int = distance - - self._id_attrs = (self.traveler, self.watcher, self.distance) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ProximityAlertTriggered"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["traveler"] = User.de_json(data.get("traveler"), bot) - data["watcher"] = User.de_json(data.get("watcher"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_reaction.py b/venv/lib/python3.11/site-packages/telegram/_reaction.py deleted file mode 100755 index 7d76b82..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_reaction.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains objects that represents a Telegram ReactionType.""" - -from typing import TYPE_CHECKING, Final, Literal, Optional, Union - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ReactionType(TelegramObject): - """Base class for Telegram ReactionType Objects. - There exist :class:`telegram.ReactionTypeEmoji`, :class:`telegram.ReactionTypeCustomEmoji` - and :class:`telegram.ReactionTypePaid`. - - .. versionadded:: 20.8 - .. versionchanged:: 21.5 - - Added paid reaction. - - Args: - type (:obj:`str`): Type of the reaction. Can be - :attr:`~telegram.ReactionType.EMOJI`, :attr:`~telegram.ReactionType.CUSTOM_EMOJI` or - :attr:`~telegram.ReactionType.PAID`. - Attributes: - type (:obj:`str`): Type of the reaction. Can be - :attr:`~telegram.ReactionType.EMOJI`, :attr:`~telegram.ReactionType.CUSTOM_EMOJI` or - :attr:`~telegram.ReactionType.PAID`. - - """ - - __slots__ = ("type",) - - EMOJI: Final[constants.ReactionType] = constants.ReactionType.EMOJI - """:const:`telegram.constants.ReactionType.EMOJI`""" - CUSTOM_EMOJI: Final[constants.ReactionType] = constants.ReactionType.CUSTOM_EMOJI - """:const:`telegram.constants.ReactionType.CUSTOM_EMOJI`""" - PAID: Final[constants.ReactionType] = constants.ReactionType.PAID - """:const:`telegram.constants.ReactionType.PAID` - - .. versionadded:: 21.5 - """ - - def __init__( - self, - type: Union[ # pylint: disable=redefined-builtin - Literal["emoji", "custom_emoji", "paid"], constants.ReactionType - ], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required by all subclasses - self.type: str = enum.get_member(constants.ReactionType, type, type) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ReactionType"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - if not data and cls is ReactionType: - return None - - _class_mapping: dict[str, type[ReactionType]] = { - cls.EMOJI: ReactionTypeEmoji, - cls.CUSTOM_EMOJI: ReactionTypeCustomEmoji, - cls.PAID: ReactionTypePaid, - } - - if cls is ReactionType and data.get("type") in _class_mapping: - return _class_mapping[data.pop("type")].de_json(data, bot) - - return super().de_json(data=data, bot=bot) - - -class ReactionTypeEmoji(ReactionType): - """ - Represents a reaction with a normal emoji. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if the :attr:`emoji` is equal. - - .. versionadded:: 20.8 - - Args: - emoji (:obj:`str`): Reaction emoji. It can be one of - :const:`telegram.constants.ReactionEmoji`. - - Attributes: - type (:obj:`str`): Type of the reaction, - always :tg-const:`telegram.ReactionType.EMOJI`. - emoji (:obj:`str`): Reaction emoji. It can be one of - :const:`telegram.constants.ReactionEmoji`. - """ - - __slots__ = ("emoji",) - - def __init__( - self, - emoji: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=ReactionType.EMOJI, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.emoji: str = emoji - self._id_attrs = (self.emoji,) - - -class ReactionTypeCustomEmoji(ReactionType): - """ - Represents a reaction with a custom emoji. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if the :attr:`custom_emoji_id` is equal. - - .. versionadded:: 20.8 - - Args: - custom_emoji_id (:obj:`str`): Custom emoji identifier. - - Attributes: - type (:obj:`str`): Type of the reaction, - always :tg-const:`telegram.ReactionType.CUSTOM_EMOJI`. - custom_emoji_id (:obj:`str`): Custom emoji identifier. - - """ - - __slots__ = ("custom_emoji_id",) - - def __init__( - self, - custom_emoji_id: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=ReactionType.CUSTOM_EMOJI, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.custom_emoji_id: str = custom_emoji_id - self._id_attrs = (self.custom_emoji_id,) - - -class ReactionTypePaid(ReactionType): - """ - The reaction is paid. - - .. versionadded:: 21.5 - - Attributes: - type (:obj:`str`): Type of the reaction, - always :tg-const:`telegram.ReactionType.PAID`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=ReactionType.PAID, api_kwargs=api_kwargs) - self._freeze() - - -class ReactionCount(TelegramObject): - """This class represents a reaction added to a message along with the number of times it was - added. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if the :attr:`type` and :attr:`total_count` is equal. - - .. versionadded:: 20.8 - - Args: - type (:class:`telegram.ReactionType`): Type of the reaction. - total_count (:obj:`int`): Number of times the reaction was added. - - Attributes: - type (:class:`telegram.ReactionType`): Type of the reaction. - total_count (:obj:`int`): Number of times the reaction was added. - """ - - __slots__ = ( - "total_count", - "type", - ) - - def __init__( - self, - type: ReactionType, # pylint: disable=redefined-builtin - total_count: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.type: ReactionType = type - self.total_count: int = total_count - - self._id_attrs = ( - self.type, - self.total_count, - ) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ReactionCount"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["type"] = ReactionType.de_json(data.get("type"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_reply.py b/venv/lib/python3.11/site-packages/telegram/_reply.py deleted file mode 100755 index ba04b89..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_reply.py +++ /dev/null @@ -1,472 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This modules contains objects that represents Telegram Replies""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional, Union - -from telegram._chat import Chat -from telegram._dice import Dice -from telegram._files.animation import Animation -from telegram._files.audio import Audio -from telegram._files.contact import Contact -from telegram._files.document import Document -from telegram._files.location import Location -from telegram._files.photosize import PhotoSize -from telegram._files.sticker import Sticker -from telegram._files.venue import Venue -from telegram._files.video import Video -from telegram._files.videonote import VideoNote -from telegram._files.voice import Voice -from telegram._games.game import Game -from telegram._giveaway import Giveaway, GiveawayWinners -from telegram._linkpreviewoptions import LinkPreviewOptions -from telegram._messageentity import MessageEntity -from telegram._messageorigin import MessageOrigin -from telegram._paidmedia import PaidMediaInfo -from telegram._payment.invoice import Invoice -from telegram._poll import Poll -from telegram._story import Story -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot - - -class ExternalReplyInfo(TelegramObject): - """ - This object contains information about a message that is being replied to, which may - come from another chat or forum topic. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`origin` is equal. - - .. versionadded:: 20.8 - - Args: - origin (:class:`telegram.MessageOrigin`): Origin of the message replied to by the given - message. - chat (:class:`telegram.Chat`, optional): Chat the original message belongs to. Available - only if the chat is a supergroup or a channel. - message_id (:obj:`int`, optional): Unique message identifier inside the original chat. - Available only if the original chat is a supergroup or a channel. - link_preview_options (:class:`telegram.LinkPreviewOptions`, optional): Options used for - link preview generation for the original message, if it is a text message - animation (:class:`telegram.Animation`, optional): Message is an animation, information - about the animation. - audio (:class:`telegram.Audio`, optional): Message is an audio file, information about the - file. - document (:class:`telegram.Document`, optional): Message is a general file, information - about the file. - photo (Sequence[:class:`telegram.PhotoSize`], optional): Message is a photo, available - sizes of the photo. - sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information about the - sticker. - story (:class:`telegram.Story`, optional): Message is a forwarded story. - video (:class:`telegram.Video`, optional): Message is a video, information about the video. - video_note (:class:`telegram.VideoNote`, optional): Message is a `video note - `_, information about the video - message. - voice (:class:`telegram.Voice`, optional): Message is a voice message, information about - the file. - has_media_spoiler (:obj:`bool`, optional): :obj:`True`, if the message media is covered by - a spoiler animation. - contact (:class:`telegram.Contact`, optional): Message is a shared contact, information - about the contact. - dice (:class:`telegram.Dice`, optional): Message is a dice with random value. - game (:Class:`telegram.Game`. optional): Message is a game, information about the game. - :ref:`More about games >> `. - giveaway (:class:`telegram.Giveaway`, optional): Message is a scheduled giveaway, - information about the giveaway. - giveaway_winners (:class:`telegram.GiveawayWinners`, optional): A giveaway with public - winners was completed. - invoice (:class:`telegram.Invoice`, optional): Message is an invoice for a payment, - information about the invoice. :ref:`More about payments >> `. - location (:class:`telegram.Location`, optional): Message is a shared location, information - about the location. - poll (:class:`telegram.Poll`, optional): Message is a native poll, information about the - poll. - venue (:class:`telegram.Venue`, optional): Message is a venue, information about the venue. - paid_media (:class:`telegram.PaidMedia`, optional): Message contains paid media; - information about the paid media. - - .. versionadded:: 21.4 - - Attributes: - origin (:class:`telegram.MessageOrigin`): Origin of the message replied to by the given - message. - chat (:class:`telegram.Chat`): Optional. Chat the original message belongs to. Available - only if the chat is a supergroup or a channel. - message_id (:obj:`int`): Optional. Unique message identifier inside the original chat. - Available only if the original chat is a supergroup or a channel. - link_preview_options (:class:`telegram.LinkPreviewOptions`): Optional. Options used for - link preview generation for the original message, if it is a text message. - animation (:class:`telegram.Animation`): Optional. Message is an animation, information - about the animation. - audio (:class:`telegram.Audio`): Optional. Message is an audio file, information about the - file. - document (:class:`telegram.Document`): Optional. Message is a general file, information - about the file. - photo (tuple[:class:`telegram.PhotoSize`]): Optional. Message is a photo, available sizes - of the photo. - sticker (:class:`telegram.Sticker`): Optional. Message is a sticker, information about the - sticker. - story (:class:`telegram.Story`): Optional. Message is a forwarded story. - video (:class:`telegram.Video`): Optional. Message is a video, information about the video. - video_note (:class:`telegram.VideoNote`): Optional. Message is a `video note - `_, information about the video - message. - voice (:class:`telegram.Voice`): Optional. Message is a voice message, information about - the file. - has_media_spoiler (:obj:`bool`): Optional. :obj:`True`, if the message media is covered by - a spoiler animation. - contact (:class:`telegram.Contact`): Optional. Message is a shared contact, information - about the contact. - dice (:class:`telegram.Dice`): Optional. Message is a dice with random value. - game (:Class:`telegram.Game`): Optional. Message is a game, information about the game. - :ref:`More about games >> `. - giveaway (:class:`telegram.Giveaway`): Optional. Message is a scheduled giveaway, - information about the giveaway. - giveaway_winners (:class:`telegram.GiveawayWinners`): Optional. A giveaway with public - winners was completed. - invoice (:class:`telegram.Invoice`): Optional. Message is an invoice for a payment, - information about the invoice. :ref:`More about payments >> `. - location (:class:`telegram.Location`): Optional. Message is a shared location, information - about the location. - poll (:class:`telegram.Poll`): Optional. Message is a native poll, information about the - poll. - venue (:class:`telegram.Venue`): Optional. Message is a venue, information about the venue. - paid_media (:class:`telegram.PaidMedia`): Optional. Message contains paid media; - information about the paid media. - - .. versionadded:: 21.4 - """ - - __slots__ = ( - "animation", - "audio", - "chat", - "contact", - "dice", - "document", - "game", - "giveaway", - "giveaway_winners", - "has_media_spoiler", - "invoice", - "link_preview_options", - "location", - "message_id", - "origin", - "paid_media", - "photo", - "poll", - "sticker", - "story", - "venue", - "video", - "video_note", - "voice", - ) - - def __init__( - self, - origin: MessageOrigin, - chat: Optional[Chat] = None, - message_id: Optional[int] = None, - link_preview_options: Optional[LinkPreviewOptions] = None, - animation: Optional[Animation] = None, - audio: Optional[Audio] = None, - document: Optional[Document] = None, - photo: Optional[Sequence[PhotoSize]] = None, - sticker: Optional[Sticker] = None, - story: Optional[Story] = None, - video: Optional[Video] = None, - video_note: Optional[VideoNote] = None, - voice: Optional[Voice] = None, - has_media_spoiler: Optional[bool] = None, - contact: Optional[Contact] = None, - dice: Optional[Dice] = None, - game: Optional[Game] = None, - giveaway: Optional[Giveaway] = None, - giveaway_winners: Optional[GiveawayWinners] = None, - invoice: Optional[Invoice] = None, - location: Optional[Location] = None, - poll: Optional[Poll] = None, - venue: Optional[Venue] = None, - paid_media: Optional[PaidMediaInfo] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.origin: MessageOrigin = origin - self.chat: Optional[Chat] = chat - self.message_id: Optional[int] = message_id - self.link_preview_options: Optional[LinkPreviewOptions] = link_preview_options - self.animation: Optional[Animation] = animation - self.audio: Optional[Audio] = audio - self.document: Optional[Document] = document - self.photo: Optional[tuple[PhotoSize, ...]] = parse_sequence_arg(photo) - self.sticker: Optional[Sticker] = sticker - self.story: Optional[Story] = story - self.video: Optional[Video] = video - self.video_note: Optional[VideoNote] = video_note - self.voice: Optional[Voice] = voice - self.has_media_spoiler: Optional[bool] = has_media_spoiler - self.contact: Optional[Contact] = contact - self.dice: Optional[Dice] = dice - self.game: Optional[Game] = game - self.giveaway: Optional[Giveaway] = giveaway - self.giveaway_winners: Optional[GiveawayWinners] = giveaway_winners - self.invoice: Optional[Invoice] = invoice - self.location: Optional[Location] = location - self.poll: Optional[Poll] = poll - self.venue: Optional[Venue] = venue - self.paid_media: Optional[PaidMediaInfo] = paid_media - - self._id_attrs = (self.origin,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ExternalReplyInfo"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - data["origin"] = MessageOrigin.de_json(data.get("origin"), bot) - data["chat"] = Chat.de_json(data.get("chat"), bot) - data["link_preview_options"] = LinkPreviewOptions.de_json( - data.get("link_preview_options"), bot - ) - data["animation"] = Animation.de_json(data.get("animation"), bot) - data["audio"] = Audio.de_json(data.get("audio"), bot) - data["document"] = Document.de_json(data.get("document"), bot) - data["photo"] = tuple(PhotoSize.de_list(data.get("photo"), bot)) - data["sticker"] = Sticker.de_json(data.get("sticker"), bot) - data["story"] = Story.de_json(data.get("story"), bot) - data["video"] = Video.de_json(data.get("video"), bot) - data["video_note"] = VideoNote.de_json(data.get("video_note"), bot) - data["voice"] = Voice.de_json(data.get("voice"), bot) - data["contact"] = Contact.de_json(data.get("contact"), bot) - data["dice"] = Dice.de_json(data.get("dice"), bot) - data["game"] = Game.de_json(data.get("game"), bot) - data["giveaway"] = Giveaway.de_json(data.get("giveaway"), bot) - data["giveaway_winners"] = GiveawayWinners.de_json(data.get("giveaway_winners"), bot) - data["invoice"] = Invoice.de_json(data.get("invoice"), bot) - data["location"] = Location.de_json(data.get("location"), bot) - data["poll"] = Poll.de_json(data.get("poll"), bot) - data["venue"] = Venue.de_json(data.get("venue"), bot) - data["paid_media"] = PaidMediaInfo.de_json(data.get("paid_media"), bot) - - return super().de_json(data=data, bot=bot) - - -class TextQuote(TelegramObject): - """ - This object contains information about the quoted part of a message that is replied to - by the given message. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text` and :attr:`position` are equal. - - .. versionadded:: 20.8 - - Args: - text (:obj:`str`): Text of the quoted part of a message that is replied to by the given - message. - position (:obj:`int`): Approximate quote position in the original message in UTF-16 code - units as specified by the sender. - entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that - appear - in the quote. Currently, only bold, italic, underline, strikethrough, spoiler, and - custom_emoji entities are kept in quotes. - is_manual (:obj:`bool`, optional): :obj:`True`, if the quote was chosen manually by the - message sender. Otherwise, the quote was added automatically by the server. - - Attributes: - text (:obj:`str`): Text of the quoted part of a message that is replied to by the given - message. - position (:obj:`int`): Approximate quote position in the original message in UTF-16 code - units as specified by the sender. - entities (tuple[:class:`telegram.MessageEntity`]): Optional. Special entities that appear - in the quote. Currently, only bold, italic, underline, strikethrough, spoiler, and - custom_emoji entities are kept in quotes. - is_manual (:obj:`bool`): Optional. :obj:`True`, if the quote was chosen manually by the - message sender. Otherwise, the quote was added automatically by the server. - """ - - __slots__ = ( - "entities", - "is_manual", - "position", - "text", - ) - - def __init__( - self, - text: str, - position: int, - entities: Optional[Sequence[MessageEntity]] = None, - is_manual: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.text: str = text - self.position: int = position - self.entities: Optional[tuple[MessageEntity, ...]] = parse_sequence_arg(entities) - self.is_manual: Optional[bool] = is_manual - - self._id_attrs = ( - self.text, - self.position, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["TextQuote"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - data["entities"] = tuple(MessageEntity.de_list(data.get("entities"), bot)) - - return super().de_json(data=data, bot=bot) - - -class ReplyParameters(TelegramObject): - """ - Describes reply parameters for the message that is being sent. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_id` is equal. - - .. versionadded:: 20.8 - - Args: - message_id (:obj:`int`): Identifier of the message that will be replied to in the current - chat, or in the chat :paramref:`chat_id` if it is specified. - chat_id (:obj:`int` | :obj:`str`, optional): If the message to be replied to is from a - different chat, |chat_id_channel| - Not supported for messages sent on behalf of a business account. - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| Can be - used only for replies in the same chat and forum topic. - quote (:obj:`str`, optional): Quoted part of the message to be replied to; 0-1024 - characters after entities parsing. The quote must be an exact substring of the message - to be replied to, including bold, italic, underline, strikethrough, spoiler, and - custom_emoji entities. The message will fail to send if the quote isn't found in the - original message. - quote_parse_mode (:obj:`str`, optional): Mode for parsing entities in the quote. See - :wiki:`formatting options ` for - more details. - quote_entities (Sequence[:class:`telegram.MessageEntity`], optional): A JSON-serialized - list - of special entities that appear in the quote. It can be specified instead of - :paramref:`quote_parse_mode`. - quote_position (:obj:`int`, optional): Position of the quote in the original message in - UTF-16 code units. - - Attributes: - message_id (:obj:`int`): Identifier of the message that will be replied to in the current - chat, or in the chat :paramref:`chat_id` if it is specified. - chat_id (:obj:`int` | :obj:`str`): Optional. If the message to be replied to is from a - different chat, |chat_id_channel| - Not supported for messages sent on behalf of a business account. - allow_sending_without_reply (:obj:`bool`): Optional. |allow_sending_without_reply| Can be - used only for replies in the same chat and forum topic. - quote (:obj:`str`): Optional. Quoted part of the message to be replied to; 0-1024 - characters after entities parsing. The quote must be an exact substring of the message - to be replied to, including bold, italic, underline, strikethrough, spoiler, and - custom_emoji entities. The message will fail to send if the quote isn't found in the - original message. - quote_parse_mode (:obj:`str`): Optional. Mode for parsing entities in the quote. See - :wiki:`formatting options ` for - more details. - quote_entities (tuple[:class:`telegram.MessageEntity`]): Optional. A JSON-serialized list - of special entities that appear in the quote. It can be specified instead of - :paramref:`quote_parse_mode`. - quote_position (:obj:`int`): Optional. Position of the quote in the original message in - UTF-16 code units. - """ - - __slots__ = ( - "allow_sending_without_reply", - "chat_id", - "message_id", - "quote", - "quote_entities", - "quote_parse_mode", - "quote_position", - ) - - def __init__( - self, - message_id: int, - chat_id: Optional[Union[int, str]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: Optional[str] = None, - quote_parse_mode: ODVInput[str] = DEFAULT_NONE, - quote_entities: Optional[Sequence[MessageEntity]] = None, - quote_position: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.message_id: int = message_id - self.chat_id: Optional[Union[int, str]] = chat_id - self.allow_sending_without_reply: ODVInput[bool] = allow_sending_without_reply - self.quote: Optional[str] = quote - self.quote_parse_mode: ODVInput[str] = quote_parse_mode - self.quote_entities: Optional[tuple[MessageEntity, ...]] = parse_sequence_arg( - quote_entities - ) - self.quote_position: Optional[int] = quote_position - - self._id_attrs = (self.message_id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ReplyParameters"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - data["quote_entities"] = tuple(MessageEntity.de_list(data.get("quote_entities"), bot)) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_replykeyboardmarkup.py b/venv/lib/python3.11/site-packages/telegram/_replykeyboardmarkup.py deleted file mode 100755 index 3928f82..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_replykeyboardmarkup.py +++ /dev/null @@ -1,360 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ReplyKeyboardMarkup.""" - -from collections.abc import Sequence -from typing import Final, Optional, Union - -from telegram import constants -from telegram._keyboardbutton import KeyboardButton -from telegram._telegramobject import TelegramObject -from telegram._utils.markup import check_keyboard_type -from telegram._utils.types import JSONDict - - -class ReplyKeyboardMarkup(TelegramObject): - """This object represents a custom keyboard with reply options. Not supported in channels and - for messages sent on behalf of a Telegram Business account. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their size of :attr:`keyboard` and all the buttons are equal. - - .. figure:: https://core.telegram.org/file/464001950/1191a/2RwpmgU-swU.123554/b5\ - 0478c124d5914c23 - :align: center - - A reply keyboard with reply options. - - .. seealso:: - Another kind of keyboard would be the :class:`telegram.InlineKeyboardMarkup`. - - Examples: - * Example usage: A user requests to change the bot's language, bot replies to the request - with a keyboard to select the new language. Other users in the group don't see - the keyboard. - * :any:`Conversation Bot ` - * :any:`Conversation Bot 2 ` - - Args: - keyboard (Sequence[Sequence[:obj:`str` | :class:`telegram.KeyboardButton`]]): Array of - button rows, each represented by an Array of :class:`telegram.KeyboardButton` objects. - resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically - for optimal fit (e.g., make the keyboard smaller if there are just two rows of - buttons). Defaults to :obj:`False`, in which case the custom keyboard is always of the - same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as - it's been used. The keyboard will still be available, but clients will automatically - display the usual letter-keyboard in the chat - the user can press a special button in - the input field to see the custom keyboard again. Defaults to :obj:`False`. - selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to - specific users only. Targets: - - 1) Users that are @mentioned in the :attr:`~telegram.Message.text` of the - :class:`telegram.Message` object. - 2) If the bot's message is a reply to a message in the same chat and forum topic, - sender of the original message. - - Defaults to :obj:`False`. - - input_field_placeholder (:obj:`str`, optional): The placeholder to be shown in the input - field when the keyboard is active; - :tg-const:`telegram.ReplyKeyboardMarkup.MIN_INPUT_FIELD_PLACEHOLDER`- - :tg-const:`telegram.ReplyKeyboardMarkup.MAX_INPUT_FIELD_PLACEHOLDER` - characters. - - .. versionadded:: 13.7 - is_persistent (:obj:`bool`, optional): Requests clients to always show the keyboard when - the regular keyboard is hidden. Defaults to :obj:`False`, in which case the custom - keyboard can be hidden and opened with a keyboard icon. - - .. versionadded:: 20.0 - - Attributes: - keyboard (tuple[tuple[:class:`telegram.KeyboardButton`]]): Array of button rows, - each represented by an Array of :class:`telegram.KeyboardButton` objects. - resize_keyboard (:obj:`bool`): Optional. Requests clients to resize the keyboard vertically - for optimal fit (e.g., make the keyboard smaller if there are just two rows of - buttons). Defaults to :obj:`False`, in which case the custom keyboard is always of the - same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`): Optional. Requests clients to hide the keyboard as soon as - it's been used. The keyboard will still be available, but clients will automatically - display the usual letter-keyboard in the chat - the user can press a special button in - the input field to see the custom keyboard again. Defaults to :obj:`False`. - selective (:obj:`bool`): Optional. Show the keyboard to specific users only. - Targets: - - 1) Users that are @mentioned in the :attr:`~telegram.Message.text` of the - :class:`telegram.Message` object. - 2) If the bot's message is a reply to a message in the same chat and forum topic, - sender of the original message. - - Defaults to :obj:`False`. - - input_field_placeholder (:obj:`str`): Optional. The placeholder to be shown in the input - field when the keyboard is active; - :tg-const:`telegram.ReplyKeyboardMarkup.MIN_INPUT_FIELD_PLACEHOLDER`- - :tg-const:`telegram.ReplyKeyboardMarkup.MAX_INPUT_FIELD_PLACEHOLDER` - characters. - - .. versionadded:: 13.7 - is_persistent (:obj:`bool`): Optional. Requests clients to always show the keyboard when - the regular keyboard is hidden. If :obj:`False`, the custom keyboard can be hidden and - opened with a keyboard icon. - - .. versionadded:: 20.0 - - """ - - __slots__ = ( - "input_field_placeholder", - "is_persistent", - "keyboard", - "one_time_keyboard", - "resize_keyboard", - "selective", - ) - - def __init__( - self, - keyboard: Sequence[Sequence[Union[str, KeyboardButton]]], - resize_keyboard: Optional[bool] = None, - one_time_keyboard: Optional[bool] = None, - selective: Optional[bool] = None, - input_field_placeholder: Optional[str] = None, - is_persistent: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - if not check_keyboard_type(keyboard): - raise ValueError( - "The parameter `keyboard` should be a sequence of sequences of " - "strings or KeyboardButtons" - ) - - # Required - self.keyboard: tuple[tuple[KeyboardButton, ...], ...] = tuple( - tuple(KeyboardButton(button) if isinstance(button, str) else button for button in row) - for row in keyboard - ) - - # Optionals - self.resize_keyboard: Optional[bool] = resize_keyboard - self.one_time_keyboard: Optional[bool] = one_time_keyboard - self.selective: Optional[bool] = selective - self.input_field_placeholder: Optional[str] = input_field_placeholder - self.is_persistent: Optional[bool] = is_persistent - - self._id_attrs = (self.keyboard,) - - self._freeze() - - @classmethod - def from_button( - cls, - button: Union[KeyboardButton, str], - resize_keyboard: bool = False, - one_time_keyboard: bool = False, - selective: bool = False, - input_field_placeholder: Optional[str] = None, - is_persistent: Optional[bool] = None, - **kwargs: object, - ) -> "ReplyKeyboardMarkup": - """Shortcut for:: - - ReplyKeyboardMarkup([[button]], **kwargs) - - Return a ReplyKeyboardMarkup from a single KeyboardButton. - - Args: - button (:class:`telegram.KeyboardButton` | :obj:`str`): The button to use in - the markup. - resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard - vertically for optimal fit (e.g., make the keyboard smaller if there are just two - rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is - always of the same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as - soon as it's been used. The keyboard will still be available, but clients will - automatically display the usual letter-keyboard in the chat - the user can press - a special button in the input field to see the custom keyboard again. - Defaults to :obj:`False`. - selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard - to specific users only. Targets: - - 1) Users that are @mentioned in the text of the Message object. - 2) If the bot's message is a reply to a message in the same chat and forum topic, - sender of the original message. - - Defaults to :obj:`False`. - - input_field_placeholder (:obj:`str`): Optional. The placeholder shown in the input - field when the reply is active. - - .. versionadded:: 13.7 - is_persistent (:obj:`bool`): Optional. Requests clients to always show the keyboard - when the regular keyboard is hidden. Defaults to :obj:`False`, in which case the - custom keyboard can be hidden and opened with a keyboard icon. - - .. versionadded:: 20.0 - """ - return cls( - [[button]], - resize_keyboard=resize_keyboard, - one_time_keyboard=one_time_keyboard, - selective=selective, - input_field_placeholder=input_field_placeholder, - is_persistent=is_persistent, - **kwargs, # type: ignore[arg-type] - ) - - @classmethod - def from_row( - cls, - button_row: Sequence[Union[str, KeyboardButton]], - resize_keyboard: bool = False, - one_time_keyboard: bool = False, - selective: bool = False, - input_field_placeholder: Optional[str] = None, - is_persistent: Optional[bool] = None, - **kwargs: object, - ) -> "ReplyKeyboardMarkup": - """Shortcut for:: - - ReplyKeyboardMarkup([button_row], **kwargs) - - Return a ReplyKeyboardMarkup from a single row of KeyboardButtons. - - Args: - button_row (Sequence[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to - use in the markup. - - .. versionchanged:: 20.0 - |sequenceargs| - resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard - vertically for optimal fit (e.g., make the keyboard smaller if there are just two - rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is - always of the same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as - soon as it's been used. The keyboard will still be available, but clients will - automatically display the usual letter-keyboard in the chat - the user can press - a special button in the input field to see the custom keyboard again. - Defaults to :obj:`False`. - selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard - to specific users only. Targets: - - 1) Users that are @mentioned in the text of the Message object. - 2) If the bot's message is a reply to a message in the same chat and forum topic, - sender of the original message. - - Defaults to :obj:`False`. - - input_field_placeholder (:obj:`str`): Optional. The placeholder shown in the input - field when the reply is active. - - .. versionadded:: 13.7 - is_persistent (:obj:`bool`): Optional. Requests clients to always show the keyboard - when the regular keyboard is hidden. Defaults to :obj:`False`, in which case the - custom keyboard can be hidden and opened with a keyboard icon. - - .. versionadded:: 20.0 - - """ - return cls( - [button_row], - resize_keyboard=resize_keyboard, - one_time_keyboard=one_time_keyboard, - selective=selective, - input_field_placeholder=input_field_placeholder, - is_persistent=is_persistent, - **kwargs, # type: ignore[arg-type] - ) - - @classmethod - def from_column( - cls, - button_column: Sequence[Union[str, KeyboardButton]], - resize_keyboard: bool = False, - one_time_keyboard: bool = False, - selective: bool = False, - input_field_placeholder: Optional[str] = None, - is_persistent: Optional[bool] = None, - **kwargs: object, - ) -> "ReplyKeyboardMarkup": - """Shortcut for:: - - ReplyKeyboardMarkup([[button] for button in button_column], **kwargs) - - Return a ReplyKeyboardMarkup from a single column of KeyboardButtons. - - Args: - button_column (Sequence[:class:`telegram.KeyboardButton` | :obj:`str`]): The button - to use in the markup. - - .. versionchanged:: 20.0 - |sequenceargs| - resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard - vertically for optimal fit (e.g., make the keyboard smaller if there are just two - rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is - always of the same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as - soon as it's been used. The keyboard will still be available, but clients will - automatically display the usual letter-keyboard in the chat - the user can press - a special button in the input field to see the custom keyboard again. - Defaults to :obj:`False`. - selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard - to specific users only. Targets: - - 1) Users that are @mentioned in the text of the Message object. - 2) If the bot's message is a reply to a message in the same chat and forum topic, - sender of the original message. - - Defaults to :obj:`False`. - - input_field_placeholder (:obj:`str`): Optional. The placeholder shown in the input - field when the reply is active. - - .. versionadded:: 13.7 - is_persistent (:obj:`bool`): Optional. Requests clients to always show the keyboard - when the regular keyboard is hidden. Defaults to :obj:`False`, in which case the - custom keyboard can be hidden and opened with a keyboard icon. - - .. versionadded:: 20.0 - - """ - button_grid = [[button] for button in button_column] - return cls( - button_grid, - resize_keyboard=resize_keyboard, - one_time_keyboard=one_time_keyboard, - selective=selective, - input_field_placeholder=input_field_placeholder, - is_persistent=is_persistent, - **kwargs, # type: ignore[arg-type] - ) - - MIN_INPUT_FIELD_PLACEHOLDER: Final[int] = constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER - """:const:`telegram.constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER` - - .. versionadded:: 20.0 - """ - MAX_INPUT_FIELD_PLACEHOLDER: Final[int] = constants.ReplyLimit.MAX_INPUT_FIELD_PLACEHOLDER - """:const:`telegram.constants.ReplyLimit.MAX_INPUT_FIELD_PLACEHOLDER` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_replykeyboardremove.py b/venv/lib/python3.11/site-packages/telegram/_replykeyboardremove.py deleted file mode 100755 index 808bee2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_replykeyboardremove.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ReplyKeyboardRemove.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class ReplyKeyboardRemove(TelegramObject): - """ - Upon receiving a message with this object, Telegram clients will remove the current custom - keyboard and display the default letter-keyboard. By default, custom keyboards are displayed - until a new keyboard is sent by a bot. An exception is made for one-time keyboards that are - hidden immediately after the user presses a button (see :class:`telegram.ReplyKeyboardMarkup`). - Not supported in channels and for messages sent on behalf of a Telegram Business account. - - Note: - User will not be able to summon this keyboard; if you want to hide the keyboard from - sight but keep it accessible, use :attr:`telegram.ReplyKeyboardMarkup.one_time_keyboard`. - - Examples: - * Example usage: A user votes in a poll, bot returns confirmation message in reply to - the vote and removes the keyboard for that user, while still showing the keyboard with - poll options to users who haven't voted yet. - * :any:`Conversation Bot ` - * :any:`Conversation Bot 2 ` - - Args: - selective (:obj:`bool`, optional): Use this parameter if you want to remove the keyboard - for specific users only. Targets: - - 1) Users that are @mentioned in the text of the :class:`telegram.Message` object. - 2) If the bot's message is a reply to a message in the same chat and forum topic, - sender of the original message. - - Attributes: - remove_keyboard (:obj:`True`): Requests clients to remove the custom keyboard. - selective (:obj:`bool`): Optional. Remove the keyboard for specific users only. - Targets: - - 1) Users that are @mentioned in the text of the :class:`telegram.Message` object. - 2) If the bot's message is a reply to a message in the same chat and forum topic, - sender of the original message. - - """ - - __slots__ = ("remove_keyboard", "selective") - - def __init__(self, selective: Optional[bool] = None, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - # Required - self.remove_keyboard: bool = True - # Optionals - self.selective: Optional[bool] = selective - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_sentwebappmessage.py b/venv/lib/python3.11/site-packages/telegram/_sentwebappmessage.py deleted file mode 100755 index 492f440..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_sentwebappmessage.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Sent Web App Message.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class SentWebAppMessage(TelegramObject): - """Contains information about an inline message sent by a Web App on behalf of a user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`inline_message_id` are equal. - - .. versionadded:: 20.0 - - Args: - inline_message_id (:obj:`str`, optional): Identifier of the sent inline message. Available - only if there is an :attr:`inline keyboard ` attached to - the message. - - Attributes: - inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message. Available - only if there is an :attr:`inline keyboard ` attached to - the message. - """ - - __slots__ = ("inline_message_id",) - - def __init__( - self, inline_message_id: Optional[str] = None, *, api_kwargs: Optional[JSONDict] = None - ): - super().__init__(api_kwargs=api_kwargs) - # Optionals - self.inline_message_id: Optional[str] = inline_message_id - - self._id_attrs = (self.inline_message_id,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_shared.py b/venv/lib/python3.11/site-packages/telegram/_shared.py deleted file mode 100755 index 5ba54ea..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_shared.py +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains two objects used for request chats/users service messages.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._files.photosize import PhotoSize -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram._bot import Bot - - -class UsersShared(TelegramObject): - """ - This object contains information about the user whose identifier was shared with the bot - using a :class:`telegram.KeyboardButtonRequestUsers` button. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`request_id` and :attr:`users` are equal. - - .. versionadded:: 20.8 - Bot API 7.0 replaces ``UserShared`` with this class. The only difference is that now - the ``user_ids`` is a sequence instead of a single integer. - - .. versionchanged:: 21.1 - The argument :attr:`users` is now considered for the equality comparison instead of - ``user_ids``. - - .. versionremoved:: 21.2 - Removed the deprecated argument and attribute ``user_ids``. - - Args: - request_id (:obj:`int`): Identifier of the request. - users (Sequence[:class:`telegram.SharedUser`]): Information about users shared with the - bot. - - .. versionadded:: 21.1 - - .. versionchanged:: 21.2 - This argument is now required. - - Attributes: - request_id (:obj:`int`): Identifier of the request. - users (tuple[:class:`telegram.SharedUser`]): Information about users shared with the - bot. - - .. versionadded:: 21.1 - """ - - __slots__ = ("request_id", "users") - - def __init__( - self, - request_id: int, - users: Sequence["SharedUser"], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.request_id: int = request_id - self.users: tuple[SharedUser, ...] = parse_sequence_arg(users) - - self._id_attrs = (self.request_id, self.users) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["UsersShared"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["users"] = SharedUser.de_list(data.get("users"), bot) - - api_kwargs = {} - # This is a deprecated field that TG still returns for backwards compatibility - # Let's filter it out to speed up the de-json process - if user_ids := data.get("user_ids"): - api_kwargs = {"user_ids": user_ids} - - return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) - - -class ChatShared(TelegramObject): - """ - This object contains information about the chat whose identifier was shared with the bot - using a :class:`telegram.KeyboardButtonRequestChat` button. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`request_id` and :attr:`chat_id` are equal. - - .. versionadded:: 20.1 - - Args: - request_id (:obj:`int`): Identifier of the request. - chat_id (:obj:`int`): Identifier of the shared user. This number may be greater than 32 - bits and some programming languages may have difficulty/silent defects in interpreting - it. But it is smaller than 52 bits, so a signed 64-bit integer or double-precision - float type are safe for storing this identifier. - title (:obj:`str`, optional): Title of the chat, if the title was requested by the bot. - - .. versionadded:: 21.1 - username (:obj:`str`, optional): Username of the chat, if the username was requested by - the bot and available. - - .. versionadded:: 21.1 - photo (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the chat photo, - if the photo was requested by the bot - - .. versionadded:: 21.1 - - Attributes: - request_id (:obj:`int`): Identifier of the request. - chat_id (:obj:`int`): Identifier of the shared user. This number may be greater than 32 - bits and some programming languages may have difficulty/silent defects in interpreting - it. But it is smaller than 52 bits, so a signed 64-bit integer or double-precision - float type are safe for storing this identifier. - title (:obj:`str`): Optional. Title of the chat, if the title was requested by the bot. - - .. versionadded:: 21.1 - username (:obj:`str`): Optional. Username of the chat, if the username was requested by - the bot and available. - - .. versionadded:: 21.1 - photo (tuple[:class:`telegram.PhotoSize`]): Optional. Available sizes of the chat photo, - if the photo was requested by the bot - - .. versionadded:: 21.1 - """ - - __slots__ = ("chat_id", "photo", "request_id", "title", "username") - - def __init__( - self, - request_id: int, - chat_id: int, - title: Optional[str] = None, - username: Optional[str] = None, - photo: Optional[Sequence[PhotoSize]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.request_id: int = request_id - self.chat_id: int = chat_id - self.title: Optional[str] = title - self.username: Optional[str] = username - self.photo: Optional[tuple[PhotoSize, ...]] = parse_sequence_arg(photo) - - self._id_attrs = (self.request_id, self.chat_id) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatShared"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["photo"] = PhotoSize.de_list(data.get("photo"), bot) - return super().de_json(data=data, bot=bot) - - -class SharedUser(TelegramObject): - """ - This object contains information about a user that was shared with the bot using a - :class:`telegram.KeyboardButtonRequestUsers` button. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`user_id` is equal. - - .. versionadded:: 21.1 - - Args: - user_id (:obj:`int`): Identifier of the shared user. This number may have 32 significant - bits and some programming languages may have difficulty/silent defects in interpreting - it. But it has atmost 52 significant bits, so 64-bit integers or double-precision - float types are safe for storing these identifiers. The bot may not have access to the - user and could be unable to use this identifier, unless the user is already known to - the bot by some other means. - first_name (:obj:`str`, optional): First name of the user, if the name was requested by the - bot. - last_name (:obj:`str`, optional): Last name of the user, if the name was requested by the - bot. - username (:obj:`str`, optional): Username of the user, if the username was requested by the - bot. - photo (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the chat photo, - if the photo was requested by the bot. - - Attributes: - user_id (:obj:`int`): Identifier of the shared user. This number may have 32 significant - bits and some programming languages may have difficulty/silent defects in interpreting - it. But it has atmost 52 significant bits, so 64-bit integers or double-precision - float types are safe for storing these identifiers. The bot may not have access to the - user and could be unable to use this identifier, unless the user is already known to - the bot by some other means. - first_name (:obj:`str`): Optional. First name of the user, if the name was requested by the - bot. - last_name (:obj:`str`): Optional. Last name of the user, if the name was requested by the - bot. - username (:obj:`str`): Optional. Username of the user, if the username was requested by the - bot. - photo (tuple[:class:`telegram.PhotoSize`]): Available sizes of the chat photo, if - the photo was requested by the bot. This list is empty if the photo was not requsted. - """ - - __slots__ = ("first_name", "last_name", "photo", "user_id", "username") - - def __init__( - self, - user_id: int, - first_name: Optional[str] = None, - last_name: Optional[str] = None, - username: Optional[str] = None, - photo: Optional[Sequence[PhotoSize]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.user_id: int = user_id - self.first_name: Optional[str] = first_name - self.last_name: Optional[str] = last_name - self.username: Optional[str] = username - self.photo: Optional[tuple[PhotoSize, ...]] = parse_sequence_arg(photo) - - self._id_attrs = (self.user_id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["SharedUser"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["photo"] = PhotoSize.de_list(data.get("photo"), bot) - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_story.py b/venv/lib/python3.11/site-packages/telegram/_story.py deleted file mode 100755 index 06832e0..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_story.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object related to a Telegram Story.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._chat import Chat -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class Story(TelegramObject): - """ - This object represents a story. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`chat` and :attr:`id` are equal. - - .. versionadded:: 20.5 - - .. versionchanged:: 21.0 - Added attributes :attr:`chat` and :attr:`id` and equality based on them. - - Args: - chat (:class:`telegram.Chat`): Chat that posted the story. - id (:obj:`int`): Unique identifier for the story in the chat. - - Attributes: - chat (:class:`telegram.Chat`): Chat that posted the story. - id (:obj:`int`): Unique identifier for the story in the chat. - - """ - - __slots__ = ( - "chat", - "id", - ) - - def __init__( - self, - chat: Chat, - id: int, # pylint: disable=redefined-builtin - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.chat: Chat = chat - self.id: int = id - - self._id_attrs = (self.chat, self.id) - - self._freeze() - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Story"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["chat"] = Chat.de_json(data.get("chat", {}), bot) - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_switchinlinequerychosenchat.py b/venv/lib/python3.11/site-packages/telegram/_switchinlinequerychosenchat.py deleted file mode 100755 index 7fca5a9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_switchinlinequerychosenchat.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -"""This module contains a class that represents a Telegram SwitchInlineQueryChosenChat.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class SwitchInlineQueryChosenChat(TelegramObject): - """ - This object represents an inline button that switches the current user to inline mode in a - chosen chat, with an optional default inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`query`, :attr:`allow_user_chats`, :attr:`allow_bot_chats`, - :attr:`allow_group_chats`, and :attr:`allow_channel_chats` are equal. - - .. versionadded:: 20.3 - - Caution: - The PTB team has discovered that you must pass at least one of - :paramref:`allow_user_chats`, :paramref:`allow_bot_chats`, :paramref:`allow_group_chats`, - or :paramref:`allow_channel_chats` to Telegram. Otherwise, an error will be raised. - - Args: - query (:obj:`str`, optional): The default inline query to be inserted in the input field. - If left empty, only the bot's username will be inserted. - allow_user_chats (:obj:`bool`, optional): Pass :obj:`True`, if private chats with users - can be chosen. - allow_bot_chats (:obj:`bool`, optional): Pass :obj:`True`, if private chats with bots can - be chosen. - allow_group_chats (:obj:`bool`, optional): Pass :obj:`True`, if group and supergroup chats - can be chosen. - allow_channel_chats (:obj:`bool`, optional): Pass :obj:`True`, if channel chats can be - chosen. - - Attributes: - query (:obj:`str`): Optional. The default inline query to be inserted in the input field. - If left empty, only the bot's username will be inserted. - allow_user_chats (:obj:`bool`): Optional. :obj:`True`, if private chats with users can be - chosen. - allow_bot_chats (:obj:`bool`): Optional. :obj:`True`, if private chats with bots can be - chosen. - allow_group_chats (:obj:`bool`): Optional. :obj:`True`, if group and supergroup chats can - be chosen. - allow_channel_chats (:obj:`bool`): Optional. :obj:`True`, if channel chats can be chosen. - - """ - - __slots__ = ( - "allow_bot_chats", - "allow_channel_chats", - "allow_group_chats", - "allow_user_chats", - "query", - ) - - def __init__( - self, - query: Optional[str] = None, - allow_user_chats: Optional[bool] = None, - allow_bot_chats: Optional[bool] = None, - allow_group_chats: Optional[bool] = None, - allow_channel_chats: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Optional - self.query: Optional[str] = query - self.allow_user_chats: Optional[bool] = allow_user_chats - self.allow_bot_chats: Optional[bool] = allow_bot_chats - self.allow_group_chats: Optional[bool] = allow_group_chats - self.allow_channel_chats: Optional[bool] = allow_channel_chats - - self._id_attrs = ( - self.query, - self.allow_user_chats, - self.allow_bot_chats, - self.allow_group_chats, - self.allow_channel_chats, - ) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_telegramobject.py b/venv/lib/python3.11/site-packages/telegram/_telegramobject.py deleted file mode 100755 index baa739e..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_telegramobject.py +++ /dev/null @@ -1,675 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""Base class for Telegram Objects.""" -import contextlib -import datetime as dtm -import inspect -import json -from collections.abc import Iterator, Mapping, Sized -from contextlib import contextmanager -from copy import deepcopy -from itertools import chain -from types import MappingProxyType -from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypeVar, Union, cast - -from telegram._utils.datetime import to_timestamp -from telegram._utils.defaultvalue import DefaultValue -from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn - -if TYPE_CHECKING: - from telegram import Bot - -Tele_co = TypeVar("Tele_co", bound="TelegramObject", covariant=True) - - -class TelegramObject: - """Base class for most Telegram objects. - - Objects of this type are subscriptable with strings. See :meth:`__getitem__` for more details. - The :mod:`pickle` and :func:`~copy.deepcopy` behavior of objects of this type are defined by - :meth:`__getstate__`, :meth:`__setstate__` and :meth:`__deepcopy__`. - - Tip: - Objects of this type can be serialized via Python's :mod:`pickle` module and pickled - objects from one version of PTB are usually loadable in future versions. However, we can - not guarantee that this compatibility will always be provided. At least a manual one-time - conversion of the data may be needed on major updates of the library. - - .. versionchanged:: 20.0 - - * Removed argument and attribute ``bot`` for several subclasses. Use - :meth:`set_bot` and :meth:`get_bot` instead. - * Removed the possibility to pass arbitrary keyword arguments for several subclasses. - * String representations objects of this type was overhauled. See :meth:`__repr__` for - details. As this class doesn't implement :meth:`object.__str__`, the default - implementation will be used, which is equivalent to :meth:`__repr__`. - * Objects of this class (or subclasses) are now immutable. This means that you can't set - or delete attributes anymore. Moreover, attributes that were formerly of type - :obj:`list` are now of type :obj:`tuple`. - - Arguments: - api_kwargs (dict[:obj:`str`, any], optional): |toapikwargsarg| - - .. versionadded:: 20.0 - - Attributes: - api_kwargs (:obj:`types.MappingProxyType` [:obj:`str`, any]): |toapikwargsattr| - - .. versionadded:: 20.0 - - """ - - __slots__ = ("_bot", "_frozen", "_id_attrs", "api_kwargs") - - # Used to cache the names of the parameters of the __init__ method of the class - # Must be a private attribute to avoid name clashes between subclasses - __INIT_PARAMS: ClassVar[set[str]] = set() - # Used to check if __INIT_PARAMS has been set for the current class. Unfortunately, we can't - # just check if `__INIT_PARAMS is None`, since subclasses use the parent class' __INIT_PARAMS - # unless it's overridden - __INIT_PARAMS_CHECK: Optional[type["TelegramObject"]] = None - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - # Setting _frozen to `False` here means that classes without arguments still need to - # implement __init__. However, with `True` would mean increased usage of - # `with self._unfrozen()` in the `__init__` of subclasses and we have fewer empty - # classes than classes with arguments. - self._frozen: bool = False - self._id_attrs: tuple[object, ...] = () - self._bot: Optional[Bot] = None - # We don't do anything with api_kwargs here - see docstring of _apply_api_kwargs - self.api_kwargs: Mapping[str, Any] = MappingProxyType(api_kwargs or {}) - - def __eq__(self, other: object) -> bool: - """Compares this object with :paramref:`other` in terms of equality. - If this object and :paramref:`other` are `not` objects of the same class, - this comparison will fall back to Python's default implementation of :meth:`object.__eq__`. - Otherwise, both objects may be compared in terms of equality, if the corresponding - subclass of :class:`TelegramObject` has defined a set of attributes to compare and - the objects are considered to be equal, if all of these attributes are equal. - If the subclass has not defined a set of attributes to compare, a warning will be issued. - - Tip: - If instances of a class in the :mod:`telegram` module are comparable in terms of - equality, the documentation of the class will state the attributes that will be used - for this comparison. - - Args: - other (:obj:`object`): The object to compare with. - - Returns: - :obj:`bool` - - """ - if isinstance(other, self.__class__): - if not self._id_attrs: - warn( - f"Objects of type {self.__class__.__name__} can not be meaningfully tested for" - " equivalence.", - stacklevel=2, - ) - if not other._id_attrs: - warn( - f"Objects of type {other.__class__.__name__} can not be meaningfully tested" - " for equivalence.", - stacklevel=2, - ) - return self._id_attrs == other._id_attrs - return super().__eq__(other) - - def __hash__(self) -> int: - """Builds a hash value for this object such that the hash of two objects is equal if and - only if the objects are equal in terms of :meth:`__eq__`. - - Returns: - :obj:`int` - """ - if self._id_attrs: - return hash((self.__class__, self._id_attrs)) - return super().__hash__() - - def __setattr__(self, key: str, value: object) -> None: - """Overrides :meth:`object.__setattr__` to prevent the overriding of attributes. - - Raises: - :exc:`AttributeError` - """ - # protected attributes can always be set for convenient internal use - if key[0] == "_" or not getattr(self, "_frozen", True): - super().__setattr__(key, value) - return - - raise AttributeError( - f"Attribute `{key}` of class `{self.__class__.__name__}` can't be set!" - ) - - def __delattr__(self, key: str) -> None: - """Overrides :meth:`object.__delattr__` to prevent the deletion of attributes. - - Raises: - :exc:`AttributeError` - """ - # protected attributes can always be set for convenient internal use - if key[0] == "_" or not getattr(self, "_frozen", True): - super().__delattr__(key) - return - - raise AttributeError( - f"Attribute `{key}` of class `{self.__class__.__name__}` can't be deleted!" - ) - - def __repr__(self) -> str: - """Gives a string representation of this object in the form - ``ClassName(attr_1=value_1, attr_2=value_2, ...)``, where attributes are omitted if they - have the value :obj:`None` or are empty instances of :class:`collections.abc.Sized` (e.g. - :class:`list`, :class:`dict`, :class:`set`, :class:`str`, etc.). - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - # * `__repr__` goal is to be unambiguous - # * `__str__` goal is to be readable - # * `str()` calls `__repr__`, if `__str__` is not defined - # In our case "unambiguous" and "readable" largely coincide, so we can use the same logic. - as_dict = self._get_attrs(recursive=False, include_private=False) - - if not self.api_kwargs: - # Drop api_kwargs from the representation, if empty - as_dict.pop("api_kwargs", None) - else: - # Otherwise, we want to skip the "mappingproxy" part of the repr - as_dict["api_kwargs"] = dict(self.api_kwargs) - - contents = ", ".join( - f"{k}={as_dict[k]!r}" - for k in sorted(as_dict.keys()) - if ( - as_dict[k] is not None - and not ( - isinstance(as_dict[k], Sized) - and len(as_dict[k]) == 0 # type: ignore[arg-type] - ) - ) - ) - return f"{self.__class__.__name__}({contents})" - - def __getitem__(self, item: str) -> object: - """ - Objects of this type are subscriptable with strings, where - ``telegram_object["attribute_name"]`` is equivalent to ``telegram_object.attribute_name``. - - Tip: - This is useful for dynamic attribute lookup, i.e. ``telegram_object[arg]`` where the - value of ``arg`` is determined at runtime. - In all other cases, it's recommended to use the dot notation instead, i.e. - ``telegram_object.attribute_name``. - - .. versionchanged:: 20.0 - - ``telegram_object['from']`` will look up the key ``from_user``. This is to account for - special cases like :attr:`Message.from_user` that deviate from the official Bot API. - - Args: - item (:obj:`str`): The name of the attribute to look up. - - Returns: - :obj:`object` - - Raises: - :exc:`KeyError`: If the object does not have an attribute with the appropriate name. - """ - if item == "from": - item = "from_user" - try: - return getattr(self, item) - except AttributeError as exc: - raise KeyError( - f"Objects of type {self.__class__.__name__} don't have an attribute called " - f"`{item}`." - ) from exc - - def __getstate__(self) -> dict[str, Union[str, object]]: - """ - Overrides :meth:`object.__getstate__` to customize the pickling process of objects of this - type. - The returned state does `not` contain the :class:`telegram.Bot` instance set with - :meth:`set_bot` (if any), as it can't be pickled. - - Returns: - state (dict[:obj:`str`, :obj:`object`]): The state of the object. - """ - out = self._get_attrs( - include_private=True, recursive=False, remove_bot=True, convert_default_vault=False - ) - # MappingProxyType is not pickable, so we convert it to a dict and revert in - # __setstate__ - out["api_kwargs"] = dict(self.api_kwargs) - return out - - def __setstate__(self, state: dict[str, object]) -> None: - """ - Overrides :meth:`object.__setstate__` to customize the unpickling process of objects of - this type. Modifies the object in-place. - - If any data was stored in the :attr:`api_kwargs` of the pickled object, this method checks - if the class now has dedicated attributes for those keys and moves the values from - :attr:`api_kwargs` to the dedicated attributes. - This can happen, if serialized data is loaded with a new version of this library, where - the new version was updated to account for updates of the Telegram Bot API. - - If on the contrary an attribute was removed from the class, the value is not discarded but - made available via :attr:`api_kwargs`. - - Args: - state (:obj:`dict`): The data to set as attributes of this object. - """ - self._unfreeze() - - # Make sure that we have a `_bot` attribute. This is necessary, since __getstate__ omits - # this as Bots are not pickable. - self._bot = None - - # get api_kwargs first because we may need to add entries to it (see try-except below) - api_kwargs = cast(dict[str, object], state.pop("api_kwargs", {})) - # get _frozen before the loop to avoid setting it to True in the loop - frozen = state.pop("_frozen", False) - - for key, val in state.items(): - try: - setattr(self, key, val) - except AttributeError: - # So an attribute was deprecated and removed from the class. Let's handle this: - # 1) Is the attribute now a property with no setter? Let's check that: - if isinstance(getattr(self.__class__, key, None), property): - # It is, so let's try to set the "private attribute" instead - try: - setattr(self, f"_{key}", val) - # If this fails as well, guess we've completely removed it. Let's add it to - # api_kwargs as fallback - except AttributeError: - api_kwargs[key] = val - - # 2) The attribute is a private attribute, i.e. it went through case 1) in the past - elif key.startswith("_"): - continue # skip adding this to api_kwargs, the attribute is lost forever. - api_kwargs[key] = val # add it to api_kwargs as fallback - - # For api_kwargs we first apply any kwargs that are already attributes of the object - # and then set the rest as MappingProxyType attribute. Converting to MappingProxyType - # is necessary, since __getstate__ converts it to a dict as MPT is not pickable. - self._apply_api_kwargs(api_kwargs) - self.api_kwargs = MappingProxyType(api_kwargs) - - # Apply freezing if necessary - # we .get(…) the setting for backwards compatibility with objects that were pickled - # before the freeze feature was introduced - if frozen: - self._freeze() - - def __deepcopy__(self: Tele_co, memodict: dict[int, object]) -> Tele_co: - """ - Customizes how :func:`copy.deepcopy` processes objects of this type. - The only difference to the default implementation is that the :class:`telegram.Bot` - instance set via :meth:`set_bot` (if any) is not copied, but shared between the original - and the copy, i.e.:: - - assert telegram_object.get_bot() is copy.deepcopy(telegram_object).get_bot() - - Args: - memodict (:obj:`dict`): A dictionary that maps objects to their copies. - - Returns: - :class:`telegram.TelegramObject`: The copied object. - """ - bot = self._bot # Save bot so we can set it after copying - self.set_bot(None) # set to None so it is not deepcopied - cls = self.__class__ - result = cls.__new__(cls) # create a new instance - memodict[id(self)] = result # save the id of the object in the dict - - result._frozen = False # unfreeze the new object for setting the attributes - - # now we set the attributes in the deepcopied object - for k in self._get_attrs_names(include_private=True): - if k == "_frozen": - # Setting the frozen status to True would prevent the attributes from being set - continue - if k == "api_kwargs": - # Need to copy api_kwargs manually, since it's a MappingProxyType is not - # pickable and deepcopy uses the pickle interface - setattr(result, k, MappingProxyType(deepcopy(dict(self.api_kwargs), memodict))) - continue - - try: - setattr(result, k, deepcopy(getattr(self, k), memodict)) - except AttributeError: - # Skip missing attributes. This can happen if the object was loaded from a pickle - # file that was created with an older version of the library, where the class - # did not have the attribute yet. - continue - - # Apply freezing if necessary - if self._frozen: - result._freeze() - - result.set_bot(bot) # Assign the bots back - self.set_bot(bot) - return result - - @staticmethod - def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]: - """Should be called by subclasses that override de_json to ensure that the input - is not altered. Whoever calls de_json might still want to use the original input - for something else. - """ - return None if data is None else data.copy() - - @classmethod - def _de_json( - cls: type[Tele_co], - data: Optional[JSONDict], - bot: Optional["Bot"], - api_kwargs: Optional[JSONDict] = None, - ) -> Optional[Tele_co]: - if data is None: - return None - - # try-except is significantly faster in case we already have a correct argument set - try: - obj = cls(**data, api_kwargs=api_kwargs) - except TypeError as exc: - if "__init__() got an unexpected keyword argument" not in str(exc): - raise - - if cls.__INIT_PARAMS_CHECK is not cls: - signature = inspect.signature(cls) - cls.__INIT_PARAMS = set(signature.parameters.keys()) - cls.__INIT_PARAMS_CHECK = cls - - api_kwargs = api_kwargs or {} - existing_kwargs: JSONDict = {} - for key, value in data.items(): - (existing_kwargs if key in cls.__INIT_PARAMS else api_kwargs)[key] = value - - obj = cls(api_kwargs=api_kwargs, **existing_kwargs) - - obj.set_bot(bot=bot) - return obj - - @classmethod - def de_json( - cls: type[Tele_co], data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional[Tele_co]: - """Converts JSON data to a Telegram object. - - Args: - data (dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`, optional): The bot associated with this object. Defaults to - :obj:`None`, in which case shortcut methods will not be available. - - .. versionchanged:: 21.4 - :paramref:`bot` is now optional and defaults to :obj:`None` - - Returns: - The Telegram object. - - """ - return cls._de_json(data=data, bot=bot) - - @classmethod - def de_list( - cls: type[Tele_co], data: Optional[list[JSONDict]], bot: Optional["Bot"] = None - ) -> tuple[Tele_co, ...]: - """Converts a list of JSON objects to a tuple of Telegram objects. - - .. versionchanged:: 20.0 - - * Returns a tuple instead of a list. - * Filters out any :obj:`None` values. - - Args: - data (list[dict[:obj:`str`, ...]]): The JSON data. - bot (:class:`telegram.Bot`, optional): The bot associated with these object. Defaults - to :obj:`None`, in which case shortcut methods will not be available. - - .. versionchanged:: 21.4 - :paramref:`bot` is now optional and defaults to :obj:`None` - - Returns: - A tuple of Telegram objects. - - """ - if not data: - return () - - return tuple(obj for obj in (cls.de_json(d, bot) for d in data) if obj is not None) - - @contextmanager - def _unfrozen(self: Tele_co) -> Iterator[Tele_co]: - """Context manager to temporarily unfreeze the object. For internal use only. - - Note: - with to._unfrozen() as other_to: - assert to is other_to - """ - self._unfreeze() - yield self - self._freeze() - - def _freeze(self) -> None: - self._frozen = True - - def _unfreeze(self) -> None: - self._frozen = False - - def _apply_api_kwargs(self, api_kwargs: JSONDict) -> None: - """Loops through the api kwargs and for every key that exists as attribute of the - object (and is None), it moves the value from `api_kwargs` to the attribute. - *Edits `api_kwargs` in place!* - - This method is currently only called in the unpickling process, i.e. not on "normal" init. - This is because - * automating this is tricky to get right: It should be called at the *end* of the __init__, - preferably only once at the end of the __init__ of the last child class. This could be - done via __init_subclass__, but it's hard to not destroy the signature of __init__ in the - process. - * calling it manually in every __init__ is tedious - * There probably is no use case for it anyway. If you manually initialize a TO subclass, - then you can pass everything as proper argument. - """ - # we convert to list to ensure that the list doesn't change length while we loop - for key in list(api_kwargs.keys()): - # property attributes are not settable, so we need to set the private attribute - if isinstance(getattr(self.__class__, key, None), property): - # if setattr fails, we'll just leave the value in api_kwargs: - with contextlib.suppress(AttributeError): - setattr(self, f"_{key}", api_kwargs.pop(key)) - elif getattr(self, key, True) is None: - setattr(self, key, api_kwargs.pop(key)) - - def _get_attrs_names(self, include_private: bool) -> Iterator[str]: - """ - Returns the names of the attributes of this object. This is used to determine which - attributes should be serialized when pickling the object. - - Args: - include_private (:obj:`bool`): Whether to include private attributes. - - Returns: - Iterator[:obj:`str`]: An iterator over the names of the attributes of this object. - """ - # We want to get all attributes for the class, using self.__slots__ only includes the - # attributes used by that class itself, and not its superclass(es). Hence, we get its MRO - # and then get their attributes. The `[:-1]` slice excludes the `object` class - all_slots = (s for c in self.__class__.__mro__[:-1] for s in c.__slots__) # type: ignore - # chain the class's slots with the user defined subclass __dict__ (class has no slots) - all_attrs = ( - chain(all_slots, self.__dict__.keys()) if hasattr(self, "__dict__") else all_slots - ) - - if include_private: - return all_attrs - return (attr for attr in all_attrs if not attr.startswith("_")) - - def _get_attrs( - self, - include_private: bool = False, - recursive: bool = False, - remove_bot: bool = False, - convert_default_vault: bool = True, - ) -> dict[str, Union[str, object]]: - """This method is used for obtaining the attributes of the object. - - Args: - include_private (:obj:`bool`): Whether the result should include private variables. - recursive (:obj:`bool`): If :obj:`True`, will convert any ``TelegramObjects`` (if - found) in the attributes to a dictionary. Else, preserves it as an object itself. - remove_bot (:obj:`bool`): Whether the bot should be included in the result. - convert_default_vault (:obj:`bool`): Whether :class:`telegram.DefaultValue` should be - converted to its true value. This is necessary when converting to a dictionary for - end users since DefaultValue is used in some classes that work with - `tg.ext.defaults` (like `LinkPreviewOptions`) - - Returns: - :obj:`dict`: A dict where the keys are attribute names and values are their values. - """ - data = {} - - for key in self._get_attrs_names(include_private=include_private): - value = ( - DefaultValue.get_value(getattr(self, key, None)) - if convert_default_vault - else getattr(self, key, None) - ) - - if value is not None: - if recursive and hasattr(value, "to_dict"): - data[key] = value.to_dict(recursive=True) - else: - data[key] = value - elif not recursive: - data[key] = value - - if recursive and data.get("from_user"): - data["from"] = data.pop("from_user", None) - if remove_bot: - data.pop("_bot", None) - return data - - def to_json(self) -> str: - """Gives a JSON representation of object. - - .. versionchanged:: 20.0 - Now includes all entries of :attr:`api_kwargs`. - - Returns: - :obj:`str` - """ - return json.dumps(self.to_dict()) - - def to_dict(self, recursive: bool = True) -> JSONDict: - """Gives representation of object as :obj:`dict`. - - .. versionchanged:: 20.0 - - * Now includes all entries of :attr:`api_kwargs`. - * Attributes whose values are empty sequences are no longer included. - - Args: - recursive (:obj:`bool`, optional): If :obj:`True`, will convert any TelegramObjects - (if found) in the attributes to a dictionary. Else, preserves it as an object - itself. Defaults to :obj:`True`. - - .. versionadded:: 20.0 - - Returns: - :obj:`dict` - """ - out = self._get_attrs(recursive=recursive) - - # Now we should convert TGObjects to dicts inside objects such as sequences, and convert - # datetimes to timestamps. This mostly eliminates the need for subclasses to override - # `to_dict` - pop_keys: set[str] = set() - for key, value in out.items(): - if isinstance(value, (tuple, list)): - if not value: - # not popping directly to avoid changing the dict size during iteration - pop_keys.add(key) - continue - - val = [] # empty list to append our converted values to - for item in value: - if hasattr(item, "to_dict"): - val.append(item.to_dict(recursive=recursive)) - # This branch is useful for e.g. tuple[tuple[PhotoSize|KeyboardButton]] - elif isinstance(item, (tuple, list)): - val.append( - [ - i.to_dict(recursive=recursive) if hasattr(i, "to_dict") else i - for i in item - ] - ) - else: # if it's not a TGObject, just append it. E.g. [TGObject, 2] - val.append(item) - out[key] = val - - elif isinstance(value, dtm.datetime): - out[key] = to_timestamp(value) - elif isinstance(value, dtm.timedelta): - out[key] = value.total_seconds() - - for key in pop_keys: - out.pop(key) - - # Effectively "unpack" api_kwargs into `out`: - out.update(out.pop("api_kwargs", {})) # type: ignore[call-overload] - return out - - def get_bot(self) -> "Bot": - """Returns the :class:`telegram.Bot` instance associated with this object. - - .. seealso:: :meth:`set_bot` - - .. versionadded: 20.0 - - Raises: - RuntimeError: If no :class:`telegram.Bot` instance was set for this object. - """ - if self._bot is None: - raise RuntimeError( - "This object has no bot associated with it. Shortcuts cannot be used." - ) - return self._bot - - def set_bot(self, bot: Optional["Bot"]) -> None: - """Sets the :class:`telegram.Bot` instance associated with this object. - - .. seealso:: :meth:`get_bot` - - .. versionadded: 20.0 - - Arguments: - bot (:class:`telegram.Bot` | :obj:`None`): The bot instance. - """ - self._bot = bot diff --git a/venv/lib/python3.11/site-packages/telegram/_update.py b/venv/lib/python3.11/site-packages/telegram/_update.py deleted file mode 100755 index 34f8fe2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_update.py +++ /dev/null @@ -1,803 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Update.""" - -from typing import TYPE_CHECKING, Final, Optional, Union - -from telegram import constants -from telegram._business import BusinessConnection, BusinessMessagesDeleted -from telegram._callbackquery import CallbackQuery -from telegram._chatboost import ChatBoostRemoved, ChatBoostUpdated -from telegram._chatjoinrequest import ChatJoinRequest -from telegram._chatmemberupdated import ChatMemberUpdated -from telegram._choseninlineresult import ChosenInlineResult -from telegram._inline.inlinequery import InlineQuery -from telegram._message import Message -from telegram._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated -from telegram._paidmedia import PaidMediaPurchased -from telegram._payment.precheckoutquery import PreCheckoutQuery -from telegram._payment.shippingquery import ShippingQuery -from telegram._poll import Poll, PollAnswer -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn - -if TYPE_CHECKING: - from telegram import Bot, Chat, User - - -class Update(TelegramObject): - """This object represents an incoming update. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`update_id` is equal. - - Note: - At most one of the optional parameters can be present in any given update. - - .. seealso:: :wiki:`Your First Bot ` - - Args: - update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a - certain positive number and increase sequentially. This ID becomes especially handy if - you're using Webhooks, since it allows you to ignore repeated updates or to restore the - correct update sequence, should they get out of order. If there are no new updates for - at least a week, then identifier of the next update will be chosen randomly instead of - sequentially. - message (:class:`telegram.Message`, optional): New incoming message of any kind - text, - photo, sticker, etc. - edited_message (:class:`telegram.Message`, optional): New version of a message that is - known to the bot and was edited. This update may at times be triggered by changes to - message fields that are either unavailable or not actively used by your bot. - channel_post (:class:`telegram.Message`, optional): New incoming channel post of any kind - - text, photo, sticker, etc. - edited_channel_post (:class:`telegram.Message`, optional): New version of a channel post - that is known to the bot and was edited. This update may at times be triggered by - changes to message fields that are either unavailable or not actively used by your bot. - inline_query (:class:`telegram.InlineQuery`, optional): New incoming inline query. - chosen_inline_result (:class:`telegram.ChosenInlineResult`, optional): The result of an - inline query that was chosen by a user and sent to their chat partner. - callback_query (:class:`telegram.CallbackQuery`, optional): New incoming callback query. - shipping_query (:class:`telegram.ShippingQuery`, optional): New incoming shipping query. - Only for invoices with flexible price. - pre_checkout_query (:class:`telegram.PreCheckoutQuery`, optional): New incoming - pre-checkout query. Contains full information about checkout. - poll (:class:`telegram.Poll`, optional): New poll state. Bots receive only updates about - manually stopped polls and polls, which are sent by the bot. - poll_answer (:class:`telegram.PollAnswer`, optional): A user changed their answer - in a non-anonymous poll. Bots receive new votes only in polls that were sent - by the bot itself. - my_chat_member (:class:`telegram.ChatMemberUpdated`, optional): The bot's chat member - status was updated in a chat. For private chats, this update is received only when the - bot is blocked or unblocked by the user. - - .. versionadded:: 13.4 - chat_member (:class:`telegram.ChatMemberUpdated`, optional): A chat member's status was - updated in a chat. The bot must be an administrator in the chat and must explicitly - specify :attr:`CHAT_MEMBER` in the list of - :paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these - updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, - :meth:`telegram.ext.Application.run_polling` and - :meth:`telegram.ext.Application.run_webhook`). - - .. versionadded:: 13.4 - chat_join_request (:class:`telegram.ChatJoinRequest`, optional): A request to join the - chat has been sent. The bot must have the - :attr:`telegram.ChatPermissions.can_invite_users` administrator right in the chat to - receive these updates. - - .. versionadded:: 13.8 - - chat_boost (:class:`telegram.ChatBoostUpdated`, optional): A chat boost was added or - changed. The bot must be an administrator in the chat to receive these updates. - - .. versionadded:: 20.8 - - removed_chat_boost (:class:`telegram.ChatBoostRemoved`, optional): A boost was removed from - a chat. The bot must be an administrator in the chat to receive these updates. - - .. versionadded:: 20.8 - - message_reaction (:class:`telegram.MessageReactionUpdated`, optional): A reaction to a - message was changed by a user. The bot must be an administrator in the chat and must - explicitly specify :attr:`MESSAGE_REACTION` in the list of - :paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these - updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, - :meth:`telegram.ext.Application.run_polling` and - :meth:`telegram.ext.Application.run_webhook`). The update isn't received for reactions - set by bots. - - .. versionadded:: 20.8 - - message_reaction_count (:class:`telegram.MessageReactionCountUpdated`, optional): Reactions - to a message with anonymous reactions were changed. The bot must be an administrator in - the chat and must explicitly specify :attr:`MESSAGE_REACTION_COUNT` in the list of - :paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these - updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, - :meth:`telegram.ext.Application.run_polling` and - :meth:`telegram.ext.Application.run_webhook`). The updates are grouped and can be sent - with delay up to a few minutes. - - .. versionadded:: 20.8 - - business_connection (:class:`telegram.BusinessConnection`, optional): The bot was connected - to or disconnected from a business account, or a user edited an existing connection - with the bot. - - .. versionadded:: 21.1 - - business_message (:class:`telegram.Message`, optional): New message from a connected - business account. - - .. versionadded:: 21.1 - - edited_business_message (:class:`telegram.Message`, optional): New version of a message - from a connected business account. - - .. versionadded:: 21.1 - - deleted_business_messages (:class:`telegram.BusinessMessagesDeleted`, optional): Messages - were deleted from a connected business account. - - .. versionadded:: 21.1 - - purchased_paid_media (:class:`telegram.PaidMediaPurchased`, optional): A user purchased - paid media with a non-empty payload sent by the bot in a non-channel chat. - - .. versionadded:: 21.6 - - - Attributes: - update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a - certain positive number and increase sequentially. This ID becomes especially handy if - you're using Webhooks, since it allows you to ignore repeated updates or to restore the - correct update sequence, should they get out of order. If there are no new updates for - at least a week, then identifier of the next update will be chosen randomly instead of - sequentially. - message (:class:`telegram.Message`): Optional. New incoming message of any kind - text, - photo, sticker, etc. - edited_message (:class:`telegram.Message`): Optional. New version of a message that is - known to the bot and was edited. This update may at times be triggered by changes to - message fields that are either unavailable or not actively used by your bot. - channel_post (:class:`telegram.Message`): Optional. New incoming channel post of any kind - - text, photo, sticker, etc. - edited_channel_post (:class:`telegram.Message`): Optional. New version of a channel post - that is known to the bot and was edited. This update may at times be triggered by - changes to message fields that are either unavailable or not actively used by your bot. - inline_query (:class:`telegram.InlineQuery`): Optional. New incoming inline query. - chosen_inline_result (:class:`telegram.ChosenInlineResult`): Optional. The result of an - inline query that was chosen by a user and sent to their chat partner. - callback_query (:class:`telegram.CallbackQuery`): Optional. New incoming callback query. - - Examples: - :any:`Arbitrary Callback Data Bot ` - shipping_query (:class:`telegram.ShippingQuery`): Optional. New incoming shipping query. - Only for invoices with flexible price. - pre_checkout_query (:class:`telegram.PreCheckoutQuery`): Optional. New incoming - pre-checkout query. Contains full information about checkout. - poll (:class:`telegram.Poll`): Optional. New poll state. Bots receive only updates about - manually stopped polls and polls, which are sent by the bot. - poll_answer (:class:`telegram.PollAnswer`): Optional. A user changed their answer - in a non-anonymous poll. Bots receive new votes only in polls that were sent - by the bot itself. - my_chat_member (:class:`telegram.ChatMemberUpdated`): Optional. The bot's chat member - status was updated in a chat. For private chats, this update is received only when the - bot is blocked or unblocked by the user. - - .. versionadded:: 13.4 - chat_member (:class:`telegram.ChatMemberUpdated`): Optional. A chat member's status was - updated in a chat. The bot must be an administrator in the chat and must explicitly - specify :attr:`CHAT_MEMBER` in the list of - :paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these - updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, - :meth:`telegram.ext.Application.run_polling` and - :meth:`telegram.ext.Application.run_webhook`). - - .. versionadded:: 13.4 - chat_join_request (:class:`telegram.ChatJoinRequest`): Optional. A request to join the - chat has been sent. The bot must have the - :attr:`telegram.ChatPermissions.can_invite_users` administrator right in the chat to - receive these updates. - - .. versionadded:: 13.8 - - chat_boost (:class:`telegram.ChatBoostUpdated`): Optional. A chat boost was added or - changed. The bot must be an administrator in the chat to receive these updates. - - .. versionadded:: 20.8 - - removed_chat_boost (:class:`telegram.ChatBoostRemoved`): Optional. A boost was removed from - a chat. The bot must be an administrator in the chat to receive these updates. - - .. versionadded:: 20.8 - - message_reaction (:class:`telegram.MessageReactionUpdated`): Optional. A reaction to a - message was changed by a user. The bot must be an administrator in the chat and must - explicitly specify :attr:`MESSAGE_REACTION` in the list of - :paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these - updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, - :meth:`telegram.ext.Application.run_polling` and - :meth:`telegram.ext.Application.run_webhook`). The update isn't received for reactions - set by bots. - - .. versionadded:: 20.8 - - message_reaction_count (:class:`telegram.MessageReactionCountUpdated`): Optional. Reactions - to a message with anonymous reactions were changed. The bot must be an administrator in - the chat and must explicitly specify :attr:`MESSAGE_REACTION_COUNT` in the list of - :paramref:`telegram.ext.Application.run_polling.allowed_updates` to receive these - updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, - :meth:`telegram.ext.Application.run_polling` and - :meth:`telegram.ext.Application.run_webhook`). The updates are grouped and can be sent - with delay up to a few minutes. - - .. versionadded:: 20.8 - - business_connection (:class:`telegram.BusinessConnection`): Optional. The bot was connected - to or disconnected from a business account, or a user edited an existing connection - with the bot. - - .. versionadded:: 21.1 - - business_message (:class:`telegram.Message`): Optional. New message from a connected - business account. - - .. versionadded:: 21.1 - - edited_business_message (:class:`telegram.Message`): Optional. New version of a message - from a connected business account. - - .. versionadded:: 21.1 - - deleted_business_messages (:class:`telegram.BusinessMessagesDeleted`): Optional. Messages - were deleted from a connected business account. - - .. versionadded:: 21.1 - - purchased_paid_media (:class:`telegram.PaidMediaPurchased`): Optional. A user purchased - paid media with a non-empty payload sent by the bot in a non-channel chat. - - .. versionadded:: 21.6 - """ - - __slots__ = ( - "_effective_chat", - "_effective_message", - "_effective_sender", - "_effective_user", - "business_connection", - "business_message", - "callback_query", - "channel_post", - "chat_boost", - "chat_join_request", - "chat_member", - "chosen_inline_result", - "deleted_business_messages", - "edited_business_message", - "edited_channel_post", - "edited_message", - "inline_query", - "message", - "message_reaction", - "message_reaction_count", - "my_chat_member", - "poll", - "poll_answer", - "pre_checkout_query", - "purchased_paid_media", - "removed_chat_boost", - "shipping_query", - "update_id", - ) - - MESSAGE: Final[str] = constants.UpdateType.MESSAGE - """:const:`telegram.constants.UpdateType.MESSAGE` - - .. versionadded:: 13.5""" - EDITED_MESSAGE: Final[str] = constants.UpdateType.EDITED_MESSAGE - """:const:`telegram.constants.UpdateType.EDITED_MESSAGE` - - .. versionadded:: 13.5""" - CHANNEL_POST: Final[str] = constants.UpdateType.CHANNEL_POST - """:const:`telegram.constants.UpdateType.CHANNEL_POST` - - .. versionadded:: 13.5""" - EDITED_CHANNEL_POST: Final[str] = constants.UpdateType.EDITED_CHANNEL_POST - """:const:`telegram.constants.UpdateType.EDITED_CHANNEL_POST` - - .. versionadded:: 13.5""" - INLINE_QUERY: Final[str] = constants.UpdateType.INLINE_QUERY - """:const:`telegram.constants.UpdateType.INLINE_QUERY` - - .. versionadded:: 13.5""" - CHOSEN_INLINE_RESULT: Final[str] = constants.UpdateType.CHOSEN_INLINE_RESULT - """:const:`telegram.constants.UpdateType.CHOSEN_INLINE_RESULT` - - .. versionadded:: 13.5""" - CALLBACK_QUERY: Final[str] = constants.UpdateType.CALLBACK_QUERY - """:const:`telegram.constants.UpdateType.CALLBACK_QUERY` - - .. versionadded:: 13.5""" - SHIPPING_QUERY: Final[str] = constants.UpdateType.SHIPPING_QUERY - """:const:`telegram.constants.UpdateType.SHIPPING_QUERY` - - .. versionadded:: 13.5""" - PRE_CHECKOUT_QUERY: Final[str] = constants.UpdateType.PRE_CHECKOUT_QUERY - """:const:`telegram.constants.UpdateType.PRE_CHECKOUT_QUERY` - - .. versionadded:: 13.5""" - POLL: Final[str] = constants.UpdateType.POLL - """:const:`telegram.constants.UpdateType.POLL` - - .. versionadded:: 13.5""" - POLL_ANSWER: Final[str] = constants.UpdateType.POLL_ANSWER - """:const:`telegram.constants.UpdateType.POLL_ANSWER` - - .. versionadded:: 13.5""" - MY_CHAT_MEMBER: Final[str] = constants.UpdateType.MY_CHAT_MEMBER - """:const:`telegram.constants.UpdateType.MY_CHAT_MEMBER` - - .. versionadded:: 13.5""" - CHAT_MEMBER: Final[str] = constants.UpdateType.CHAT_MEMBER - """:const:`telegram.constants.UpdateType.CHAT_MEMBER` - - .. versionadded:: 13.5""" - CHAT_JOIN_REQUEST: Final[str] = constants.UpdateType.CHAT_JOIN_REQUEST - """:const:`telegram.constants.UpdateType.CHAT_JOIN_REQUEST` - - .. versionadded:: 13.8""" - CHAT_BOOST: Final[str] = constants.UpdateType.CHAT_BOOST - """:const:`telegram.constants.UpdateType.CHAT_BOOST` - - .. versionadded:: 20.8""" - REMOVED_CHAT_BOOST: Final[str] = constants.UpdateType.REMOVED_CHAT_BOOST - """:const:`telegram.constants.UpdateType.REMOVED_CHAT_BOOST` - - .. versionadded:: 20.8""" - MESSAGE_REACTION: Final[str] = constants.UpdateType.MESSAGE_REACTION - """:const:`telegram.constants.UpdateType.MESSAGE_REACTION` - - .. versionadded:: 20.8""" - MESSAGE_REACTION_COUNT: Final[str] = constants.UpdateType.MESSAGE_REACTION_COUNT - """:const:`telegram.constants.UpdateType.MESSAGE_REACTION_COUNT` - - .. versionadded:: 20.8""" - BUSINESS_CONNECTION: Final[str] = constants.UpdateType.BUSINESS_CONNECTION - """:const:`telegram.constants.UpdateType.BUSINESS_CONNECTION` - - .. versionadded:: 21.1""" - BUSINESS_MESSAGE: Final[str] = constants.UpdateType.BUSINESS_MESSAGE - """:const:`telegram.constants.UpdateType.BUSINESS_MESSAGE` - - .. versionadded:: 21.1""" - EDITED_BUSINESS_MESSAGE: Final[str] = constants.UpdateType.EDITED_BUSINESS_MESSAGE - """:const:`telegram.constants.UpdateType.EDITED_BUSINESS_MESSAGE` - - .. versionadded:: 21.1""" - DELETED_BUSINESS_MESSAGES: Final[str] = constants.UpdateType.DELETED_BUSINESS_MESSAGES - """:const:`telegram.constants.UpdateType.DELETED_BUSINESS_MESSAGES` - - .. versionadded:: 21.1""" - - PURCHASED_PAID_MEDIA: Final[str] = constants.UpdateType.PURCHASED_PAID_MEDIA - """:const:`telegram.constants.UpdateType.PURCHASED_PAID_MEDIA` - - .. versionadded:: 21.6 - """ - - ALL_TYPES: Final[list[str]] = list(constants.UpdateType) - """list[:obj:`str`]: A list of all available update types. - - .. versionadded:: 13.5""" - - def __init__( - self, - update_id: int, - message: Optional[Message] = None, - edited_message: Optional[Message] = None, - channel_post: Optional[Message] = None, - edited_channel_post: Optional[Message] = None, - inline_query: Optional[InlineQuery] = None, - chosen_inline_result: Optional[ChosenInlineResult] = None, - callback_query: Optional[CallbackQuery] = None, - shipping_query: Optional[ShippingQuery] = None, - pre_checkout_query: Optional[PreCheckoutQuery] = None, - poll: Optional[Poll] = None, - poll_answer: Optional[PollAnswer] = None, - my_chat_member: Optional[ChatMemberUpdated] = None, - chat_member: Optional[ChatMemberUpdated] = None, - chat_join_request: Optional[ChatJoinRequest] = None, - chat_boost: Optional[ChatBoostUpdated] = None, - removed_chat_boost: Optional[ChatBoostRemoved] = None, - message_reaction: Optional[MessageReactionUpdated] = None, - message_reaction_count: Optional[MessageReactionCountUpdated] = None, - business_connection: Optional[BusinessConnection] = None, - business_message: Optional[Message] = None, - edited_business_message: Optional[Message] = None, - deleted_business_messages: Optional[BusinessMessagesDeleted] = None, - purchased_paid_media: Optional[PaidMediaPurchased] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.update_id: int = update_id - # Optionals - self.message: Optional[Message] = message - self.edited_message: Optional[Message] = edited_message - self.inline_query: Optional[InlineQuery] = inline_query - self.chosen_inline_result: Optional[ChosenInlineResult] = chosen_inline_result - self.callback_query: Optional[CallbackQuery] = callback_query - self.shipping_query: Optional[ShippingQuery] = shipping_query - self.pre_checkout_query: Optional[PreCheckoutQuery] = pre_checkout_query - self.channel_post: Optional[Message] = channel_post - self.edited_channel_post: Optional[Message] = edited_channel_post - self.poll: Optional[Poll] = poll - self.poll_answer: Optional[PollAnswer] = poll_answer - self.my_chat_member: Optional[ChatMemberUpdated] = my_chat_member - self.chat_member: Optional[ChatMemberUpdated] = chat_member - self.chat_join_request: Optional[ChatJoinRequest] = chat_join_request - self.chat_boost: Optional[ChatBoostUpdated] = chat_boost - self.removed_chat_boost: Optional[ChatBoostRemoved] = removed_chat_boost - self.message_reaction: Optional[MessageReactionUpdated] = message_reaction - self.message_reaction_count: Optional[MessageReactionCountUpdated] = message_reaction_count - self.business_connection: Optional[BusinessConnection] = business_connection - self.business_message: Optional[Message] = business_message - self.edited_business_message: Optional[Message] = edited_business_message - self.deleted_business_messages: Optional[BusinessMessagesDeleted] = ( - deleted_business_messages - ) - self.purchased_paid_media: Optional[PaidMediaPurchased] = purchased_paid_media - - self._effective_user: Optional[User] = None - self._effective_sender: Optional[Union[User, Chat]] = None - self._effective_chat: Optional[Chat] = None - self._effective_message: Optional[Message] = None - - self._id_attrs = (self.update_id,) - - self._freeze() - - @property - def effective_user(self) -> Optional["User"]: - """ - :class:`telegram.User`: The user that sent this update, no matter what kind of update this - is. If no user is associated with this update, this gives :obj:`None`. This is the case - if any of - - * :attr:`channel_post` - * :attr:`edited_channel_post` - * :attr:`poll` - * :attr:`chat_boost` - * :attr:`removed_chat_boost` - * :attr:`message_reaction_count` - * :attr:`deleted_business_messages` - - is present. - - .. versionchanged:: 21.1 - This property now also considers :attr:`business_connection`, :attr:`business_message` - and :attr:`edited_business_message`. - - .. versionchanged:: 21.6 - This property now also considers :attr:`purchased_paid_media`. - - Example: - * If :attr:`message` is present, this will give - :attr:`telegram.Message.from_user`. - * If :attr:`poll_answer` is present, this will give :attr:`telegram.PollAnswer.user`. - - """ - if self._effective_user: - return self._effective_user - - user = None - - if self.message: - user = self.message.from_user - - elif self.edited_message: - user = self.edited_message.from_user - - elif self.inline_query: - user = self.inline_query.from_user - - elif self.chosen_inline_result: - user = self.chosen_inline_result.from_user - - elif self.callback_query: - user = self.callback_query.from_user - - elif self.shipping_query: - user = self.shipping_query.from_user - - elif self.pre_checkout_query: - user = self.pre_checkout_query.from_user - - elif self.poll_answer: - user = self.poll_answer.user - - elif self.my_chat_member: - user = self.my_chat_member.from_user - - elif self.chat_member: - user = self.chat_member.from_user - - elif self.chat_join_request: - user = self.chat_join_request.from_user - - elif self.message_reaction: - user = self.message_reaction.user - - elif self.business_message: - user = self.business_message.from_user - - elif self.edited_business_message: - user = self.edited_business_message.from_user - - elif self.business_connection: - user = self.business_connection.user - - elif self.purchased_paid_media: - user = self.purchased_paid_media.from_user - - self._effective_user = user - return user - - @property - def effective_sender(self) -> Optional[Union["User", "Chat"]]: - """ - :class:`telegram.User` or :class:`telegram.Chat`: The user or chat that sent this update, - no matter what kind of update this is. - - Note: - * Depending on the type of update and the user's 'Remain anonymous' setting, this - could either be :class:`telegram.User`, :class:`telegram.Chat` or :obj:`None`. - - If no user whatsoever is associated with this update, this gives :obj:`None`. This - is the case if any of - - * :attr:`poll` - * :attr:`chat_boost` - * :attr:`removed_chat_boost` - * :attr:`message_reaction_count` - * :attr:`deleted_business_messages` - - is present. - - Example: - * If :attr:`message` is present, this will give either - :attr:`telegram.Message.from_user` or :attr:`telegram.Message.sender_chat`. - * If :attr:`poll_answer` is present, this will give either - :attr:`telegram.PollAnswer.user` or :attr:`telegram.PollAnswer.voter_chat`. - * If :attr:`channel_post` is present, this will give - :attr:`telegram.Message.sender_chat`. - - .. versionadded:: 21.1 - """ - if self._effective_sender: - return self._effective_sender - - sender: Optional[Union[User, Chat]] = None - - if message := ( - self.message - or self.edited_message - or self.channel_post - or self.edited_channel_post - or self.business_message - or self.edited_business_message - ): - sender = message.sender_chat - - elif self.poll_answer: - sender = self.poll_answer.voter_chat - - elif self.message_reaction: - sender = self.message_reaction.actor_chat - - if sender is None: - sender = self.effective_user - - self._effective_sender = sender - return sender - - @property - def effective_chat(self) -> Optional["Chat"]: - """ - :class:`telegram.Chat`: The chat that this update was sent in, no matter what kind of - update this is. - If no chat is associated with this update, this gives :obj:`None`. - This is the case, if :attr:`inline_query`, - :attr:`chosen_inline_result`, :attr:`callback_query` from inline messages, - :attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll`, - :attr:`poll_answer`, :attr:`business_connection`, or :attr:`purchased_paid_media` - is present. - - .. versionchanged:: 21.1 - This property now also considers :attr:`business_message`, - :attr:`edited_business_message`, and :attr:`deleted_business_messages`. - - Example: - If :attr:`message` is present, this will give :attr:`telegram.Message.chat`. - - """ - if self._effective_chat: - return self._effective_chat - - chat = None - - if self.message: - chat = self.message.chat - - elif self.edited_message: - chat = self.edited_message.chat - - elif self.callback_query and self.callback_query.message: - chat = self.callback_query.message.chat - - elif self.channel_post: - chat = self.channel_post.chat - - elif self.edited_channel_post: - chat = self.edited_channel_post.chat - - elif self.my_chat_member: - chat = self.my_chat_member.chat - - elif self.chat_member: - chat = self.chat_member.chat - - elif self.chat_join_request: - chat = self.chat_join_request.chat - - elif self.chat_boost: - chat = self.chat_boost.chat - - elif self.removed_chat_boost: - chat = self.removed_chat_boost.chat - - elif self.message_reaction: - chat = self.message_reaction.chat - - elif self.message_reaction_count: - chat = self.message_reaction_count.chat - - elif self.business_message: - chat = self.business_message.chat - - elif self.edited_business_message: - chat = self.edited_business_message.chat - - elif self.deleted_business_messages: - chat = self.deleted_business_messages.chat - - self._effective_chat = chat - return chat - - @property - def effective_message(self) -> Optional[Message]: - """ - :class:`telegram.Message`: The message included in this update, no matter what kind of - update this is. More precisely, this will be the message contained in :attr:`message`, - :attr:`edited_message`, :attr:`channel_post`, :attr:`edited_channel_post` or - :attr:`callback_query` (i.e. :attr:`telegram.CallbackQuery.message`) or :obj:`None`, if - none of those are present. - - .. versionchanged:: 21.1 - This property now also considers :attr:`business_message`, and - :attr:`edited_business_message`. - - Tip: - This property will only ever return objects of type :class:`telegram.Message` or - :obj:`None`, never :class:`telegram.MaybeInaccessibleMessage` or - :class:`telegram.InaccessibleMessage`. - Currently, this is only relevant for :attr:`callback_query`, as - :attr:`telegram.CallbackQuery.message` is the only attribute considered by this - property that can be an object of these types. - """ - if self._effective_message: - return self._effective_message - - message: Optional[Message] = None - - if self.message: - message = self.message - - elif self.edited_message: - message = self.edited_message - - elif self.callback_query: - if ( - isinstance(cbq_message := self.callback_query.message, Message) - or cbq_message is None - ): - message = cbq_message - else: - warn( - ( - "`update.callback_query` is not `None`, but of type " - f"`{cbq_message.__class__.__name__}`. This is not considered by " - "`Update.effective_message`. Please manually access this attribute " - "if necessary." - ), - stacklevel=2, - ) - - elif self.channel_post: - message = self.channel_post - - elif self.edited_channel_post: - message = self.edited_channel_post - - elif self.business_message: - message = self.business_message - - elif self.edited_business_message: - message = self.edited_business_message - - self._effective_message = message - return message - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Update"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["message"] = Message.de_json(data.get("message"), bot) - data["edited_message"] = Message.de_json(data.get("edited_message"), bot) - data["inline_query"] = InlineQuery.de_json(data.get("inline_query"), bot) - data["chosen_inline_result"] = ChosenInlineResult.de_json( - data.get("chosen_inline_result"), bot - ) - data["callback_query"] = CallbackQuery.de_json(data.get("callback_query"), bot) - data["shipping_query"] = ShippingQuery.de_json(data.get("shipping_query"), bot) - data["pre_checkout_query"] = PreCheckoutQuery.de_json(data.get("pre_checkout_query"), bot) - data["channel_post"] = Message.de_json(data.get("channel_post"), bot) - data["edited_channel_post"] = Message.de_json(data.get("edited_channel_post"), bot) - data["poll"] = Poll.de_json(data.get("poll"), bot) - data["poll_answer"] = PollAnswer.de_json(data.get("poll_answer"), bot) - data["my_chat_member"] = ChatMemberUpdated.de_json(data.get("my_chat_member"), bot) - data["chat_member"] = ChatMemberUpdated.de_json(data.get("chat_member"), bot) - data["chat_join_request"] = ChatJoinRequest.de_json(data.get("chat_join_request"), bot) - data["chat_boost"] = ChatBoostUpdated.de_json(data.get("chat_boost"), bot) - data["removed_chat_boost"] = ChatBoostRemoved.de_json(data.get("removed_chat_boost"), bot) - data["message_reaction"] = MessageReactionUpdated.de_json( - data.get("message_reaction"), bot - ) - data["message_reaction_count"] = MessageReactionCountUpdated.de_json( - data.get("message_reaction_count"), bot - ) - data["business_connection"] = BusinessConnection.de_json( - data.get("business_connection"), bot - ) - data["business_message"] = Message.de_json(data.get("business_message"), bot) - data["edited_business_message"] = Message.de_json(data.get("edited_business_message"), bot) - data["deleted_business_messages"] = BusinessMessagesDeleted.de_json( - data.get("deleted_business_messages"), bot - ) - data["purchased_paid_media"] = PaidMediaPurchased.de_json( - data.get("purchased_paid_media"), bot - ) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_user.py b/venv/lib/python3.11/site-packages/telegram/_user.py deleted file mode 100755 index 0e9ce1f..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_user.py +++ /dev/null @@ -1,2336 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=redefined-builtin -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram User.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional, Union - -from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton -from telegram._menubutton import MenuButton -from telegram._telegramobject import TelegramObject -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup -from telegram.helpers import mention_html as helpers_mention_html -from telegram.helpers import mention_markdown as helpers_mention_markdown - -if TYPE_CHECKING: - from telegram import ( - Animation, - Audio, - Contact, - Document, - Gift, - InlineKeyboardMarkup, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - InputPollOption, - LabeledPrice, - LinkPreviewOptions, - Location, - Message, - MessageEntity, - MessageId, - PhotoSize, - ReplyParameters, - Sticker, - UserChatBoosts, - UserProfilePhotos, - Venue, - Video, - VideoNote, - Voice, - ) - - -class User(TelegramObject): - """This object represents a Telegram user or bot. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - .. versionchanged:: 20.0 - The following are now keyword-only arguments in Bot methods: - ``location``, ``filename``, ``venue``, ``contact``, - ``{read, write, connect, pool}_timeout`` ``api_kwargs``. Use a named argument for those, - and notice that some positional arguments changed position as a result. - - Args: - id (:obj:`int`): Unique identifier for this user or bot. - is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. - first_name (:obj:`str`): User's or bot's first name. - last_name (:obj:`str`, optional): User's or bot's last name. - username (:obj:`str`, optional): User's or bot's username. - language_code (:obj:`str`, optional): IETF language tag of the user's language. - can_join_groups (:obj:`str`, optional): :obj:`True`, if the bot can be invited to groups. - Returned only in :meth:`telegram.Bot.get_me`. - can_read_all_group_messages (:obj:`str`, optional): :obj:`True`, if privacy mode is - disabled for the bot. Returned only in :meth:`telegram.Bot.get_me`. - supports_inline_queries (:obj:`str`, optional): :obj:`True`, if the bot supports inline - queries. Returned only in :meth:`telegram.Bot.get_me`. - - is_premium (:obj:`bool`, optional): :obj:`True`, if this user is a Telegram Premium user. - - .. versionadded:: 20.0 - added_to_attachment_menu (:obj:`bool`, optional): :obj:`True`, if this user added - the bot to the attachment menu. - - .. versionadded:: 20.0 - can_connect_to_business (:obj:`bool`, optional): :obj:`True`, if the bot can be connected - to a Telegram Business account to receive its messages. Returned only in - :meth:`telegram.Bot.get_me`. - - .. versionadded:: 21.1 - has_main_web_app (:obj:`bool`, optional): :obj:`True`, if the bot has the main Web App. - Returned only in :meth:`telegram.Bot.get_me`. - - .. versionadded:: 21.5 - - Attributes: - id (:obj:`int`): Unique identifier for this user or bot. - is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. - first_name (:obj:`str`): User's or bot's first name. - last_name (:obj:`str`): Optional. User's or bot's last name. - username (:obj:`str`): Optional. User's or bot's username. - language_code (:obj:`str`): Optional. IETF language tag of the user's language. - can_join_groups (:obj:`str`): Optional. :obj:`True`, if the bot can be invited to groups. - Returned only in :attr:`telegram.Bot.get_me` requests. - can_read_all_group_messages (:obj:`str`): Optional. :obj:`True`, if privacy mode is - disabled for the bot. Returned only in :attr:`telegram.Bot.get_me` requests. - supports_inline_queries (:obj:`str`): Optional. :obj:`True`, if the bot supports inline - queries. Returned only in :attr:`telegram.Bot.get_me` requests. - is_premium (:obj:`bool`): Optional. :obj:`True`, if this user is a Telegram - Premium user. - - .. versionadded:: 20.0 - added_to_attachment_menu (:obj:`bool`): Optional. :obj:`True`, if this user added - the bot to the attachment menu. - - .. versionadded:: 20.0 - can_connect_to_business (:obj:`bool`): Optional. :obj:`True`, if the bot can be connected - to a Telegram Business account to receive its messages. Returned only in - :meth:`telegram.Bot.get_me`. - - .. versionadded:: 21.1 - has_main_web_app (:obj:`bool`) Optional. :obj:`True`, if the bot has the main Web App. - Returned only in :meth:`telegram.Bot.get_me`. - - .. versionadded:: 21.5 - - .. |user_chat_id_note| replace:: This shortcuts build on the assumption that :attr:`User.id` - coincides with the :attr:`Chat.id` of the private chat with the user. This has been the - case so far, but Telegram does not guarantee that this stays this way. - """ - - __slots__ = ( - "added_to_attachment_menu", - "can_connect_to_business", - "can_join_groups", - "can_read_all_group_messages", - "first_name", - "has_main_web_app", - "id", - "is_bot", - "is_premium", - "language_code", - "last_name", - "supports_inline_queries", - "username", - ) - - def __init__( - self, - id: int, - first_name: str, - is_bot: bool, - last_name: Optional[str] = None, - username: Optional[str] = None, - language_code: Optional[str] = None, - can_join_groups: Optional[bool] = None, - can_read_all_group_messages: Optional[bool] = None, - supports_inline_queries: Optional[bool] = None, - is_premium: Optional[bool] = None, - added_to_attachment_menu: Optional[bool] = None, - can_connect_to_business: Optional[bool] = None, - has_main_web_app: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.id: int = id - self.first_name: str = first_name - self.is_bot: bool = is_bot - # Optionals - self.last_name: Optional[str] = last_name - self.username: Optional[str] = username - self.language_code: Optional[str] = language_code - self.can_join_groups: Optional[bool] = can_join_groups - self.can_read_all_group_messages: Optional[bool] = can_read_all_group_messages - self.supports_inline_queries: Optional[bool] = supports_inline_queries - self.is_premium: Optional[bool] = is_premium - self.added_to_attachment_menu: Optional[bool] = added_to_attachment_menu - self.can_connect_to_business: Optional[bool] = can_connect_to_business - self.has_main_web_app: Optional[bool] = has_main_web_app - - self._id_attrs = (self.id,) - - self._freeze() - - @property - def name(self) -> str: - """:obj:`str`: Convenience property. If available, returns the user's :attr:`username` - prefixed with "@". If :attr:`username` is not available, returns :attr:`full_name`. - """ - if self.username: - return f"@{self.username}" - return self.full_name - - @property - def full_name(self) -> str: - """:obj:`str`: Convenience property. The user's :attr:`first_name`, followed by (if - available) :attr:`last_name`. - """ - if self.last_name: - return f"{self.first_name} {self.last_name}" - return self.first_name - - @property - def link(self) -> Optional[str]: - """:obj:`str`: Convenience property. If :attr:`username` is available, returns a t.me link - of the user. - """ - if self.username: - return f"https://t.me/{self.username}" - return None - - async def get_profile_photos( - self, - offset: Optional[int] = None, - limit: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> Optional["UserProfilePhotos"]: - """Shortcut for:: - - await bot.get_user_profile_photos(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_user_profile_photos`. - - """ - return await self.get_bot().get_user_profile_photos( - user_id=self.id, - offset=offset, - limit=limit, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - def mention_markdown(self, name: Optional[str] = None) -> str: - """ - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`mention_markdown_v2` - instead. - - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as markdown (version 1). - - """ - if name: - return helpers_mention_markdown(self.id, name) - return helpers_mention_markdown(self.id, self.full_name) - - def mention_markdown_v2(self, name: Optional[str] = None) -> str: - """ - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as markdown (version 2). - - """ - if name: - return helpers_mention_markdown(self.id, name, version=2) - return helpers_mention_markdown(self.id, self.full_name, version=2) - - def mention_html(self, name: Optional[str] = None) -> str: - """ - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as HTML. - - """ - if name: - return helpers_mention_html(self.id, name) - return helpers_mention_html(self.id, self.full_name) - - def mention_button(self, name: Optional[str] = None) -> InlineKeyboardButton: - """Shortcut for:: - - InlineKeyboardButton(text=name, url=f"tg://user?id={update.effective_user.id}") - - .. versionadded:: 13.9 - - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :class:`telegram.InlineKeyboardButton`: InlineButton with url set to the user mention - """ - return InlineKeyboardButton(text=name or self.full_name, url=f"tg://user?id={self.id}") - - async def pin_message( - self, - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.pin_chat_message(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. - - Note: - |user_chat_id_note| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().pin_chat_message( - chat_id=self.id, - message_id=message_id, - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - business_connection_id=business_connection_id, - api_kwargs=api_kwargs, - ) - - async def unpin_message( - self, - message_id: Optional[int] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.unpin_chat_message(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. - - Note: - |user_chat_id_note| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().unpin_chat_message( - chat_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - message_id=message_id, - business_connection_id=business_connection_id, - ) - - async def unpin_all_messages( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.unpin_all_chat_messages(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_all_chat_messages`. - - Note: - |user_chat_id_note| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().unpin_all_chat_messages( - chat_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def send_message( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - disable_web_page_preview: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_message( - chat_id=self.id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - link_preview_options=link_preview_options, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - entities=entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def delete_message( - self, - message_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.delete_message(update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.delete_message`. - - .. versionadded:: 20.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().delete_message( - chat_id=self.id, - message_id=message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def delete_messages( - self, - message_ids: Sequence[int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.delete_messages(update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.delete_messages`. - - .. versionadded:: 20.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().delete_messages( - chat_id=self.id, - message_ids=message_ids, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def send_photo( - self, - photo: Union[FileInput, "PhotoSize"], - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_photo(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_photo( - chat_id=self.id, - photo=photo, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - has_spoiler=has_spoiler, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_media_group( - self, - media: Sequence[ - Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] - ], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - ) -> tuple["Message", ...]: - """Shortcut for:: - - await bot.send_media_group(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. - - Note: - |user_chat_id_note| - - Returns: - tuple[:class:`telegram.Message`:] On success, a tuple of :class:`~telegram.Message` - instances that were sent is returned. - - """ - return await self.get_bot().send_media_group( - chat_id=self.id, - media=media, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_audio( - self, - audio: Union[FileInput, "Audio"], - duration: Optional[int] = None, - performer: Optional[str] = None, - title: Optional[str] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_audio(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_audio( - chat_id=self.id, - audio=audio, - duration=duration, - performer=performer, - title=title, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - thumbnail=thumbnail, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_chat_action( - self, - action: str, - message_thread_id: Optional[int] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.send_chat_action(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. - - Note: - |user_chat_id_note| - - Returns: - :obj:`True`: On success. - - """ - return await self.get_bot().send_chat_action( - chat_id=self.id, - action=action, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - business_connection_id=business_connection_id, - ) - - send_action = send_chat_action - """Alias for :attr:`send_chat_action`""" - - async def send_contact( - self, - phone_number: Optional[str] = None, - first_name: Optional[str] = None, - last_name: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - vcard: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - contact: Optional["Contact"] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_contact(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_contact( - chat_id=self.id, - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - contact=contact, - vcard=vcard, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_dice( - self, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - emoji: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_dice(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_dice( - chat_id=self.id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - emoji=emoji, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_document( - self, - document: Union[FileInput, "Document"], - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_content_type_detection: Optional[bool] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_document(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_document( - chat_id=self.id, - document=document, - filename=filename, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - parse_mode=parse_mode, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - disable_content_type_detection=disable_content_type_detection, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_game( - self, - game_short_name: str, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_game(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_game( - chat_id=self.id, - game_short_name=game_short_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_invoice( - self, - title: str, - description: str, - payload: str, - provider_token: Optional[str], - currency: str, - prices: Sequence["LabeledPrice"], - start_parameter: Optional[str] = None, - photo_url: Optional[str] = None, - photo_size: Optional[int] = None, - photo_width: Optional[int] = None, - photo_height: Optional[int] = None, - need_name: Optional[bool] = None, - need_phone_number: Optional[bool] = None, - need_email: Optional[bool] = None, - need_shipping_address: Optional[bool] = None, - is_flexible: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - provider_data: Optional[Union[str, object]] = None, - send_phone_number_to_provider: Optional[bool] = None, - send_email_to_provider: Optional[bool] = None, - max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[Sequence[int]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_invoice(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. - - Warning: - As of API 5.2 :paramref:`start_parameter ` - is an optional argument and therefore the - order of the arguments had to be changed. Use keyword arguments to make sure that the - arguments are passed correctly. - - Note: - |user_chat_id_note| - - .. versionchanged:: 13.5 - As of Bot API 5.2, the parameter - :paramref:`start_parameter ` is optional. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_invoice( - chat_id=self.id, - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - start_parameter=start_parameter, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - is_flexible=is_flexible, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - provider_data=provider_data, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - protect_content=protect_content, - message_thread_id=message_thread_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_location( - self, - latitude: Optional[float] = None, - longitude: Optional[float] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - live_period: Optional[int] = None, - horizontal_accuracy: Optional[float] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - location: Optional["Location"] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_location(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_location( - chat_id=self.id, - latitude=latitude, - longitude=longitude, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - location=location, - live_period=live_period, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_animation( - self, - animation: Union[FileInput, "Animation"], - duration: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_animation(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_animation( - chat_id=self.id, - animation=animation, - duration=duration, - width=width, - height=height, - caption=caption, - parse_mode=parse_mode, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - has_spoiler=has_spoiler, - thumbnail=thumbnail, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_sticker( - self, - sticker: Union[FileInput, "Sticker"], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - emoji: Optional[str] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_sticker(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_sticker( - chat_id=self.id, - sticker=sticker, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - emoji=emoji, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_video( - self, - video: Union[FileInput, "Video"], - duration: Optional[int] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - width: Optional[int] = None, - height: Optional[int] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - supports_streaming: Optional[bool] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_video(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_video( - chat_id=self.id, - video=video, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - width=width, - height=height, - parse_mode=parse_mode, - supports_streaming=supports_streaming, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - has_spoiler=has_spoiler, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_venue( - self, - latitude: Optional[float] = None, - longitude: Optional[float] = None, - title: Optional[str] = None, - address: Optional[str] = None, - foursquare_id: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - foursquare_type: Optional[str] = None, - google_place_id: Optional[str] = None, - google_place_type: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - venue: Optional["Venue"] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_venue(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_venue( - chat_id=self.id, - latitude=latitude, - longitude=longitude, - title=title, - address=address, - foursquare_id=foursquare_id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - venue=venue, - foursquare_type=foursquare_type, - api_kwargs=api_kwargs, - google_place_id=google_place_id, - google_place_type=google_place_type, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_video_note( - self, - video_note: Union[FileInput, "VideoNote"], - duration: Optional[int] = None, - length: Optional[int] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_video_note(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_video_note( - chat_id=self.id, - video_note=video_note, - duration=duration, - length=length, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - thumbnail=thumbnail, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_voice( - self, - voice: Union[FileInput, "Voice"], - duration: Optional[int] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_voice(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_voice( - chat_id=self.id, - voice=voice, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_poll( - self, - question: str, - options: Sequence[Union[str, "InputPollOption"]], - is_anonymous: Optional[bool] = None, - type: Optional[str] = None, - allows_multiple_answers: Optional[bool] = None, - correct_option_id: Optional[CorrectOptionID] = None, - is_closed: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - explanation: Optional[str] = None, - explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, - open_period: Optional[int] = None, - close_date: Optional[Union[int, dtm.datetime]] = None, - explanation_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - question_parse_mode: ODVInput[str] = DEFAULT_NONE, - question_entities: Optional[Sequence["MessageEntity"]] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.send_poll(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().send_poll( - chat_id=self.id, - question=question, - options=options, - is_anonymous=is_anonymous, - type=type, # pylint=pylint, - allows_multiple_answers=allows_multiple_answers, - correct_option_id=correct_option_id, - is_closed=is_closed, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - explanation=explanation, - explanation_parse_mode=explanation_parse_mode, - open_period=open_period, - close_date=close_date, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - explanation_entities=explanation_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - question_parse_mode=question_parse_mode, - question_entities=question_entities, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_gift( - self, - gift_id: Union[str, "Gift"], - text: Optional[str] = None, - text_parse_mode: ODVInput[str] = DEFAULT_NONE, - text_entities: Optional[Sequence["MessageEntity"]] = None, - pay_for_upgrade: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.send_gift( user_id=update.effective_user.id, *args, **kwargs ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_gift`. - - .. versionadded:: 21.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().send_gift( - user_id=self.id, - gift_id=gift_id, - text=text, - text_parse_mode=text_parse_mode, - text_entities=text_entities, - pay_for_upgrade=pay_for_upgrade, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def send_copy( - self, - from_chat_id: Union[str, int], - message_id: int, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - show_caption_above_media: Optional[bool] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "MessageId": - """Shortcut for:: - - await bot.copy_message(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().copy_message( - chat_id=self.id, - from_chat_id=from_chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - protect_content=protect_content, - message_thread_id=message_thread_id, - show_caption_above_media=show_caption_above_media, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def copy_message( - self, - chat_id: Union[int, str], - message_id: int, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - show_caption_above_media: Optional[bool] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "MessageId": - """Shortcut for:: - - await bot.copy_message(from_chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Note: - |user_chat_id_note| - - Returns: - :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. - - """ - return await self.get_bot().copy_message( - from_chat_id=self.id, - chat_id=chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_parameters=reply_parameters, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - protect_content=protect_content, - message_thread_id=message_thread_id, - show_caption_above_media=show_caption_above_media, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_copies( - self, - from_chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - remove_caption: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> tuple["MessageId", ...]: - """Shortcut for:: - - await bot.copy_messages(chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_messages`. - - .. seealso:: :meth:`copy_message`, :meth:`send_copy`, :meth:`copy_messages`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of the sent messages is returned. - - """ - return await self.get_bot().copy_messages( - chat_id=self.id, - from_chat_id=from_chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - remove_caption=remove_caption, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def copy_messages( - self, - chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - remove_caption: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> tuple["MessageId", ...]: - """Shortcut for:: - - await bot.copy_messages(from_chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_messages`. - - .. seealso:: :meth:`copy_message`, :meth:`send_copy`, :meth:`send_copies`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of the sent messages is returned. - - """ - return await self.get_bot().copy_messages( - from_chat_id=self.id, - chat_id=chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - remove_caption=remove_caption, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def forward_from( - self, - from_chat_id: Union[str, int], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.forward_message(chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`. - - .. seealso:: :meth:`forward_to`, :meth:`forward_messages_from`, :meth:`forward_messages_to` - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().forward_message( - chat_id=self.id, - from_chat_id=from_chat_id, - message_id=message_id, - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - protect_content=protect_content, - message_thread_id=message_thread_id, - ) - - async def forward_to( - self, - chat_id: Union[int, str], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "Message": - """Shortcut for:: - - await bot.forward_message(from_chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`. - - .. seealso:: :meth:`forward_from`, :meth:`forward_messages_from`, - :meth:`forward_messages_to` - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return await self.get_bot().forward_message( - from_chat_id=self.id, - chat_id=chat_id, - message_id=message_id, - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - protect_content=protect_content, - message_thread_id=message_thread_id, - ) - - async def forward_messages_from( - self, - from_chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> tuple["MessageId", ...]: - """Shortcut for:: - - await bot.forward_messages(chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_messages`. - - .. seealso:: :meth:`forward_to`, :meth:`forward_from`, :meth:`forward_messages_to`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of sent messages is returned. - - """ - return await self.get_bot().forward_messages( - chat_id=self.id, - from_chat_id=from_chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def forward_messages_to( - self, - chat_id: Union[int, str], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> tuple["MessageId", ...]: - """Shortcut for:: - - await bot.forward_messages(from_chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_messages`. - - .. seealso:: :meth:`forward_from`, :meth:`forward_to`, :meth:`forward_messages_from`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of sent messages is returned. - - """ - return await self.get_bot().forward_messages( - from_chat_id=self.id, - chat_id=chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def approve_join_request( - self, - chat_id: Union[int, str], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.approve_chat_join_request(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.approve_chat_join_request`. - - Note: - |user_chat_id_note| - - .. versionadded:: 13.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().approve_chat_join_request( - user_id=self.id, - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def decline_join_request( - self, - chat_id: Union[int, str], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.decline_chat_join_request(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.decline_chat_join_request`. - - Note: - |user_chat_id_note| - - .. versionadded:: 13.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().decline_chat_join_request( - user_id=self.id, - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def set_menu_button( - self, - menu_button: Optional[MenuButton] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.set_chat_menu_button(chat_id=update.effective_user.id, *argss, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_menu_button`. - - .. seealso:: :meth:`get_menu_button` - - Note: - |user_chat_id_note| - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().set_chat_menu_button( - chat_id=self.id, - menu_button=menu_button, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def get_menu_button( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> MenuButton: - """Shortcut for:: - - await bot.get_chat_menu_button(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_chat_menu_button`. - - .. seealso:: :meth:`set_menu_button` - - Note: - |user_chat_id_note| - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.MenuButton`: On success, the current menu button is returned. - """ - return await self.get_bot().get_chat_menu_button( - chat_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def get_chat_boosts( - self, - chat_id: Union[int, str], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> "UserChatBoosts": - """Shortcut for:: - - await bot.get_user_chat_boosts(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_user_chat_boosts`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.UserChatBoosts`: On success, returns the boosts applied by the user. - """ - return await self.get_bot().get_user_chat_boosts( - chat_id=chat_id, - user_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def refund_star_payment( - self, - telegram_payment_charge_id: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.refund_star_payment(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.refund_star_payment`. - - .. versionadded:: 21.3 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().refund_star_payment( - user_id=self.id, - telegram_payment_charge_id=telegram_payment_charge_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def verify( - self, - custom_description: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.verify_user(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.verify_user`. - - .. versionadded:: 21.10 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().verify_user( - user_id=self.id, - custom_description=custom_description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def remove_verification( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> bool: - """Shortcut for:: - - await bot.remove_user_verification(user_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.remove_user_verification`. - - .. versionadded:: 21.10 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().remove_user_verification( - user_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_userprofilephotos.py b/venv/lib/python3.11/site-packages/telegram/_userprofilephotos.py deleted file mode 100755 index cc812d5..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_userprofilephotos.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram UserProfilePhotos.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._files.photosize import PhotoSize -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class UserProfilePhotos(TelegramObject): - """This object represents a user's profile pictures. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`total_count` and :attr:`photos` are equal. - - Args: - total_count (:obj:`int`): Total number of profile pictures the target user has. - photos (Sequence[Sequence[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up - to 4 sizes each). - - .. versionchanged:: 20.0 - |sequenceclassargs| - - Attributes: - total_count (:obj:`int`): Total number of profile pictures. - photos (tuple[tuple[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up to 4 - sizes each). - - .. versionchanged:: 20.0 - |tupleclassattrs| - - """ - - __slots__ = ("photos", "total_count") - - def __init__( - self, - total_count: int, - photos: Sequence[Sequence[PhotoSize]], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.total_count: int = total_count - self.photos: tuple[tuple[PhotoSize, ...], ...] = tuple(tuple(sizes) for sizes in photos) - - self._id_attrs = (self.total_count, self.photos) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["UserProfilePhotos"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["photos"] = [PhotoSize.de_list(photo, bot) for photo in data["photos"]] - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__init__.py b/venv/lib/python3.11/site-packages/telegram/_utils/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 039b3be817df240b3fd77510ac65f25106e7720c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192 zcmZ3^%ge<81UIM5$^y}kK?DpiLK&agfQ;!3DGb33nv8xc8H$*I{LdiCU%~nr`MIh3 zxrs%|`TAb@>G{U`i3J7vWvO{(`Z<|N`URCG8Tom}dWMGj#hE3kx&?{J*@@|?#rh?w zIjQMIiMjgmr6rj;#rpB_nR%Hd@$q^EmA^P_a`RJ4b5iY!Sb=tcTv5yqBt9@RGBSQ( KfDuK^KrsMYH!$%4 diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/argumentparsing.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/argumentparsing.cpython-311.pyc deleted file mode 100755 index 2aa42270d9dd3aef54aec8739b98f23b18106b88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2070 zcmZ`)%WoS+7@xJ*uT31c;i0r@$pC3p7hx-^kdQ%@s+MSlmYxwGq{5&e7alJEzHY-pRXqTXzfXf|7No z=$6_gwJtbix6-a?D2G^q7QfLD`T>4}(Kcv_=`6>L6T>aEzoKO}#td3n&h76l>(scb zx5w!i=vDXk={T#f(gC?VDlZpl74#p^pQ?h3)k);l0RZUMTRg&#~nYA(+6#qu6EPicdwuFqR1S;BL#n zFfN02b>Cmc;Q_CNGi=KvI&jcsI1;dwd)yQt2aEe?1MymT;Cus(a>>)E2H56q{W=dgDL}BF#e_u` zs4T6I2@a#cVTQ`>67PutOcE-H2A^yB-J7k>Fu6{>g%_Xzdp0sEFo0RAyrW`2U}K=Z zAYF70sR9aXjAwkx!oWZx;$h|nA%HEl8p`hXvcv_oQP((hB@!}y{HWbr@m7Q z*J0*5>zV<0HG={C$>R=iVJMjcWQ3KITG`kGd>%Fw;Kw(#QP8P23i^lI2D)=Bl$zPt zKtJY3?|h(bNMh)>K3?KbC+Kd%{Rp~s9eUIxT|Wv<${N$QKUVIWJApyXcPrz#kz7zN+d=gB$ z9t8YJIB3d?Z@~oMkE1e9kzO$3nHSaj;lxy$)2b)_&gW~!KM1B2X(lzxcN{kO>^4Z(;u6)Q81@6G zG}l4k1-Wx-NaKbnE0ggnBa})od1C*HVtNCNFu~>Xa~I%k3QSzd_4N> z=wr8EyLb7{+}*j`T3W1VXTEs-!Hw_8*Y9qfnoSYNKe5eAn_~0TpIs#$o~CLV-hS%r lgYYXa&CB(bx%h2!>q!@sN7QUCw| diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/datetime.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/datetime.cpython-311.pyc deleted file mode 100755 index 37325b020dfb746737ffe414e4babbefdaa6a6e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10198 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 PA^fxSQt%7$rQrVp5N3-? diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/defaultvalue.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/defaultvalue.cpython-311.pyc deleted file mode 100755 index c69e7edf5b11d5d200972941fb0390f2990be52d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4879 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 Urk2=PkM%cV;blo-MJKKBFB6WACIA2c diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/enum.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/enum.cpython-311.pyc deleted file mode 100755 index c47defd341914a7ddef5ce7095b028dda8143974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3866 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 a&A)bP-M=ww_-WaFxEjEDM6p-HjpJWODE}b< diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/logging.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/logging.cpython-311.pyc deleted file mode 100755 index 4ed23de2cfcadf650054d8955d328b6bd1f23e94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1818 zcmZ`)&1)M+6ra`V!00K@Kk<`U9z$~cMJilgTvtJYL!>pLa&`O|7eJOBI#qx|z!YTIDmK&?DQ`{6V zRWj}q##(s21sW7HZ=Dm~!o+uR!4G7ix1r604!3ZrPW&1b3dVUKprG&z&!rs9uX9T7 z061LfsVJ)r(!%N-U~q#c{9Mpii6~lLn2l z6-I=J=V?x5llzrKKg%$hz3+GmQv4Wgqo-#!2UFL02K&$9i`!0OJK-hr8PH6f(L9UhRM|}rYwno-m0`UnXxj)cokO9b`B!@elIN$=C+Nq-jwwe^ z1!%y!?Q?j6dl~XKgmz0OPGF)*1%%u5WF77wlQ85#$UWd3R{6H{4c!(L6M?G%W5K2< z7PDHa$fr07>I=9=r4ui5j=mko$;ZdOsDdKLbc-}XpnAE#UBg~3&Mzz^*p1h!CD*#mFd5~rfcB$UB_n7TgD zzEQR?#9eJNOs$%wV<-UvRw9rMeNH11P>(7T;9C({F;&ZP7(k`ziXpfuJ=QPwq1aSR zF)ZOhdY~jBL;alOR8sQgo`c?<#YL|?7Bz@sx&JPFsnb<1;#F1CdJ$h=WH@gWpQDt< zvCI`kPYf%cj#46Io{X|W5-x>eL6qh~axa8RBcUe=^S+@`rspFXg?oosjqm>$N4rgKW0J&%bxt5#otaf4}VIen3lWvNp8YwsZ zacU#&W-6#~hWub5wBBM0w}l&c6gz@z!nnc&x2We+i5mfTG!q;*gv9IAqfJTL*A#x2 z`d;`Zkz0YUayi?^9V!*bIW5AQ)LmJ@FD}}PIgIh!l6IH~louAUZVfOf*9waUod3bT zLnXzeLzqYE;EHZZ5j0z|${ZKi6JS?jdY389c(Y(kJ04LA*J^s`mwn8uTFuVoZWGBt zc*O|gRS53ifC=C-^U0+y)&kcl4isz+PjcdUA+Cq9A0DeqB125Li|4t}^TQ9ZdC-wI zUX9~d#?JBJ3;$>zUCk{j6w7XmW#R0p8+v;sjpe zfAFSGNgl&H8IMX?Xn=8l>HemhfB{N=@a1ZYI$H`e)5{c(@{fHfI#6e5qG6w#zL%0Z z8tc%fcmcnH)v#=45Jr1t$CWO(eUCXzL+fd(1}zW+FwXRXVZ~-^AC|etI4uswar^aQ z`3G}Zi%q?@UPwhbreLZyfhLir1)`+VGD_D&FjYuO6LXZ5;!c!ioWmd+8JL)-@041i zO-pSe9Z|X^nqs*`e81G8yi%Ycl&Pvoha3mI=ipI~fqaDiJdegM@3tOhyXOkMbA>*#(w81>>}B_te@_2Y z>@KYJ7S>|sLH^=S@LT>$AEndNG1*D}nxFdg`Ooim^K-rY97vs=dUWf1^vPbtT-Q{v`*(i=r zA6&V*8<^i;{j^ccps|Ua>xbYtdaIC$&Qz-~xz%cvcZBCb!QoO=HmN&<#Aif(6PQt| zE`%4y{VkH`L066ed76D`a1*~QFT&AGs9FQkPg<7MpUqjRJ~HGovSyy37mok?nF(v+ Ri`hPc*Ej3&>pw{h_&3x-wpIWD diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/repr.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/repr.cpython-311.pyc deleted file mode 100755 index 9df45be2094bdfe06e418ccd12816213848d0d49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1861 zcmaJ?O>7%Q6rR~#ZxY7|1=6I45)BX`ToSu!#04c$BXcQ8Arb+klxRKP9oy^dkC~ZG z>nN3S$N`~B^Z*K?s+3cp3P|OaW2un1x>63XCnPR#vy_`pyxDbK2MN~eH#2YM&3o_r z-m||O8_Obie*fy*Mt%sPKh@&dWA-Lz%P=`W4%$Etb~F$B+J=UaqchzxnC4`dQ8gWN z-`L1FL(Fi7`??X(nNIdYlpm#UV}#c0t{{HsL>?n{7)a^{g3#!;>$#M-NHq#<>4pLI zTnVd?lS<@zjvLg7kQ@e)C@qV#Cbul&Gg%LvLN@ye4@%#Qo3chULv5!`<~=)-tm0QDJafU*QINJh%#XY7^BJyL;y1a%=>P!{EK$)iF9 z)Mqy#$@!)ESpws=rE8nzGEl7;UI&20XOSWlh_bgBkj?yNoeFn{C3jV+Enz|>a7X|$ z21}a;J;Mu51&{@GkVSc_ST*>B|fHH-8FG}XI8mE5Iilpm_qDsEdY;{K# zYb;>5n|yg^K55#tM{l{ZZV9ll0cwi^o}#emg*NrXa-nbXCPXE!g7^zQd#HVJ4c?#L zdNgyA`MPm9aTq(wAC(N%4_j3pzqO&$Ksr2K^J)`Sb)zI_~Dm8 z4C2GpA4DQ%)lMG79{O$k#rEiRcz+yz^zy^8AI91f%lAsB6Ep3JnUjTdt8H9Q5?jp= z#Y2__zjMHdDO*kWG2|+x*i1V!)}dw-m=iY-QDT;m(;Z$+|1OsKYha<8L3|FPqhpLa zZ=$u diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/strings.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/strings.cpython-311.pyc deleted file mode 100755 index 6fcdef38887769007fe6b203dcf40d09fc6495ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1811 zcmZ`)&2Jk;6rWjtB;F>F50F{~(P^btIFMc3h^DndBnWQRf^ujANS4rcvNN$a*$*?b zj$*4wMhdqaDuk4(7YstFs$4km2jovkq#VkgkhsvBkva9mn_b6oh?w=hnSEdL-tWyD zKN}s@5scq|c)G3+A@ryEI2oDVqWdu{b`e8m#4yub>}h2UBMsd}EVYeTnrnM0g!bW0 zMmfbYJk7E^y_RM}+v#$K4KJg7j$X$ItyCRJynxkRPVB%BspCsRNtL@bF34Klw?iiY zmf$W8IU`{}WGEcJLOkj_wK{M?Zs_`#RQSLy>IB9jc;bF2Nw7x3fgPye#8D!axLW0; zE@7#7!l$m=Agc|q;KX%S1r-fKeMYAJAe`aqcC*?%6$b;|YL_ zNB3=*b`eKq4E50%2JE$Rnxz2qbUDj1fO|F?S>an@$+rUrF*TRs5^!*NS^(Y?5@}bt z2RW_S5aqUWfYsfTMbx0*RM6>iSBd?`N^4O^B^ zJ#JZ%ZdpmeVLf75U)QPIlMGoFKmqKWWl1*(B`h6-Fs&rpH zFsp&bO^*sYFz*MIVAiCynz_mSO%n=e)*4|o@Mn!e!IVzOXKK{mpinY1X}wO zbX;jBM@kyChET^mCRbn~^FUhtr=z7Z!yTlEj>acj_x>1}Y?WS&O||Z+N4$1o8|9== zH@F3UqpaXzUHJA%jX(!MZz0tm-5nsi=n-nee10&z2Uh!i%Wv=_=(tOLMV4y!Wql?r zSb7_QW`Y zNHgA#@Rn425+YuQ=~ZsN!hOC~6AMkq%Zjl93gFDUflXbxVDvTSz(7s|`3s&FI=otf z->>8C!n3)b=YG2V%k6|SNaG{*QWbd#_Rq+g>x5ByJ#hTICdPmr>2~1N0$<&BgMme( zXQC16Vwizf-UZS^oe4BCwR`#d%k9ad@oUH9*IM^qTzK;_-TCmzjUVTp&h=tjKNvrl zIGFg&hwr1SrDLE|rQ@m6(S_1sx)cYul+OzFrxCqz(o{y$RED}zgepedPEiU<7l#oy zaMCL=gv0a6b+90=fU?R}ehZ|N!Weh1XK}iN6d6PKy+icw;IA{1!*6xadGfgUx8nYD YD!QoSJNU_R2dTN;o0G5qqj8A;0;`SScK`qY diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/types.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_utils/__pycache__/types.cpython-311.pyc deleted file mode 100755 index 41b3fb6b38064e1d93c8bb555e888472c61c0ca7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2431 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 a#L}o=Lrh2gf+b5-JD}}Xc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions related to parsing arguments for classes and methods. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from collections.abc import Sequence -from typing import Optional, TypeVar - -from telegram._linkpreviewoptions import LinkPreviewOptions -from telegram._utils.types import ODVInput - -T = TypeVar("T") - - -def parse_sequence_arg(arg: Optional[Sequence[T]]) -> tuple[T, ...]: - """Parses an optional sequence into a tuple - - Args: - arg (:obj:`Sequence`): The sequence to parse. - - Returns: - :obj:`Tuple`: The sequence converted to a tuple or an empty tuple. - """ - return tuple(arg) if arg else () - - -def parse_lpo_and_dwpp( - disable_web_page_preview: Optional[bool], link_preview_options: ODVInput[LinkPreviewOptions] -) -> ODVInput[LinkPreviewOptions]: - """Wrapper around warn_about_deprecated_arg_return_new_arg. Takes care of converting - disable_web_page_preview to LinkPreviewOptions. - """ - if disable_web_page_preview and link_preview_options: - raise ValueError( - "Parameters `disable_web_page_preview` and `link_preview_options` are mutually " - "exclusive." - ) - - if disable_web_page_preview is not None: - link_preview_options = LinkPreviewOptions(is_disabled=disable_web_page_preview) - - return link_preview_options diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/datetime.py b/venv/lib/python3.11/site-packages/telegram/_utils/datetime.py deleted file mode 100755 index 8e6ebdd..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/datetime.py +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions related to datetime and timestamp conversations. - -.. versionchanged:: 20.0 - Previously, the contents of this module were available through the (no longer existing) - module ``telegram._utils.helpers``. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -import contextlib -import datetime as dtm -import time -from typing import TYPE_CHECKING, Optional, Union - -if TYPE_CHECKING: - from telegram import Bot - -UTC = dtm.timezone.utc -try: - import pytz -except ImportError: - pytz = None # type: ignore[assignment] - - -def localize(datetime: dtm.datetime, tzinfo: dtm.tzinfo) -> dtm.datetime: - """Localize the datetime, both for pytz and zoneinfo timezones.""" - if tzinfo is UTC: - return datetime.replace(tzinfo=UTC) - - with contextlib.suppress(AttributeError): - # Since pytz might not be available, we need the suppress context manager - if isinstance(tzinfo, pytz.BaseTzInfo): - return tzinfo.localize(datetime) - - if datetime.tzinfo is None: - return datetime.replace(tzinfo=tzinfo) - return datetime.astimezone(tzinfo) - - -def to_float_timestamp( - time_object: Union[float, dtm.timedelta, dtm.datetime, dtm.time], - reference_timestamp: Optional[float] = None, - tzinfo: Optional[dtm.tzinfo] = None, -) -> float: - """ - Converts a given time object to a float POSIX timestamp. - Used to convert different time specifications to a common format. The time object - can be relative (i.e. indicate a time increment, or a time of day) or absolute. - Objects from the :class:`datetime` module that are timezone-naive will be assumed - to be in UTC, if ``bot`` is not passed or ``bot.defaults`` is :obj:`None`. - - Args: - time_object (:obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`): - Time value to convert. The semantics of this parameter will depend on its type: - - * :obj:`float` will be interpreted as "seconds from :paramref:`reference_t`" - * :obj:`datetime.timedelta` will be interpreted as - "time increment from :paramref:`reference_timestamp`" - * :obj:`datetime.datetime` will be interpreted as an absolute date/time value - * :obj:`datetime.time` will be interpreted as a specific time of day - - reference_timestamp (:obj:`float`, optional): POSIX timestamp that indicates the absolute - time from which relative calculations are to be performed (e.g. when - :paramref:`time_object` is given as an :obj:`int`, indicating "seconds from - :paramref:`reference_time`"). Defaults to now (the time at which this function is - called). - - If :paramref:`time_object` is given as an absolute representation of date & time (i.e. - a :obj:`datetime.datetime` object), :paramref:`reference_timestamp` is not relevant - and so its value should be :obj:`None`. If this is not the case, a :exc:`ValueError` - will be raised. - tzinfo (:class:`datetime.tzinfo`, optional): If :paramref:`time_object` is a naive object - from the :mod:`datetime` module, it will be interpreted as this timezone. Defaults to - :attr:`datetime.timezone.utc` otherwise. - - Note: - Only to be used by ``telegram.ext``. - - Returns: - :obj:`float` | :obj:`None`: - The return value depends on the type of argument :paramref:`time_object`. - If :paramref:`time_object` is given as a time increment (i.e. as a :obj:`int`, - :obj:`float` or :obj:`datetime.timedelta`), then the return value will be - :paramref:`reference_timestamp` + :paramref:`time_object`. - - Else if it is given as an absolute date/time value (i.e. a :obj:`datetime.datetime` - object), the equivalent value as a POSIX timestamp will be returned. - - Finally, if it is a time of the day without date (i.e. a :obj:`datetime.time` - object), the return value is the nearest future occurrence of that time of day. - - Raises: - TypeError: If :paramref:`time_object` s type is not one of those described above. - ValueError: If :paramref:`time_object` is a :obj:`datetime.datetime` and - :paramref:`reference_timestamp` is not :obj:`None`. - """ - if reference_timestamp is None: - reference_timestamp = time.time() - elif isinstance(time_object, dtm.datetime): - raise ValueError("t is an (absolute) datetime while reference_timestamp is not None") - - if isinstance(time_object, dtm.timedelta): - return reference_timestamp + time_object.total_seconds() - if isinstance(time_object, (int, float)): - return reference_timestamp + time_object - - if tzinfo is None: - # We do this here rather than in the signature to ensure that we can make calls like - # to_float_timestamp( - # time, tzinfo=bot.defaults.tzinfo if bot.defaults else None - # ) - # This ensures clean separation of concerns, i.e. the default timezone should not be - # the responsibility of the caller - tzinfo = UTC - - if isinstance(time_object, dtm.time): - reference_dt = dtm.datetime.fromtimestamp( - reference_timestamp, tz=time_object.tzinfo or tzinfo - ) - reference_date = reference_dt.date() - reference_time = reference_dt.timetz() - - aware_datetime = dtm.datetime.combine(reference_date, time_object) - if aware_datetime.tzinfo is None: - # datetime.combine uses the tzinfo of `time_object`, which might be None - # so we still need to localize - aware_datetime = localize(aware_datetime, tzinfo) - - # if the time of day has passed today, use tomorrow - if reference_time > aware_datetime.timetz(): - aware_datetime += dtm.timedelta(days=1) - return _datetime_to_float_timestamp(aware_datetime) - if isinstance(time_object, dtm.datetime): - if time_object.tzinfo is None: - time_object = localize(time_object, tzinfo) - return _datetime_to_float_timestamp(time_object) - - raise TypeError(f"Unable to convert {type(time_object).__name__} object to timestamp") - - -def to_timestamp( - dt_obj: Union[float, dtm.timedelta, dtm.datetime, dtm.time, None], - reference_timestamp: Optional[float] = None, - tzinfo: Optional[dtm.tzinfo] = None, -) -> Optional[int]: - """ - Wrapper over :func:`to_float_timestamp` which returns an integer (the float value truncated - down to the nearest integer). - - See the documentation for :func:`to_float_timestamp` for more details. - """ - return ( - int(to_float_timestamp(dt_obj, reference_timestamp, tzinfo)) - if dt_obj is not None - else None - ) - - -def from_timestamp( - unixtime: Optional[int], - tzinfo: Optional[dtm.tzinfo] = None, -) -> Optional[dtm.datetime]: - """ - Converts an (integer) unix timestamp to a timezone aware datetime object. - :obj:`None` s are left alone (i.e. ``from_timestamp(None)`` is :obj:`None`). - - Args: - unixtime (:obj:`int`): Integer POSIX timestamp. - tzinfo (:obj:`datetime.tzinfo`, optional): The timezone to which the timestamp is to be - converted to. Defaults to :obj:`None`, in which case the returned datetime object will - be timezone aware and in UTC. - - Returns: - Timezone aware equivalent :obj:`datetime.datetime` value if :paramref:`unixtime` is not - :obj:`None`; else :obj:`None`. - """ - if unixtime is None: - return None - - return dtm.datetime.fromtimestamp(unixtime, tz=UTC if tzinfo is None else tzinfo) - - -def extract_tzinfo_from_defaults(bot: Optional["Bot"]) -> Union[dtm.tzinfo, None]: - """ - Extracts the timezone info from the default values of the bot. - If the bot has no default values, :obj:`None` is returned. - """ - # We don't use `ininstance(bot, ExtBot)` here so that this works - # without the job-queue extra dependencies as well - if bot is None: - return None - - if hasattr(bot, "defaults") and bot.defaults: - return bot.defaults.tzinfo - return None - - -def _datetime_to_float_timestamp(dt_obj: dtm.datetime) -> float: - """ - Converts a datetime object to a float timestamp (with sub-second precision). - If the datetime object is timezone-naive, it is assumed to be in UTC. - """ - if dt_obj.tzinfo is None: - dt_obj = dt_obj.replace(tzinfo=dtm.timezone.utc) - return dt_obj.timestamp() diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/defaultvalue.py b/venv/lib/python3.11/site-packages/telegram/_utils/defaultvalue.py deleted file mode 100755 index f9374c5..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/defaultvalue.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the DefaultValue class. - -.. versionchanged:: 20.0 - Previously, the contents of this module were available through the (no longer existing) - module ``telegram._utils.helpers``. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from typing import Generic, TypeVar, Union, overload - -DVType = TypeVar("DVType", bound=object) # pylint: disable=invalid-name -OT = TypeVar("OT", bound=object) - - -class DefaultValue(Generic[DVType]): - """Wrapper for immutable default arguments that allows to check, if the default value was set - explicitly. Usage:: - - default_one = DefaultValue(1) - def f(arg=default_one): - if arg is default_one: - print('`arg` is the default') - arg = arg.value - else: - print('`arg` was set explicitly') - print(f'`arg` = {str(arg)}') - - This yields:: - - >>> f() - `arg` is the default - `arg` = 1 - >>> f(1) - `arg` was set explicitly - `arg` = 1 - >>> f(2) - `arg` was set explicitly - `arg` = 2 - - Also allows to evaluate truthiness:: - - default = DefaultValue(value) - if default: - ... - - is equivalent to:: - - default = DefaultValue(value) - if value: - ... - - ``repr(DefaultValue(value))`` returns ``repr(value)`` and ``str(DefaultValue(value))`` returns - ``f'DefaultValue({value})'``. - - Args: - value (:class:`object`): The value of the default argument - Attributes: - value (:class:`object`): The value of the default argument - - """ - - __slots__ = ("value",) - - def __init__(self, value: DVType): - self.value: DVType = value - - def __bool__(self) -> bool: - return bool(self.value) - - # This is mostly here for readability during debugging - def __str__(self) -> str: - return f"DefaultValue({self.value})" - - # This is here to have the default instances nicely rendered in the docs - def __repr__(self) -> str: - return repr(self.value) - - @overload - @staticmethod - def get_value(obj: "DefaultValue[OT]") -> OT: ... - - @overload - @staticmethod - def get_value(obj: OT) -> OT: ... - - @staticmethod - def get_value(obj: Union[OT, "DefaultValue[OT]"]) -> OT: - """Shortcut for:: - - return obj.value if isinstance(obj, DefaultValue) else obj - - Args: - obj (:obj:`object`): The object to process - - Returns: - Same type as input, or the value of the input: The value - """ - return obj.value if isinstance(obj, DefaultValue) else obj - - -DEFAULT_NONE: DefaultValue[None] = DefaultValue(None) -""":class:`DefaultValue`: Default :obj:`None`""" - -DEFAULT_FALSE: DefaultValue[bool] = DefaultValue(False) -""":class:`DefaultValue`: Default :obj:`False`""" - -DEFAULT_TRUE: DefaultValue[bool] = DefaultValue(True) -""":class:`DefaultValue`: Default :obj:`True` - -.. versionadded:: 20.0 -""" - - -DEFAULT_20: DefaultValue[int] = DefaultValue(20) -""":class:`DefaultValue`: Default :obj:`20`""" - -DEFAULT_IP: DefaultValue[str] = DefaultValue("127.0.0.1") -""":class:`DefaultValue`: Default :obj:`127.0.0.1` - -.. versionadded:: 20.8 -""" - -DEFAULT_80: DefaultValue[int] = DefaultValue(80) -""":class:`DefaultValue`: Default :obj:`80` - -.. versionadded:: 20.8 -""" diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/entities.py b/venv/lib/python3.11/site-packages/telegram/_utils/entities.py deleted file mode 100755 index 7ca3eff..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/entities.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains auxiliary functionality for parsing MessageEntity objects. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from collections.abc import Sequence -from typing import Optional - -from telegram._messageentity import MessageEntity -from telegram._utils.strings import TextEncoding - - -def parse_message_entity(text: str, entity: MessageEntity) -> str: - """Returns the text from a given :class:`telegram.MessageEntity`. - - Args: - text (:obj:`str`): The text to extract the entity from. - entity (:class:`telegram.MessageEntity`): The entity to extract the text from. - - Returns: - :obj:`str`: The text of the given entity. - """ - entity_text = text.encode(TextEncoding.UTF_16_LE) - entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] - - return entity_text.decode(TextEncoding.UTF_16_LE) - - -def parse_message_entities( - text: str, entities: Sequence[MessageEntity], types: Optional[Sequence[str]] = None -) -> dict[MessageEntity, str]: - """ - Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. - It contains entities filtered by their ``type`` attribute as - the key, and the text that each entity belongs to as the value of the :obj:`dict`. - - Args: - text (:obj:`str`): The text to extract the entity from. - entities (list[:class:`telegram.MessageEntity`]): The entities to extract the text from. - types (list[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the - ``type`` attribute of an entity is contained in this list, it will be returned. - Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`. - - Returns: - dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to - the text that belongs to them, calculated based on UTF-16 codepoints. - """ - if types is None: - types = MessageEntity.ALL_TYPES - - return { - entity: parse_message_entity(text, entity) for entity in entities if entity.type in types - } diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/enum.py b/venv/lib/python3.11/site-packages/telegram/_utils/enum.py deleted file mode 100755 index 5836287..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/enum.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions related to enums. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -import enum as _enum -import sys -from typing import TypeVar, Union - -_A = TypeVar("_A") -_B = TypeVar("_B") -_Enum = TypeVar("_Enum", bound=_enum.Enum) - - -def get_member(enum_cls: type[_Enum], value: _A, default: _B) -> Union[_Enum, _A, _B]: - """Tries to call ``enum_cls(value)`` to convert the value into an enumeration member. - If that fails, the ``default`` is returned. - """ - try: - return enum_cls(value) - except ValueError: - return default - - -# Python 3.11 and above has a different output for mixin classes for IntEnum, StrEnum and IntFlag -# see https://docs.python.org/3.11/library/enum.html#notes. We want e.g. str(StrEnumTest.FOO) to -# return "foo" instead of "StrEnumTest.FOO", which is not the case < py3.11 -class StringEnum(str, _enum.Enum): - """Helper class for string enums where ``str(member)`` prints the value, but ``repr(member)`` - gives ``EnumName.MEMBER_NAME``. - """ - - __slots__ = () - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}.{self.name}>" - - def __str__(self) -> str: - return str.__str__(self) - - -# Apply the __repr__ modification and __str__ fix to IntEnum -class IntEnum(_enum.IntEnum): # pylint: disable=invalid-slots - """Helper class for int enums where ``str(member)`` prints the value, but ``repr(member)`` - gives ``EnumName.MEMBER_NAME``. - """ - - __slots__ = () - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}.{self.name}>" - - if sys.version_info < (3, 11): - - def __str__(self) -> str: - return str(self.value) - - -class FloatEnum(float, _enum.Enum): - """Helper class for float enums where ``str(member)`` prints the value, but ``repr(member)`` - gives ``EnumName.MEMBER_NAME``. - """ - - __slots__ = () - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}.{self.name}>" - - def __str__(self) -> str: - return str(self.value) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/files.py b/venv/lib/python3.11/site-packages/telegram/_utils/files.py deleted file mode 100755 index 8bce30d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/files.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions related to handling of files. - -.. versionchanged:: 20.0 - Previously, the contents of this module were available through the (no longer existing) - module ``telegram._utils.helpers``. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" - -from pathlib import Path -from typing import IO, TYPE_CHECKING, Any, Optional, TypeVar, Union, cast, overload - -from telegram._utils.types import FileInput, FilePathInput - -if TYPE_CHECKING: - from telegram import InputFile, TelegramObject - -_T = TypeVar("_T", bound=Union[bytes, "InputFile", str, Path, None]) - - -@overload -def load_file(obj: IO[bytes]) -> tuple[Optional[str], bytes]: ... - - -@overload -def load_file(obj: _T) -> tuple[None, _T]: ... - - -def load_file( - obj: Optional[FileInput], -) -> tuple[Optional[str], Union[bytes, "InputFile", str, Path, None]]: - """If the input is a file handle, read the data and name and return it. Otherwise, return - the input unchanged. - """ - if obj is None: - return None, None - - try: - contents = obj.read() # type: ignore[union-attr] - except AttributeError: - return None, cast(Union[bytes, "InputFile", str, Path], obj) - - filename = guess_file_name(obj) - - return filename, contents - - -def guess_file_name(obj: FileInput) -> Optional[str]: - """If the input is a file handle, read name and return it. Otherwise, return - the input unchanged. - """ - if hasattr(obj, "name") and not isinstance(obj.name, int): - return Path(obj.name).name - - return None - - -def is_local_file(obj: Optional[FilePathInput]) -> bool: - """ - Checks if a given string is a file on local system. - - Args: - obj (:obj:`str`): The string to check. - """ - if obj is None: - return False - - path = Path(obj) - try: - return path.is_file() - except Exception: - return False - - -def parse_file_input( # pylint: disable=too-many-return-statements - file_input: Union[FileInput, "TelegramObject"], - tg_type: Optional[type["TelegramObject"]] = None, - filename: Optional[str] = None, - attach: bool = False, - local_mode: bool = False, -) -> Union[str, "InputFile", Any]: - """ - Parses input for sending files: - - * For string input, if the input is an absolute path of a local file: - - * if ``local_mode`` is ``True``, adds the ``file://`` prefix. If the input is a relative - path of a local file, computes the absolute path and adds the ``file://`` prefix. - * if ``local_mode`` is ``False``, loads the file as binary data and builds an - :class:`InputFile` from that - - Returns the input unchanged, otherwise. - * :class:`pathlib.Path` objects are treated the same way as strings. - * For IO and bytes input, returns an :class:`telegram.InputFile`. - * If :attr:`tg_type` is specified and the input is of that type, returns the ``file_id`` - attribute. - - Args: - file_input (:obj:`str` | :obj:`bytes` | :term:`file object` | :class:`~telegram.InputFile`\ - | Telegram media object): The input to parse. - tg_type (:obj:`type`, optional): The Telegram media type the input can be. E.g. - :class:`telegram.Animation`. - filename (:obj:`str`, optional): The filename. Only relevant in case an - :class:`telegram.InputFile` is returned. - attach (:obj:`bool`, optional): Pass :obj:`True` if the parameter this file belongs to in - the request to Telegram should point to the multipart data via an ``attach://`` URI. - Defaults to `False`. Only relevant if an :class:`telegram.InputFile` is returned. - local_mode (:obj:`bool`, optional): Pass :obj:`True` if the bot is running an api server - in ``--local`` mode. - - Returns: - :obj:`str` | :class:`telegram.InputFile` | :obj:`object`: The parsed input or the untouched - :attr:`file_input`, in case it's no valid file input. - """ - # Importing on file-level yields cyclic Import Errors - from telegram import InputFile # pylint: disable=import-outside-toplevel - - if isinstance(file_input, str) and file_input.startswith("file://"): - if not local_mode: - raise ValueError("Specified file input is a file URI, but local mode is not enabled.") - return file_input - if isinstance(file_input, (str, Path)): - if is_local_file(file_input): - path = Path(file_input) - if local_mode: - return path.absolute().as_uri() - return InputFile(path.open(mode="rb"), filename=filename, attach=attach) - - return file_input - if isinstance(file_input, bytes): - return InputFile(file_input, filename=filename, attach=attach) - if hasattr(file_input, "read"): - return InputFile(cast(IO, file_input), filename=filename, attach=attach) - if tg_type and isinstance(file_input, tg_type): - return file_input.file_id # type: ignore[attr-defined] - return file_input diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/logging.py b/venv/lib/python3.11/site-packages/telegram/_utils/logging.py deleted file mode 100755 index 0bd778b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/logging.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions related to logging. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -import logging -from typing import Optional - - -def get_logger(file_name: str, class_name: Optional[str] = None) -> logging.Logger: - """Returns a logger with an appropriate name. - Use as follows:: - - logger = get_logger(__name__) - - If for example `__name__` is `telegram.ext._updater`, the logger will be named - `telegram.ext.Updater`. If `class_name` is passed, this will result in - `telegram.ext.`. Useful e.g. for CamelCase class names. - - If the file name points to a utils module, the logger name will simply be `telegram(.ext)`. - - Returns: - :class:`logging.Logger`: The logger. - """ - parts = file_name.split("_") - if parts[1].startswith("utils") and class_name is None: - name = parts[0].rstrip(".") - else: - name = f"{parts[0]}{class_name or parts[1].capitalize()}" - return logging.getLogger(name) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/markup.py b/venv/lib/python3.11/site-packages/telegram/_utils/markup.py deleted file mode 100755 index eed70b3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/markup.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains a helper function for Telegram's ReplyMarkups - -.. versionchanged:: 20.0 - Previously, the contents of this module were available through the (no longer existing) - class ``telegram.ReplyMarkup``. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from collections.abc import Sequence - - -def check_keyboard_type(keyboard: object) -> bool: - """Checks if the keyboard provided is of the correct type - A sequence of sequences. - Implicitly tested in the init-tests of `{Inline, Reply}KeyboardMarkup` - """ - # string and bytes may actually be used for ReplyKeyboardMarkup in which case each button - # would contain a single character. But that use case should be discouraged and we don't - # allow it here. - if not isinstance(keyboard, Sequence) or isinstance(keyboard, (str, bytes)): - return False - - for row in keyboard: - if not isinstance(row, Sequence) or isinstance(row, (str, bytes)): - return False - for inner in row: - if isinstance(inner, Sequence) and not isinstance(inner, str): - return False - return True diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/repr.py b/venv/lib/python3.11/site-packages/telegram/_utils/repr.py deleted file mode 100755 index 38d9834..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/repr.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains auxiliary functionality for building strings for __repr__ method. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from typing import Any - - -def build_repr_with_selected_attrs(obj: object, **kwargs: Any) -> str: - """Create ``__repr__`` string in the style ``Classname[arg1=1, arg2=2]``. - - The square brackets emphasize the fact that an object cannot be instantiated - from this string. - - Attributes that are to be used in the representation, are passed as kwargs. - """ - return ( - f"{obj.__class__.__name__}" - # square brackets emphasize that an object cannot be instantiated with these params - f"[{', '.join(_stringify(name, value) for name, value in kwargs.items())}]" - ) - - -def _stringify(key: str, val: Any) -> str: - return f"{key}={val.__qualname__ if callable(val) else val}" diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/strings.py b/venv/lib/python3.11/site-packages/telegram/_utils/strings.py deleted file mode 100755 index 76a8bcd..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/strings.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains a helper functions related to string manipulation. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" - -from telegram._utils.enum import StringEnum - -# TODO: Remove this when https://github.com/PyCQA/pylint/issues/6887 is resolved. -# pylint: disable=invalid-enum-extension - - -class TextEncoding(StringEnum): - """This enum contains encoding schemes for text. - - .. versionadded:: 21.5 - """ - - __slots__ = () - - UTF_8 = "utf-8" - UTF_16_LE = "utf-16-le" - - -def to_camel_case(snake_str: str) -> str: - """Converts a snake_case string to camelCase. - - Args: - snake_str (:obj:`str`): The string to convert. - - Returns: - :obj:`str`: The converted string. - """ - components = snake_str.split("_") - return components[0] + "".join(x.title() for x in components[1:]) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/types.py b/venv/lib/python3.11/site-packages/telegram/_utils/types.py deleted file mode 100755 index e1bf77d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/types.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains custom typing aliases for internal use within the library. - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from collections.abc import Collection -from pathlib import Path -from typing import IO, TYPE_CHECKING, Any, Literal, Optional, TypeVar, Union - -if TYPE_CHECKING: - from telegram import ( - ForceReply, - InlineKeyboardMarkup, - InputFile, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ) - from telegram._utils.defaultvalue import DefaultValue - -FileLike = Union[IO[bytes], "InputFile"] -"""Either a bytes-stream (e.g. open file handler) or a :class:`telegram.InputFile`.""" - -FilePathInput = Union[str, Path] -"""A filepath either as string or as :obj:`pathlib.Path` object.""" - -FileInput = Union[FilePathInput, FileLike, bytes, str] -"""Valid input for passing files to Telegram. Either a file id as string, a file like object, -a local file path as string, :class:`pathlib.Path` or the file contents as :obj:`bytes`.""" - -JSONDict = dict[str, Any] -"""Dictionary containing response from Telegram or data to send to the API.""" - -DVValueType = TypeVar("DVValueType") # pylint: disable=invalid-name -DVType = Union[DVValueType, "DefaultValue[DVValueType]"] -"""Generic type for a variable which can be either `type` or `DefaultVaule[type]`.""" -ODVInput = Optional[Union["DefaultValue[DVValueType]", DVValueType, "DefaultValue[None]"]] -"""Generic type for bot method parameters which can have defaults. ``ODVInput[type]`` is the same -as ``Optional[Union[DefaultValue[type], type, DefaultValue[None]]``.""" -DVInput = Union["DefaultValue[DVValueType]", DVValueType, "DefaultValue[None]"] -"""Generic type for bot method parameters which can have defaults. ``DVInput[type]`` is the same -as ``Union[DefaultValue[type], type, DefaultValue[None]]``.""" - -RT = TypeVar("RT") -SCT = Union[RT, Collection[RT]] # pylint: disable=invalid-name -"""Single instance or collection of instances.""" - -ReplyMarkup = Union[ - "InlineKeyboardMarkup", "ReplyKeyboardMarkup", "ReplyKeyboardRemove", "ForceReply" -] -"""Type alias for reply markup objects. - -.. versionadded:: 20.0 -""" - -FieldTuple = tuple[str, Union[bytes, IO[bytes]], str] -"""Alias for return type of `InputFile.field_tuple`.""" -UploadFileDict = dict[str, FieldTuple] -"""Dictionary containing file data to be uploaded to the API.""" - -HTTPVersion = Literal["1.1", "2.0", "2"] -"""Allowed HTTP versions. - -.. versionadded:: 20.4""" - -CorrectOptionID = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - -MarkdownVersion = Literal[1, 2] - -SocketOpt = Union[ - tuple[int, int, int], - tuple[int, int, Union[bytes, bytearray]], - tuple[int, int, None, int], -] diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/warnings.py b/venv/lib/python3.11/site-packages/telegram/_utils/warnings.py deleted file mode 100755 index 2aa79db..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/warnings.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions related to warnings issued by the library. - -.. versionadded:: 20.0 - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -import warnings -from typing import Union - -from telegram.warnings import PTBUserWarning - - -def warn( - message: Union[str, PTBUserWarning], - category: type[Warning] = PTBUserWarning, - stacklevel: int = 0, -) -> None: - """ - Helper function used as a shortcut for warning with default values. - - .. versionadded:: 20.0 - - Args: - message (:obj:`str` | :obj:`PTBUserWarning`): Specify the warnings message to pass to - ``warnings.warn()``. - - .. versionchanged:: 21.2 - Now also accepts a :obj:`PTBUserWarning` instance. - - category (:obj:`type[Warning]`, optional): Specify the Warning class to pass to - ``warnings.warn()``. Defaults to :class:`telegram.warnings.PTBUserWarning`. - stacklevel (:obj:`int`, optional): Specify the stacklevel to pass to ``warnings.warn()``. - Pass the same value as you'd pass directly to ``warnings.warn()``. Defaults to ``0``. - """ - warnings.warn(message, category=category, stacklevel=stacklevel + 1) diff --git a/venv/lib/python3.11/site-packages/telegram/_utils/warnings_transition.py b/venv/lib/python3.11/site-packages/telegram/_utils/warnings_transition.py deleted file mode 100755 index cd9fecd..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_utils/warnings_transition.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains functionality used for transition warnings issued by this library. - -It was created to prevent circular imports that would be caused by creating the warnings -inside warnings.py. - -.. versionadded:: 20.2 -""" -from typing import Any, Callable, Union - -from telegram._utils.warnings import warn -from telegram.warnings import PTBDeprecationWarning, PTBUserWarning - - -def build_deprecation_warning_message( - deprecated_name: str, - new_name: str, - object_type: str, - bot_api_version: str, -) -> str: - """Builds a warning message for the transition in API when an object is renamed. - - Returns a warning message that can be used in `warn` function. - """ - return ( - f"The {object_type} '{deprecated_name}' was renamed to '{new_name}' in Bot API " - f"{bot_api_version}. We recommend using '{new_name}' instead of " - f"'{deprecated_name}'." - ) - - -# Narrower type hints will cause linting errors and/or circular imports. -# We'll use `Any` here and put type hints in the calling code. -def warn_about_deprecated_arg_return_new_arg( - deprecated_arg: Any, - new_arg: Any, - deprecated_arg_name: str, - new_arg_name: str, - bot_api_version: str, - ptb_version: str, - stacklevel: int = 2, - warn_callback: Callable[[Union[str, PTBUserWarning], type[Warning], int], None] = warn, -) -> Any: - """A helper function for the transition in API when argument is renamed. - - Checks the `deprecated_arg` and `new_arg` objects; warns if non-None `deprecated_arg` object - was passed. Returns `new_arg` object (either the one originally passed by the user or the one - that user passed as `deprecated_arg`). - - Raises `ValueError` if both `deprecated_arg` and `new_arg` objects were passed, and they are - different. - """ - if deprecated_arg and new_arg and deprecated_arg != new_arg: - base_message = build_deprecation_warning_message( - deprecated_name=deprecated_arg_name, - new_name=new_arg_name, - object_type="parameter", - bot_api_version=bot_api_version, - ) - raise ValueError( - f"You passed different entities as '{deprecated_arg_name}' and '{new_arg_name}'. " - f"{base_message}" - ) - - if deprecated_arg: - warn_callback( - PTBDeprecationWarning( - ptb_version, - f"Bot API {bot_api_version} renamed the argument '{deprecated_arg_name}' to " - f"'{new_arg_name}'.", - ), - stacklevel=stacklevel + 1, # type: ignore[call-arg] - ) - return deprecated_arg - - return new_arg - - -def warn_about_deprecated_attr_in_property( - deprecated_attr_name: str, - new_attr_name: str, - bot_api_version: str, - ptb_version: str, - stacklevel: int = 2, -) -> None: - """A helper function for the transition in API when attribute is renamed. Call from properties. - - The properties replace deprecated attributes in classes and issue these deprecation warnings. - """ - warn( - PTBDeprecationWarning( - ptb_version, - f"Bot API {bot_api_version} renamed the attribute '{deprecated_attr_name}' to " - f"'{new_attr_name}'.", - ), - stacklevel=stacklevel + 1, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_version.py b/venv/lib/python3.11/site-packages/telegram/_version.py deleted file mode 100755 index f514a9b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_version.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=missing-module-docstring -from typing import Final, NamedTuple - -__all__ = ("__version__", "__version_info__") - - -class Version(NamedTuple): - """Copies the behavior of sys.version_info. - serial is always 0 for stable releases. - """ - - major: int - minor: int - micro: int - releaselevel: str # Literal['alpha', 'beta', 'candidate', 'final'] - serial: int - - def _rl_shorthand(self) -> str: - return { - "alpha": "a", - "beta": "b", - "candidate": "rc", - }[self.releaselevel] - - def __str__(self) -> str: - version = f"{self.major}.{self.minor}" - if self.micro != 0: - version = f"{version}.{self.micro}" - if self.releaselevel != "final": - version = f"{version}{self._rl_shorthand()}{self.serial}" - - return version - - -__version_info__: Final[Version] = Version( - major=21, minor=10, micro=0, releaselevel="final", serial=0 -) -__version__: Final[str] = str(__version_info__) diff --git a/venv/lib/python3.11/site-packages/telegram/_videochat.py b/venv/lib/python3.11/site-packages/telegram/_videochat.py deleted file mode 100755 index 77da893..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_videochat.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains objects related to Telegram video chats.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class VideoChatStarted(TelegramObject): - """ - This object represents a service message about a video - chat started in the chat. Currently holds no information. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This class was renamed from ``VoiceChatStarted`` in accordance to Bot API 6.0. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(api_kwargs=api_kwargs) - - self._freeze() - - -class VideoChatEnded(TelegramObject): - """ - This object represents a service message about a - video chat ended in the chat. - - Objects of this class are comparable in terms of equality. - Two objects of this class are considered equal, if their - :attr:`duration` are equal. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This class was renamed from ``VoiceChatEnded`` in accordance to Bot API 6.0. - - Args: - duration (:obj:`int`): Voice chat duration in seconds. - - Attributes: - duration (:obj:`int`): Voice chat duration in seconds. - - """ - - __slots__ = ("duration",) - - def __init__( - self, - duration: int, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.duration: int = duration - self._id_attrs = (self.duration,) - - self._freeze() - - -class VideoChatParticipantsInvited(TelegramObject): - """ - This object represents a service message about new members invited to a video chat. - - Objects of this class are comparable in terms of equality. - Two objects of this class are considered equal, if their :attr:`users` are equal. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This class was renamed from ``VoiceChatParticipantsInvited`` in accordance to Bot API 6.0. - - Args: - users (Sequence[:class:`telegram.User`]): New members that were invited to the video chat. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - Attributes: - users (tuple[:class:`telegram.User`]): New members that were invited to the video chat. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - """ - - __slots__ = ("users",) - - def __init__( - self, - users: Sequence[User], - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.users: tuple[User, ...] = parse_sequence_arg(users) - self._id_attrs = (self.users,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["VideoChatParticipantsInvited"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["users"] = User.de_list(data.get("users", []), bot) - return super().de_json(data=data, bot=bot) - - -class VideoChatScheduled(TelegramObject): - """This object represents a service message about a video chat scheduled in the chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`start_date` are equal. - - .. versionchanged:: 20.0 - This class was renamed from ``VoiceChatScheduled`` in accordance to Bot API 6.0. - - Args: - start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the video - chat is supposed to be started by a chat administrator - - .. versionchanged:: 20.3 - |datetime_localization| - Attributes: - start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the video - chat is supposed to be started by a chat administrator - - .. versionchanged:: 20.3 - |datetime_localization| - - """ - - __slots__ = ("start_date",) - - def __init__( - self, - start_date: dtm.datetime, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.start_date: dtm.datetime = start_date - - self._id_attrs = (self.start_date,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["VideoChatScheduled"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["start_date"] = from_timestamp(data["start_date"], tzinfo=loc_tzinfo) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_webappdata.py b/venv/lib/python3.11/site-packages/telegram/_webappdata.py deleted file mode 100755 index 2b1a8fd..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_webappdata.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram WebAppData.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class WebAppData(TelegramObject): - """Contains data sent from a `Web App `_ to the bot. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`data` and :attr:`button_text` are equal. - - Examples: - :any:`Webapp Bot ` - - .. versionadded:: 20.0 - - Args: - data (:obj:`str`): The data. Be aware that a bad client can send arbitrary data in this - field. - button_text (:obj:`str`): Text of the :paramref:`~telegram.KeyboardButton.web_app` keyboard - button, from which the Web App was opened. - - Attributes: - data (:obj:`str`): The data. Be aware that a bad client can send arbitrary data in this - field. - button_text (:obj:`str`): Text of the :paramref:`~telegram.KeyboardButton.web_app` keyboard - button, from which the Web App was opened. - - Warning: - Be aware that a bad client can send arbitrary data in this field. - """ - - __slots__ = ("button_text", "data") - - def __init__(self, data: str, button_text: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - # Required - self.data: str = data - self.button_text: str = button_text - - self._id_attrs = (self.data, self.button_text) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_webappinfo.py b/venv/lib/python3.11/site-packages/telegram/_webappinfo.py deleted file mode 100755 index 11a6bf3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_webappinfo.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Web App Info.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class WebAppInfo(TelegramObject): - """ - This object contains information about a `Web App `_. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`url` are equal. - - Examples: - :any:`Webapp Bot ` - - .. versionadded:: 20.0 - - Args: - url (:obj:`str`): An HTTPS URL of a Web App to be opened with additional data as specified - in `Initializing Web Apps \ - `_. - - Attributes: - url (:obj:`str`): An HTTPS URL of a Web App to be opened with additional data as specified - in `Initializing Web Apps \ - `_. - """ - - __slots__ = ("url",) - - def __init__(self, url: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - # Required - self.url: str = url - - self._id_attrs = (self.url,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_webhookinfo.py b/venv/lib/python3.11/site-packages/telegram/_webhookinfo.py deleted file mode 100755 index 5f46e64..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_webhookinfo.py +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram WebhookInfo.""" - -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class WebhookInfo(TelegramObject): - """This object represents a Telegram WebhookInfo. - - Contains information about the current status of a webhook. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`url`, :attr:`has_custom_certificate`, - :attr:`pending_update_count`, :attr:`ip_address`, :attr:`last_error_date`, - :attr:`last_error_message`, :attr:`max_connections`, :attr:`allowed_updates` and - :attr:`last_synchronization_error_date` are equal. - - .. versionchanged:: 20.0 - :attr:`last_synchronization_error_date` is considered as well when comparing objects of - this type in terms of equality. - - Args: - url (:obj:`str`): Webhook URL, may be empty if webhook is not set up. - has_custom_certificate (:obj:`bool`): :obj:`True`, if a custom certificate was provided for - webhook certificate checks. - pending_update_count (:obj:`int`): Number of updates awaiting delivery. - ip_address (:obj:`str`, optional): Currently used webhook IP address. - last_error_date (:class:`datetime.datetime`): Optional. Datetime for the most recent - error that happened when trying to deliver an update via webhook. - - .. versionchanged:: 20.3 - |datetime_localization| - last_error_message (:obj:`str`, optional): Error message in human-readable format for the - most recent error that happened when trying to deliver an update via webhook. - max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS - connections to the webhook for update delivery. - allowed_updates (Sequence[:obj:`str`], optional): A sequence of update types the bot is - subscribed to. Defaults to all update types, except - :attr:`telegram.Update.chat_member`. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - last_synchronization_error_date (:class:`datetime.datetime`, optional): Datetime of the - most recent error that happened when trying to synchronize available updates with - Telegram datacenters. - - .. versionadded:: 20.0 - - .. versionchanged:: 20.3 - |datetime_localization| - Attributes: - url (:obj:`str`): Webhook URL, may be empty if webhook is not set up. - has_custom_certificate (:obj:`bool`): :obj:`True`, if a custom certificate was provided for - webhook certificate checks. - pending_update_count (:obj:`int`): Number of updates awaiting delivery. - ip_address (:obj:`str`): Optional. Currently used webhook IP address. - last_error_date (:class:`datetime.datetime`): Optional. Datetime for the most recent - error that happened when trying to deliver an update via webhook. - - .. versionchanged:: 20.3 - |datetime_localization| - last_error_message (:obj:`str`): Optional. Error message in human-readable format for the - most recent error that happened when trying to deliver an update via webhook. - max_connections (:obj:`int`): Optional. Maximum allowed number of simultaneous HTTPS - connections to the webhook for update delivery. - allowed_updates (tuple[:obj:`str`]): Optional. A tuple of update types the bot is - subscribed to. Defaults to all update types, except - :attr:`telegram.Update.chat_member`. - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - last_synchronization_error_date (:class:`datetime.datetime`, optional): Datetime of the - most recent error that happened when trying to synchronize available updates with - Telegram datacenters. - - .. versionadded:: 20.0 - - .. versionchanged:: 20.3 - |datetime_localization| - """ - - __slots__ = ( - "allowed_updates", - "has_custom_certificate", - "ip_address", - "last_error_date", - "last_error_message", - "last_synchronization_error_date", - "max_connections", - "pending_update_count", - "url", - ) - - def __init__( - self, - url: str, - has_custom_certificate: bool, - pending_update_count: int, - last_error_date: Optional[dtm.datetime] = None, - last_error_message: Optional[str] = None, - max_connections: Optional[int] = None, - allowed_updates: Optional[Sequence[str]] = None, - ip_address: Optional[str] = None, - last_synchronization_error_date: Optional[dtm.datetime] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.url: str = url - self.has_custom_certificate: bool = has_custom_certificate - self.pending_update_count: int = pending_update_count - - # Optional - self.ip_address: Optional[str] = ip_address - self.last_error_date: Optional[dtm.datetime] = last_error_date - self.last_error_message: Optional[str] = last_error_message - self.max_connections: Optional[int] = max_connections - self.allowed_updates: tuple[str, ...] = parse_sequence_arg(allowed_updates) - self.last_synchronization_error_date: Optional[dtm.datetime] = ( - last_synchronization_error_date - ) - - self._id_attrs = ( - self.url, - self.has_custom_certificate, - self.pending_update_count, - self.ip_address, - self.last_error_date, - self.last_error_message, - self.max_connections, - self.allowed_updates, - self.last_synchronization_error_date, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["WebhookInfo"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["last_error_date"] = from_timestamp(data.get("last_error_date"), tzinfo=loc_tzinfo) - data["last_synchronization_error_date"] = from_timestamp( - data.get("last_synchronization_error_date"), tzinfo=loc_tzinfo - ) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_writeaccessallowed.py b/venv/lib/python3.11/site-packages/telegram/_writeaccessallowed.py deleted file mode 100755 index 07fdd6b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_writeaccessallowed.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains objects related to the write access allowed service message.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class WriteAccessAllowed(TelegramObject): - """ - This object represents a service message about a user allowing a bot to write messages after - adding it to the attachment menu, launching a Web App from a link, or accepting an explicit - request from a Web App sent by the method - `requestWriteAccess `_. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`web_app_name` is equal. - - .. versionadded:: 20.0 - .. versionchanged:: 20.6 - Added custom equality comparison for objects of this class. - - Args: - web_app_name (:obj:`str`, optional): Name of the Web App, if the access was granted when - the Web App was launched from a link. - - .. versionadded:: 20.3 - from_request (:obj:`bool`, optional): :obj:`True`, if the access was granted after the user - accepted an explicit request from a Web App sent by the method - `requestWriteAccess `_. - - .. versionadded:: 20.6 - from_attachment_menu (:obj:`bool`, optional): :obj:`True`, if the access was granted when - the bot was added to the attachment or side menu. - - .. versionadded:: 20.6 - - Attributes: - web_app_name (:obj:`str`): Optional. Name of the Web App, if the access was granted when - the Web App was launched from a link. - - .. versionadded:: 20.3 - from_request (:obj:`bool`): Optional. :obj:`True`, if the access was granted after the user - accepted an explicit request from a Web App. - - .. versionadded:: 20.6 - from_attachment_menu (:obj:`bool`): Optional. :obj:`True`, if the access was granted when - the bot was added to the attachment or side menu. - - .. versionadded:: 20.6 - - """ - - __slots__ = ("from_attachment_menu", "from_request", "web_app_name") - - def __init__( - self, - web_app_name: Optional[str] = None, - from_request: Optional[bool] = None, - from_attachment_menu: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.web_app_name: Optional[str] = web_app_name - self.from_request: Optional[bool] = from_request - self.from_attachment_menu: Optional[bool] = from_attachment_menu - - self._id_attrs = (self.web_app_name,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/constants.py b/venv/lib/python3.11/site-packages/telegram/constants.py deleted file mode 100755 index c61b3b9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/constants.py +++ /dev/null @@ -1,3249 +0,0 @@ -# python-telegram-bot - a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# by the python-telegram-bot contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains several constants that are relevant for working with the Bot API. - -Unless noted otherwise, all constants in this module were extracted from the -`Telegram Bots FAQ `_ and -`Telegram Bots API `_. - -Most of the following constants are related to specific classes or topics and are grouped into -enums. If they are related to a specific class, then they are also available as attributes of -those classes. - -.. versionchanged:: 20.0 - - * Most of the constants in this module are grouped into enums. -""" -# TODO: Remove this when https://github.com/PyCQA/pylint/issues/6887 is resolved. -# pylint: disable=invalid-enum-extension,invalid-slots - -__all__ = [ - "BOT_API_VERSION", - "BOT_API_VERSION_INFO", - "SUPPORTED_WEBHOOK_PORTS", - "ZERO_DATE", - "AccentColor", - "BackgroundFillLimit", - "BackgroundFillType", - "BackgroundTypeLimit", - "BackgroundTypeType", - "BotCommandLimit", - "BotCommandScopeType", - "BotDescriptionLimit", - "BotNameLimit", - "BulkRequestLimit", - "CallbackQueryLimit", - "ChatAction", - "ChatBoostSources", - "ChatID", - "ChatInviteLinkLimit", - "ChatLimit", - "ChatMemberStatus", - "ChatPhotoSize", - "ChatSubscriptionLimit", - "ChatType", - "ContactLimit", - "CustomEmojiStickerLimit", - "DiceEmoji", - "DiceLimit", - "FileSizeLimit", - "FloodLimit", - "ForumIconColor", - "ForumTopicLimit", - "GiftLimit", - "GiveawayLimit", - "InlineKeyboardButtonLimit", - "InlineKeyboardMarkupLimit", - "InlineQueryLimit", - "InlineQueryResultLimit", - "InlineQueryResultType", - "InlineQueryResultsButtonLimit", - "InputMediaType", - "InputPaidMediaType", - "InvoiceLimit", - "KeyboardButtonRequestUsersLimit", - "LocationLimit", - "MaskPosition", - "MediaGroupLimit", - "MenuButtonType", - "MessageAttachmentType", - "MessageEntityType", - "MessageLimit", - "MessageOriginType", - "MessageType", - "PaidMediaType", - "ParseMode", - "PollLimit", - "PollType", - "PollingLimit", - "ProfileAccentColor", - "ReactionEmoji", - "ReactionType", - "ReplyLimit", - "RevenueWithdrawalStateType", - "StarTransactions", - "StarTransactionsLimit", - "StickerFormat", - "StickerLimit", - "StickerSetLimit", - "StickerType", - "TransactionPartnerType", - "UpdateType", - "UserProfilePhotosLimit", - "VerifyLimit", - "WebhookLimit", -] - -import datetime as dtm -import sys -from enum import Enum -from typing import Final, NamedTuple, Optional - -from telegram._utils.datetime import UTC -from telegram._utils.enum import FloatEnum, IntEnum, StringEnum - - -class _BotAPIVersion(NamedTuple): - """Similar behavior to sys.version_info. - So far TG has only published X.Y releases. We can add X.Y.Z(a(S)) if needed. - """ - - major: int - minor: int - - def __repr__(self) -> str: - """Unfortunately calling super().__repr__ doesn't work with typing.NamedTuple, so we - do this manually. - """ - return f"BotAPIVersion(major={self.major}, minor={self.minor})" - - def __str__(self) -> str: - return f"{self.major}.{self.minor}" - - -class _AccentColor(NamedTuple): - """A helper class for (profile) accent colors. Since TG doesn't define a class for this and - the behavior is quite different for the different accent colors, we don't make this a public - class. This gives us more flexibility to change the implementation if necessary for future - versions. - """ - - identifier: int - name: Optional[str] = None - light_colors: tuple[int, ...] = () - dark_colors: tuple[int, ...] = () - - -#: :class:`typing.NamedTuple`: A tuple containing the two components of the version number: -# ``major`` and ``minor``. Both values are integers. -#: The components can also be accessed by name, so ``BOT_API_VERSION_INFO[0]`` is equivalent -#: to ``BOT_API_VERSION_INFO.major`` and so on. Also available as -#: :data:`telegram.__bot_api_version_info__`. -#: -#: .. versionadded:: 20.0 -BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=8, minor=2) -#: :obj:`str`: Telegram Bot API -#: version supported by this version of `python-telegram-bot`. Also available as -#: :data:`telegram.__bot_api_version__`. -#: -#: .. versionadded:: 13.4 -BOT_API_VERSION: Final[str] = str(BOT_API_VERSION_INFO) - -# constants above this line are tested - -#: list[:obj:`int`]: Ports supported by -#: :paramref:`telegram.Bot.set_webhook.url`. -SUPPORTED_WEBHOOK_PORTS: Final[list[int]] = [443, 80, 88, 8443] - -#: :obj:`datetime.datetime`, value of unix 0. -#: This date literal is used in :class:`telegram.InaccessibleMessage` -#: -#: .. versionadded:: 20.8 -ZERO_DATE: Final[dtm.datetime] = dtm.datetime(1970, 1, 1, tzinfo=UTC) - - -class AccentColor(Enum): - """This enum contains the available accent colors for - :class:`telegram.ChatFullInfo.accent_color_id`. - The members of this enum are named tuples with the following attributes: - - - ``identifier`` (:obj:`int`): The identifier of the accent color. - - ``name`` (:obj:`str`): Optional. The name of the accent color. - - ``light_colors`` (tuple[:obj:`str`]): Optional. The light colors of the accent color as HEX - value. - - ``dark_colors`` (tuple[:obj:`str`]): Optional. The dark colors of the accent color as HEX - value. - - Since Telegram gives no exact specification for the accent colors, future accent colors might - have a different data type. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - COLOR_000 = _AccentColor(identifier=0, name="red") - """Accent color 0. This color can be customized by app themes.""" - COLOR_001 = _AccentColor(identifier=1, name="orange") - """Accent color 1. This color can be customized by app themes.""" - COLOR_002 = _AccentColor(identifier=2, name="purple/violet") - """Accent color 2. This color can be customized by app themes.""" - COLOR_003 = _AccentColor(identifier=3, name="green") - """Accent color 3. This color can be customized by app themes.""" - COLOR_004 = _AccentColor(identifier=4, name="cyan") - """Accent color 4. This color can be customized by app themes.""" - COLOR_005 = _AccentColor(identifier=5, name="blue") - """Accent color 5. This color can be customized by app themes.""" - COLOR_006 = _AccentColor(identifier=6, name="pink") - """Accent color 6. This color can be customized by app themes.""" - COLOR_007 = _AccentColor( - identifier=7, light_colors=(0xE15052, 0xF9AE63), dark_colors=(0xFF9380, 0x992F37) - ) - """Accent color 7. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_008 = _AccentColor( - identifier=8, light_colors=(0xE0802B, 0xFAC534), dark_colors=(0xECB04E, 0xC35714) - ) - """Accent color 8. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_009 = _AccentColor( - identifier=9, light_colors=(0xA05FF3, 0xF48FFF), dark_colors=(0xC697FF, 0x5E31C8) - ) - """Accent color 9. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_010 = _AccentColor( - identifier=10, light_colors=(0x27A910, 0xA7DC57), dark_colors=(0xA7EB6E, 0x167E2D) - ) - """Accent color 10. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_011 = _AccentColor( - identifier=11, light_colors=(0x27ACCE, 0x82E8D6), dark_colors=(0x40D8D0, 0x045C7F) - ) - """Accent color 11. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - - COLOR_012 = _AccentColor( - identifier=12, light_colors=(0x3391D4, 0x7DD3F0), dark_colors=(0x52BFFF, 0x0B5494) - ) - """Accent color 12. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_013 = _AccentColor( - identifier=13, light_colors=(0xDD4371, 0xFFBE9F), dark_colors=(0xFF86A6, 0x8E366E) - ) - """Accent color 13. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_014 = _AccentColor( - identifier=14, - light_colors=(0x247BED, 0xF04856, 0xFFFFFF), - dark_colors=(0x3FA2FE, 0xE5424F, 0xFFFFFF), - ) - """Accent color 14. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_015 = _AccentColor( - identifier=15, - light_colors=(0xD67722, 0x1EA011, 0xFFFFFF), - dark_colors=(0xFF905E, 0x32A527, 0xFFFFFF), - ) - """Accent color 15. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_016 = _AccentColor( - identifier=16, - light_colors=(0x179E42, 0xE84A3F, 0xFFFFFF), - dark_colors=(0x66D364, 0xD5444F, 0xFFFFFF), - ) - """Accent color 16. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_017 = _AccentColor( - identifier=17, - light_colors=(0x2894AF, 0x6FC456, 0xFFFFFF), - dark_colors=(0x22BCE2, 0x3DA240, 0xFFFFFF), - ) - """Accent color 17. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_018 = _AccentColor( - identifier=18, - light_colors=(0x0C9AB3, 0xFFAD95, 0xFFE6B5), - dark_colors=(0x22BCE2, 0xFF9778, 0xFFDA6B), - ) - """Accent color 18. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_019 = _AccentColor( - identifier=19, - light_colors=(0x7757D6, 0xF79610, 0xFFDE8E), - dark_colors=(0x9791FF, 0xF2731D, 0xFFDB59), - ) - """Accent color 19. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - COLOR_020 = _AccentColor( - identifier=20, - light_colors=(0x1585CF, 0xF2AB1D, 0xFFFFFF), - dark_colors=(0x3DA6EB, 0xEEA51D, 0xFFFFFF), - ) - """Accent color 20. This contains three light colors - - .. raw:: html - -
-
-
-
-
-

- - and three dark colors - - .. raw:: html - -
-
-
-
-
-

- """ - - -class BackgroundTypeType(StringEnum): - """This enum contains the available types of :class:`telegram.BackgroundType`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.2 - """ - - __slots__ = () - - FILL = "fill" - """:obj:`str`: A :class:`telegram.BackgroundType` with fill background.""" - WALLPAPER = "wallpaper" - """:obj:`str`: A :class:`telegram.BackgroundType` with wallpaper background.""" - PATTERN = "pattern" - """:obj:`str`: A :class:`telegram.BackgroundType` with pattern background.""" - CHAT_THEME = "chat_theme" - """:obj:`str`: A :class:`telegram.BackgroundType` with chat_theme background.""" - - -class BackgroundFillType(StringEnum): - """This enum contains the available types of :class:`telegram.BackgroundFill`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.2 - """ - - __slots__ = () - - SOLID = "solid" - """:obj:`str`: A :class:`telegram.BackgroundFill` with solid fill.""" - GRADIENT = "gradient" - """:obj:`str`: A :class:`telegram.BackgroundFill` with gradient fill.""" - FREEFORM_GRADIENT = "freeform_gradient" - """:obj:`str`: A :class:`telegram.BackgroundFill` with freeform_gradient fill.""" - - -class BotCommandLimit(IntEnum): - """This enum contains limitations for :class:`telegram.BotCommand` and - :meth:`telegram.Bot.set_my_commands`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_COMMAND = 1 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.BotCommand.command` parameter of - :class:`telegram.BotCommand`. - """ - MAX_COMMAND = 32 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.BotCommand.command` parameter of - :class:`telegram.BotCommand`. - """ - MIN_DESCRIPTION = 1 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.BotCommand.description` - parameter of :class:`telegram.BotCommand`. - """ - MAX_DESCRIPTION = 256 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.BotCommand.description` - parameter of :class:`telegram.BotCommand`. - """ - MAX_COMMAND_NUMBER = 100 - """:obj:`int`: Maximum number of bot commands passed in a :obj:`list` to the - :paramref:`~telegram.Bot.set_my_commands.commands` - parameter of :meth:`telegram.Bot.set_my_commands`. - """ - - -class BotCommandScopeType(StringEnum): - """This enum contains the available types of :class:`telegram.BotCommandScope`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - DEFAULT = "default" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeDefault`.""" - ALL_PRIVATE_CHATS = "all_private_chats" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeAllPrivateChats`.""" - ALL_GROUP_CHATS = "all_group_chats" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeAllGroupChats`.""" - ALL_CHAT_ADMINISTRATORS = "all_chat_administrators" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeAllChatAdministrators`.""" - CHAT = "chat" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeChat`.""" - CHAT_ADMINISTRATORS = "chat_administrators" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeChatAdministrators`.""" - CHAT_MEMBER = "chat_member" - """:obj:`str`: The type of :class:`telegram.BotCommandScopeChatMember`.""" - - -class BotDescriptionLimit(IntEnum): - """This enum contains limitations for the methods :meth:`telegram.Bot.set_my_description` and - :meth:`telegram.Bot.set_my_short_description`. The enum members of this enumeration are - instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.2 - """ - - __slots__ = () - - MAX_DESCRIPTION_LENGTH = 512 - """:obj:`int`: Maximum length for the parameter - :paramref:`~telegram.Bot.set_my_description.description` of - :meth:`telegram.Bot.set_my_description` - """ - MAX_SHORT_DESCRIPTION_LENGTH = 120 - """:obj:`int`: Maximum length for the parameter - :paramref:`~telegram.Bot.set_my_short_description.short_description` of - :meth:`telegram.Bot.set_my_short_description` - """ - - -class BotNameLimit(IntEnum): - """This enum contains limitations for the methods :meth:`telegram.Bot.set_my_name`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.3 - """ - - __slots__ = () - - MAX_NAME_LENGTH = 64 - """:obj:`int`: Maximum length for the parameter :paramref:`~telegram.Bot.set_my_name.name` of - :meth:`telegram.Bot.set_my_name` - """ - - -class BulkRequestLimit(IntEnum): - """This enum contains limitations for :meth:`telegram.Bot.delete_messages`, - :meth:`telegram.Bot.forward_messages` and :meth:`telegram.Bot.copy_messages`. The enum members - of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - MIN_LIMIT = 1 - """:obj:`int`: Minimum number of messages required for bulk actions.""" - MAX_LIMIT = 100 - """:obj:`int`: Maximum number of messages required for bulk actions.""" - - -class CallbackQueryLimit(IntEnum): - """This enum contains limitations for :class:`telegram.CallbackQuery`/ - :meth:`telegram.Bot.answer_callback_query`. The enum members of this enumeration are instances - of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - ANSWER_CALLBACK_QUERY_TEXT_LENGTH = 200 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.answer_callback_query.text` parameter of - :meth:`telegram.Bot.answer_callback_query`.""" - - -class ChatAction(StringEnum): - """This enum contains the available chat actions for :meth:`telegram.Bot.send_chat_action`. - The enum members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - CHOOSE_STICKER = "choose_sticker" - """:obj:`str`: Chat action indicating that the bot is selecting a sticker.""" - FIND_LOCATION = "find_location" - """:obj:`str`: Chat action indicating that the bot is selecting a location.""" - RECORD_VOICE = "record_voice" - """:obj:`str`: Chat action indicating that the bot is recording a voice message.""" - RECORD_VIDEO = "record_video" - """:obj:`str`: Chat action indicating that the bot is recording a video.""" - RECORD_VIDEO_NOTE = "record_video_note" - """:obj:`str`: Chat action indicating that the bot is recording a video note.""" - TYPING = "typing" - """:obj:`str`: A chat indicating the bot is typing.""" - UPLOAD_VOICE = "upload_voice" - """:obj:`str`: Chat action indicating that the bot is uploading a voice message.""" - UPLOAD_DOCUMENT = "upload_document" - """:obj:`str`: Chat action indicating that the bot is uploading a document.""" - UPLOAD_PHOTO = "upload_photo" - """:obj:`str`: Chat action indicating that the bot is uploading a photo.""" - UPLOAD_VIDEO = "upload_video" - """:obj:`str`: Chat action indicating that the bot is uploading a video.""" - UPLOAD_VIDEO_NOTE = "upload_video_note" - """:obj:`str`: Chat action indicating that the bot is uploading a video note.""" - - -class ChatBoostSources(StringEnum): - """This enum contains the available sources for a - :class:`Telegram chat boost `. - The enum members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - GIFT_CODE = "gift_code" - """:obj:`str`: The source of the chat boost was a Telegram Premium gift code.""" - GIVEAWAY = "giveaway" - """:obj:`str`: The source of the chat boost was a Telegram Premium giveaway.""" - PREMIUM = "premium" - """:obj:`str`: The source of the chat boost was a Telegram Premium subscription/gift.""" - - -class ChatID(IntEnum): - """This enum contains some special chat IDs. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - ANONYMOUS_ADMIN = 1087968824 - """:obj:`int`: User ID in groups for messages sent by anonymous admins. Telegram chat: - `@GroupAnonymousBot `_. - - Note: - :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. - It's recommended to use :attr:`telegram.Message.sender_chat` instead. - """ - SERVICE_CHAT = 777000 - """:obj:`int`: Telegram service chat, that also acts as sender of channel posts forwarded to - discussion groups. Telegram chat: `Telegram `_. - - Note: - :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. - It's recommended to use :attr:`telegram.Message.sender_chat` instead. - """ - FAKE_CHANNEL = 136817688 - """:obj:`int`: User ID in groups when message is sent on behalf of a channel, or when a channel - votes on a poll. Telegram chat: `@Channel_Bot `_. - - Note: - * :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. - It's recommended to use :attr:`telegram.Message.sender_chat` instead. - * :attr:`telegram.PollAnswer.user` will contain this ID for backwards compatibility only. - It's recommended to use :attr:`telegram.PollAnswer.voter_chat` instead. - """ - - -class ChatInviteLinkLimit(IntEnum): - """This enum contains limitations for :class:`telegram.ChatInviteLink`/ - :meth:`telegram.Bot.create_chat_invite_link`/:meth:`telegram.Bot.edit_chat_invite_link`. The - enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_MEMBER_LIMIT = 1 - """:obj:`int`: Minimum value allowed for the - :paramref:`~telegram.Bot.create_chat_invite_link.member_limit` parameter of - :meth:`telegram.Bot.create_chat_invite_link` and - :paramref:`~telegram.Bot.edit_chat_invite_link.member_limit` of - :meth:`telegram.Bot.edit_chat_invite_link`. - """ - MAX_MEMBER_LIMIT = 99999 - """:obj:`int`: Maximum value allowed for the - :paramref:`~telegram.Bot.create_chat_invite_link.member_limit` parameter of - :meth:`telegram.Bot.create_chat_invite_link` and - :paramref:`~telegram.Bot.edit_chat_invite_link.member_limit` of - :meth:`telegram.Bot.edit_chat_invite_link`. - """ - NAME_LENGTH = 32 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.create_chat_invite_link.name` parameter of - :meth:`telegram.Bot.create_chat_invite_link` and - :paramref:`~telegram.Bot.edit_chat_invite_link.name` of - :meth:`telegram.Bot.edit_chat_invite_link`. - """ - - -class ChatLimit(IntEnum): - """This enum contains limitations for - :meth:`telegram.Bot.set_chat_administrator_custom_title`, - :meth:`telegram.Bot.set_chat_description`, and :meth:`telegram.Bot.set_chat_title`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - CHAT_ADMINISTRATOR_CUSTOM_TITLE_LENGTH = 16 - """:obj:`int`: Maximum length of a :obj:`str` passed as the - :paramref:`~telegram.Bot.set_chat_administrator_custom_title.custom_title` parameter of - :meth:`telegram.Bot.set_chat_administrator_custom_title`. - """ - CHAT_DESCRIPTION_LENGTH = 255 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.set_chat_description.description` parameter of - :meth:`telegram.Bot.set_chat_description`. - """ - MIN_CHAT_TITLE_LENGTH = 1 - """:obj:`int`: Minimum length of a :obj:`str` passed as the - :paramref:`~telegram.Bot.set_chat_title.title` parameter of - :meth:`telegram.Bot.set_chat_title`. - """ - MAX_CHAT_TITLE_LENGTH = 128 - """:obj:`int`: Maximum length of a :obj:`str` passed as the - :paramref:`~telegram.Bot.set_chat_title.title` parameter of - :meth:`telegram.Bot.set_chat_title`. - """ - - -class ChatSubscriptionLimit(IntEnum): - """This enum contains limitations for - :paramref:`telegram.Bot.create_chat_subscription_invite_link.subscription_period` and - :paramref:`telegram.Bot.create_chat_subscription_invite_link.subscription_price`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.5 - """ - - __slots__ = () - - SUBSCRIPTION_PERIOD = 2592000 - """:obj:`int`: The number of seconds the subscription will be active.""" - MIN_PRICE = 1 - """:obj:`int`: Amount of stars a user pays, minimum amount the subscription can be set to.""" - MAX_PRICE = 2500 - """:obj:`int`: Amount of stars a user pays, maximum amount the subscription can be set to.""" - - -class BackgroundTypeLimit(IntEnum): - """This enum contains limitations for :class:`telegram.BackgroundTypeFill`, - :class:`telegram.BackgroundTypeWallpaper` and :class:`telegram.BackgroundTypePattern`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.2 - """ - - __slots__ = () - - MAX_DIMMING = 100 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.BackgroundTypeFill.dark_theme_dimming` parameter of - :class:`telegram.BackgroundTypeFill` - * :paramref:`~telegram.BackgroundTypeWallpaper.dark_theme_dimming` parameter of - :class:`telegram.BackgroundTypeWallpaper` - """ - MAX_INTENSITY = 100 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.BackgroundTypePattern.intensity` - parameter of :class:`telegram.BackgroundTypePattern` - """ - - -class BackgroundFillLimit(IntEnum): - """This enum contains limitations for :class:`telegram.BackgroundFillGradient`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.2 - """ - - __slots__ = () - - MAX_ROTATION_ANGLE = 359 - """:obj:`int`: Maximum value allowed for: - :paramref:`~telegram.BackgroundFillGradient.rotation_angle` parameter of - :class:`telegram.BackgroundFillGradient` - """ - - -class ChatMemberStatus(StringEnum): - """This enum contains the available states for :class:`telegram.ChatMember`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - ADMINISTRATOR = "administrator" - """:obj:`str`: A :class:`telegram.ChatMember` who is administrator of the chat.""" - OWNER = "creator" - """:obj:`str`: A :class:`telegram.ChatMember` who is the owner of the chat.""" - BANNED = "kicked" - """:obj:`str`: A :class:`telegram.ChatMember` who was banned in the chat.""" - LEFT = "left" - """:obj:`str`: A :class:`telegram.ChatMember` who has left the chat.""" - MEMBER = "member" - """:obj:`str`: A :class:`telegram.ChatMember` who is a member of the chat.""" - RESTRICTED = "restricted" - """:obj:`str`: A :class:`telegram.ChatMember` who was restricted in this chat.""" - - -class ChatPhotoSize(IntEnum): - """This enum contains limitations for :class:`telegram.ChatPhoto`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - SMALL = 160 - """:obj:`int`: Width and height of a small chat photo, ID of which is passed in - :paramref:`~telegram.ChatPhoto.small_file_id` and - :paramref:`~telegram.ChatPhoto.small_file_unique_id` parameters of - :class:`telegram.ChatPhoto`. - """ - BIG = 640 - """:obj:`int`: Width and height of a big chat photo, ID of which is passed in - :paramref:`~telegram.ChatPhoto.big_file_id` and - :paramref:`~telegram.ChatPhoto.big_file_unique_id` parameters of - :class:`telegram.ChatPhoto`. - """ - - -class ChatType(StringEnum): - """This enum contains the available types of :class:`telegram.Chat`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - SENDER = "sender" - """:obj:`str`: A :class:`telegram.Chat` that represents the chat of a :class:`telegram.User` - sending an :class:`telegram.InlineQuery`. """ - PRIVATE = "private" - """:obj:`str`: A :class:`telegram.Chat` that is private.""" - GROUP = "group" - """:obj:`str`: A :class:`telegram.Chat` that is a group.""" - SUPERGROUP = "supergroup" - """:obj:`str`: A :class:`telegram.Chat` that is a supergroup.""" - CHANNEL = "channel" - """:obj:`str`: A :class:`telegram.Chat` that is a channel.""" - - -class ContactLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineQueryResultContact`, - :class:`telegram.InputContactMessageContent`, and :meth:`telegram.Bot.send_contact`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - VCARD = 2048 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.Bot.send_contact.vcard` parameter of :meth:`~telegram.Bot.send_contact` - * :paramref:`~telegram.InlineQueryResultContact.vcard` parameter of - :class:`~telegram.InlineQueryResultContact` - * :paramref:`~telegram.InputContactMessageContent.vcard` parameter of - :class:`~telegram.InputContactMessageContent` - """ - - -class CustomEmojiStickerLimit(IntEnum): - """This enum contains limitations for :meth:`telegram.Bot.get_custom_emoji_stickers`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - CUSTOM_EMOJI_IDENTIFIER_LIMIT = 200 - """:obj:`int`: Maximum amount of custom emoji identifiers which can be specified for the - :paramref:`~telegram.Bot.get_custom_emoji_stickers.custom_emoji_ids` parameter of - :meth:`telegram.Bot.get_custom_emoji_stickers`. - """ - - -class DiceEmoji(StringEnum): - """This enum contains the available emoji for :class:`telegram.Dice`/ - :meth:`telegram.Bot.send_dice`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - DICE = "🎲" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🎲``.""" - DARTS = "🎯" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🎯``.""" - BASKETBALL = "🏀" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🏀``.""" - FOOTBALL = "⚽" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``⚽``.""" - SLOT_MACHINE = "🎰" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🎰``.""" - BOWLING = "🎳" - """:obj:`str`: A :class:`telegram.Dice` with the emoji ``🎳``.""" - - -class DiceLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Dice`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_VALUE = 1 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` (any emoji). - """ - - MAX_VALUE_BASKETBALL = 5 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.BASKETBALL`. - """ - MAX_VALUE_BOWLING = 6 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.BOWLING`. - """ - MAX_VALUE_DARTS = 6 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.DARTS`. - """ - MAX_VALUE_DICE = 6 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.DICE`. - """ - MAX_VALUE_FOOTBALL = 5 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.FOOTBALL`. - """ - MAX_VALUE_SLOT_MACHINE = 64 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.Dice.value` parameter of - :class:`telegram.Dice` if :paramref:`~telegram.Dice.emoji` is - :tg-const:`telegram.constants.DiceEmoji.SLOT_MACHINE`. - """ - - -class FileSizeLimit(IntEnum): - """This enum contains limitations regarding the upload and download of files. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - FILESIZE_DOWNLOAD = int(20e6) # (20MB) - """:obj:`int`: Bots can download files of up to 20MB in size.""" - FILESIZE_UPLOAD = int(50e6) # (50MB) - """:obj:`int`: Bots can upload non-photo files of up to 50MB in size.""" - FILESIZE_UPLOAD_LOCAL_MODE = int(2e9) # (2000MB) - """:obj:`int`: Bots can upload non-photo files of up to 2000MB in size when using a local bot - API server. - """ - FILESIZE_DOWNLOAD_LOCAL_MODE = sys.maxsize - """:obj:`int`: Bots can download files without a size limit when using a local bot API server. - """ - PHOTOSIZE_UPLOAD = int(10e6) # (10MB) - """:obj:`int`: Bots can upload photo files of up to 10MB in size.""" - VOICE_NOTE_FILE_SIZE = int(1e6) # (1MB) - """:obj:`int`: File size limit for the :meth:`~telegram.Bot.send_voice` method of - :class:`telegram.Bot`. Bots can send :mimetype:`audio/ogg` files of up to 1MB in size as - a voice note. Larger voice notes (up to 20MB) will be sent as files.""" - # It seems OK to link 20MB limit to FILESIZE_DOWNLOAD rather than creating a new constant - - -class FloodLimit(IntEnum): - """This enum contains limitations regarding flood limits. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MESSAGES_PER_SECOND_PER_CHAT = 1 - """:obj:`int`: The number of messages that can be sent per second in a particular chat. - Telegram may allow short bursts that go over this limit, but eventually you'll begin - receiving 429 errors. - """ - MESSAGES_PER_SECOND = 30 - """:obj:`int`: The number of messages that can roughly be sent in an interval of 30 seconds - across all chats. - """ - MESSAGES_PER_MINUTE_PER_GROUP = 20 - """:obj:`int`: The number of messages that can roughly be sent to a particular group within one - minute. - """ - PAID_MESSAGES_PER_SECOND = 1000 - """:obj:`int`: The number of messages that can be sent per second when paying with the bot's - Telegram Star balance. See e.g. parameter - :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` of - :meth:`~telegram.Bot.send_message`. - - .. versionadded:: 21.7 - """ - - -class ForumIconColor(IntEnum): - """This enum contains the available colors for use in - :paramref:`telegram.Bot.create_forum_topic.icon_color`. The enum members of this enumeration - are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - BLUE = 0x6FB9F0 - """:obj:`int`: An icon with a color which corresponds to blue (``0x6FB9F0``). - - .. raw:: html - -
- - """ - YELLOW = 0xFFD67E - """:obj:`int`: An icon with a color which corresponds to yellow (``0xFFD67E``). - - .. raw:: html - -
- - """ - PURPLE = 0xCB86DB - """:obj:`int`: An icon with a color which corresponds to purple (``0xCB86DB``). - - .. raw:: html - -
- - """ - GREEN = 0x8EEE98 - """:obj:`int`: An icon with a color which corresponds to green (``0x8EEE98``). - - .. raw:: html - -
- - """ - PINK = 0xFF93B2 - """:obj:`int`: An icon with a color which corresponds to pink (``0xFF93B2``). - - .. raw:: html - -
- - """ - RED = 0xFB6F5F - """:obj:`int`: An icon with a color which corresponds to red (``0xFB6F5F``). - - .. raw:: html - -
- - """ - - -class GiftLimit(IntEnum): - """This enum contains limitations for :meth:`~telegram.Bot.send_gift`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.8 - """ - - __slots__ = () - - MAX_TEXT_LENGTH = 255 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.send_gift.text` parameter of :meth:`~telegram.Bot.send_gift`. - """ - - -class GiveawayLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Giveaway` and related classes. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - MAX_WINNERS = 100 - """:obj:`int`: Maximum number of winners allowed for :class:`telegram.GiveawayWinners.winners`. - """ - - -class KeyboardButtonRequestUsersLimit(IntEnum): - """This enum contains limitations for :class:`telegram.KeyboardButtonRequestUsers`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - MIN_QUANTITY = 1 - """:obj:`int`: Minimum value allowed for - :paramref:`~telegram.KeyboardButtonRequestUsers.max_quantity` parameter of - :class:`telegram.KeyboardButtonRequestUsers`. - """ - MAX_QUANTITY = 10 - """:obj:`int`: Maximum value allowed for - :paramref:`~telegram.KeyboardButtonRequestUsers.max_quantity` parameter of - :class:`telegram.KeyboardButtonRequestUsers`. - """ - - -class InlineKeyboardButtonLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineKeyboardButton`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_CALLBACK_DATA = 1 - """:obj:`int`: Minimum length allowed for - :paramref:`~telegram.InlineKeyboardButton.callback_data` parameter of - :class:`telegram.InlineKeyboardButton` - """ - MAX_CALLBACK_DATA = 64 - """:obj:`int`: Maximum length allowed for - :paramref:`~telegram.InlineKeyboardButton.callback_data` parameter of - :class:`telegram.InlineKeyboardButton` - """ - MIN_COPY_TEXT = 1 - """:obj:`int`: Minimum length allowed for - :paramref:`~telegram.CopyTextButton.text` parameter of :class:`telegram.CopyTextButton` - """ - MAX_COPY_TEXT = 256 - """:obj:`int`: Maximum length allowed for - :paramref:`~telegram.CopyTextButton.text` parameter of :class:`telegram.CopyTextButton` - """ - - -class InlineKeyboardMarkupLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineKeyboardMarkup`/ - :meth:`telegram.Bot.send_message` & friends. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - TOTAL_BUTTON_NUMBER = 100 - """:obj:`int`: Maximum number of buttons that can be attached to a message. - - Note: - This value is undocumented and might be changed by Telegram. - """ - BUTTONS_PER_ROW = 8 - """:obj:`int`: Maximum number of buttons that can be attached to a message per row. - - Note: - This value is undocumented and might be changed by Telegram. - """ - - -class InputMediaType(StringEnum): - """This enum contains the available types of :class:`telegram.InputMedia`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - ANIMATION = "animation" - """:obj:`str`: Type of :class:`telegram.InputMediaAnimation`.""" - DOCUMENT = "document" - """:obj:`str`: Type of :class:`telegram.InputMediaDocument`.""" - AUDIO = "audio" - """:obj:`str`: Type of :class:`telegram.InputMediaAudio`.""" - PHOTO = "photo" - """:obj:`str`: Type of :class:`telegram.InputMediaPhoto`.""" - VIDEO = "video" - """:obj:`str`: Type of :class:`telegram.InputMediaVideo`.""" - - -class InputPaidMediaType(StringEnum): - """This enum contains the available types of :class:`telegram.InputPaidMedia`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - PHOTO = "photo" - """:obj:`str`: Type of :class:`telegram.InputMediaPhoto`.""" - VIDEO = "video" - """:obj:`str`: Type of :class:`telegram.InputMediaVideo`.""" - - -class InlineQueryLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineQuery`/ - :meth:`telegram.Bot.answer_inline_query`. The enum members of this enumeration are instances - of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - RESULTS = 50 - """:obj:`int`: Maximum number of results that can be passed to - :meth:`telegram.Bot.answer_inline_query`.""" - MAX_OFFSET_LENGTH = 64 - """:obj:`int`: Maximum number of bytes in a :obj:`str` passed as the - :paramref:`~telegram.Bot.answer_inline_query.next_offset` parameter of - :meth:`telegram.Bot.answer_inline_query`.""" - MAX_QUERY_LENGTH = 256 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.InlineQuery.query` parameter of :class:`telegram.InlineQuery`.""" - MIN_SWITCH_PM_TEXT_LENGTH = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.answer_inline_query.switch_pm_parameter` parameter of - :meth:`telegram.Bot.answer_inline_query`. - - .. deprecated:: 20.3 - Deprecated in favor of :attr:`InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH`. - """ - MAX_SWITCH_PM_TEXT_LENGTH = 64 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.answer_inline_query.switch_pm_parameter` parameter of - :meth:`telegram.Bot.answer_inline_query`. - - .. deprecated:: 20.3 - Deprecated in favor of :attr:`InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH`. - """ - - -class InlineQueryResultLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineQueryResult` and its subclasses. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_ID_LENGTH = 1 - """:obj:`int`: Minimum number of bytes in a :obj:`str` passed as the - :paramref:`~telegram.InlineQueryResult.id` parameter of - :class:`telegram.InlineQueryResult` and its subclasses - """ - MAX_ID_LENGTH = 64 - """:obj:`int`: Maximum number of bytes in a :obj:`str` passed as the - :paramref:`~telegram.InlineQueryResult.id` parameter of - :class:`telegram.InlineQueryResult` and its subclasses - """ - - -class InlineQueryResultsButtonLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InlineQueryResultsButton`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.3 - """ - - __slots__ = () - - MIN_START_PARAMETER_LENGTH = InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.InlineQueryResultsButton.start_parameter` parameter of - :meth:`telegram.InlineQueryResultsButton`.""" - - MAX_START_PARAMETER_LENGTH = InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.InlineQueryResultsButton.start_parameter` parameter of - :meth:`telegram.InlineQueryResultsButton`.""" - - -class InlineQueryResultType(StringEnum): - """This enum contains the available types of :class:`telegram.InlineQueryResult`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - AUDIO = "audio" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultAudio` and - :class:`telegram.InlineQueryResultCachedAudio`. - """ - DOCUMENT = "document" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultDocument` and - :class:`telegram.InlineQueryResultCachedDocument`. - """ - GIF = "gif" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultGif` and - :class:`telegram.InlineQueryResultCachedGif`. - """ - MPEG4GIF = "mpeg4_gif" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultMpeg4Gif` and - :class:`telegram.InlineQueryResultCachedMpeg4Gif`. - """ - PHOTO = "photo" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultPhoto` and - :class:`telegram.InlineQueryResultCachedPhoto`. - """ - STICKER = "sticker" - """:obj:`str`: Type of and :class:`telegram.InlineQueryResultCachedSticker`.""" - VIDEO = "video" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultVideo` and - :class:`telegram.InlineQueryResultCachedVideo`. - """ - VOICE = "voice" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultVoice` and - :class:`telegram.InlineQueryResultCachedVoice`. - """ - ARTICLE = "article" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultArticle`.""" - CONTACT = "contact" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultContact`.""" - GAME = "game" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultGame`.""" - LOCATION = "location" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultLocation`.""" - VENUE = "venue" - """:obj:`str`: Type of :class:`telegram.InlineQueryResultVenue`.""" - - -class LocationLimit(IntEnum): - """This enum contains limitations for - :class:`telegram.Location`/:class:`telegram.ChatLocation`/ - :meth:`telegram.Bot.edit_message_live_location`/:meth:`telegram.Bot.send_location`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_CHAT_LOCATION_ADDRESS = 1 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.ChatLocation.address` parameter - of :class:`telegram.ChatLocation` - """ - MAX_CHAT_LOCATION_ADDRESS = 64 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.ChatLocation.address` parameter - of :class:`telegram.ChatLocation` - """ - - HORIZONTAL_ACCURACY = 1500 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.Location.horizontal_accuracy` parameter of :class:`telegram.Location` - * :paramref:`~telegram.InlineQueryResultLocation.horizontal_accuracy` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.horizontal_accuracy` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.horizontal_accuracy` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.horizontal_accuracy` parameter of - :meth:`telegram.Bot.send_location` - """ - - MIN_HEADING = 1 - """:obj:`int`: Minimum value allowed for: - - * :paramref:`~telegram.Location.heading` parameter of :class:`telegram.Location` - * :paramref:`~telegram.InlineQueryResultLocation.heading` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.heading` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.heading` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.heading` parameter of - :meth:`telegram.Bot.send_location` - """ - MAX_HEADING = 360 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.Location.heading` parameter of :class:`telegram.Location` - * :paramref:`~telegram.InlineQueryResultLocation.heading` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.heading` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.heading` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.heading` parameter of - :meth:`telegram.Bot.send_location` - """ - - MIN_LIVE_PERIOD = 60 - """:obj:`int`: Minimum value allowed for: - - * :paramref:`~telegram.InlineQueryResultLocation.live_period` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.live_period` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.live_period` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.live_period` parameter of - :meth:`telegram.Bot.send_location` - """ - MAX_LIVE_PERIOD = 86400 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.InlineQueryResultLocation.live_period` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.live_period` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.live_period` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.live_period` parameter of - :meth:`telegram.Bot.send_location` - """ - - LIVE_PERIOD_FOREVER = int(hex(0x7FFFFFFF), 16) - """:obj:`int`: Value for live locations that can be edited indefinitely. Passed in: - - * :paramref:`~telegram.InlineQueryResultLocation.live_period` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.live_period` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.live_period` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.live_period` parameter of - :meth:`telegram.Bot.send_location` - - .. versionadded:: 21.2 - """ - - MIN_PROXIMITY_ALERT_RADIUS = 1 - """:obj:`int`: Minimum value allowed for: - - * :paramref:`~telegram.InlineQueryResultLocation.proximity_alert_radius` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.proximity_alert_radius` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.proximity_alert_radius` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.proximity_alert_radius` parameter of - :meth:`telegram.Bot.send_location` - """ - MAX_PROXIMITY_ALERT_RADIUS = 100000 - """:obj:`int`: Maximum value allowed for: - - * :paramref:`~telegram.InlineQueryResultLocation.proximity_alert_radius` parameter of - :class:`telegram.InlineQueryResultLocation` - * :paramref:`~telegram.InputLocationMessageContent.proximity_alert_radius` parameter of - :class:`telegram.InputLocationMessageContent` - * :paramref:`~telegram.Bot.edit_message_live_location.proximity_alert_radius` parameter of - :meth:`telegram.Bot.edit_message_live_location` - * :paramref:`~telegram.Bot.send_location.proximity_alert_radius` parameter of - :meth:`telegram.Bot.send_location` - """ - - -class MaskPosition(StringEnum): - """This enum contains the available positions for :class:`telegram.MaskPosition`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - FOREHEAD = "forehead" - """:obj:`str`: Mask position for a sticker on the forehead.""" - EYES = "eyes" - """:obj:`str`: Mask position for a sticker on the eyes.""" - MOUTH = "mouth" - """:obj:`str`: Mask position for a sticker on the mouth.""" - CHIN = "chin" - """:obj:`str`: Mask position for a sticker on the chin.""" - - -class MediaGroupLimit(IntEnum): - """This enum contains limitations for :meth:`telegram.Bot.send_media_group`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_MEDIA_LENGTH = 2 - """:obj:`int`: Minimum length of a :obj:`list` passed as the - :paramref:`~telegram.Bot.send_media_group.media` parameter of - :meth:`telegram.Bot.send_media_group`. - """ - MAX_MEDIA_LENGTH = 10 - """:obj:`int`: Maximum length of a :obj:`list` passed as the - :paramref:`~telegram.Bot.send_media_group.media` parameter of - :meth:`telegram.Bot.send_media_group`. - """ - - -class MenuButtonType(StringEnum): - """This enum contains the available types of :class:`telegram.MenuButton`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - COMMANDS = "commands" - """:obj:`str`: The type of :class:`telegram.MenuButtonCommands`.""" - WEB_APP = "web_app" - """:obj:`str`: The type of :class:`telegram.MenuButtonWebApp`.""" - DEFAULT = "default" - """:obj:`str`: The type of :class:`telegram.MenuButtonDefault`.""" - - -class MessageAttachmentType(StringEnum): - """This enum contains the available types of :class:`telegram.Message` that can be seen - as attachment. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - # Make sure that all constants here are also listed in the MessageType Enum! - # (Enums are not extendable) - - ANIMATION = "animation" - """:obj:`str`: Messages with :attr:`telegram.Message.animation`.""" - AUDIO = "audio" - """:obj:`str`: Messages with :attr:`telegram.Message.audio`.""" - CONTACT = "contact" - """:obj:`str`: Messages with :attr:`telegram.Message.contact`.""" - DICE = "dice" - """:obj:`str`: Messages with :attr:`telegram.Message.dice`.""" - DOCUMENT = "document" - """:obj:`str`: Messages with :attr:`telegram.Message.document`.""" - GAME = "game" - """:obj:`str`: Messages with :attr:`telegram.Message.game`.""" - INVOICE = "invoice" - """:obj:`str`: Messages with :attr:`telegram.Message.invoice`.""" - LOCATION = "location" - """:obj:`str`: Messages with :attr:`telegram.Message.location`.""" - PAID_MEDIA = "paid_media" - """:obj:`str`: Messages with :attr:`telegram.Message.paid_media`. - - .. versionadded:: 21.4 - """ - PASSPORT_DATA = "passport_data" - """:obj:`str`: Messages with :attr:`telegram.Message.passport_data`.""" - PHOTO = "photo" - """:obj:`str`: Messages with :attr:`telegram.Message.photo`.""" - POLL = "poll" - """:obj:`str`: Messages with :attr:`telegram.Message.poll`.""" - STICKER = "sticker" - """:obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" - STORY = "story" - """:obj:`str`: Messages with :attr:`telegram.Message.story`.""" - SUCCESSFUL_PAYMENT = "successful_payment" - """:obj:`str`: Messages with :attr:`telegram.Message.successful_payment`.""" - VIDEO = "video" - """:obj:`str`: Messages with :attr:`telegram.Message.video`.""" - VIDEO_NOTE = "video_note" - """:obj:`str`: Messages with :attr:`telegram.Message.video_note`.""" - VOICE = "voice" - """:obj:`str`: Messages with :attr:`telegram.Message.voice`.""" - VENUE = "venue" - """:obj:`str`: Messages with :attr:`telegram.Message.venue`.""" - - -class MessageEntityType(StringEnum): - """This enum contains the available types of :class:`telegram.MessageEntity`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - BLOCKQUOTE = "blockquote" - """:obj:`str`: Message entities representing a block quotation. - - .. versionadded:: 20.8 - """ - BOLD = "bold" - """:obj:`str`: Message entities representing bold text.""" - BOT_COMMAND = "bot_command" - """:obj:`str`: Message entities representing a bot command.""" - CASHTAG = "cashtag" - """:obj:`str`: Message entities representing a cashtag.""" - CODE = "code" - """:obj:`str`: Message entities representing monowidth string.""" - CUSTOM_EMOJI = "custom_emoji" - """:obj:`str`: Message entities representing inline custom emoji stickers. - - .. versionadded:: 20.0 - """ - EMAIL = "email" - """:obj:`str`: Message entities representing a email.""" - EXPANDABLE_BLOCKQUOTE = "expandable_blockquote" - """:obj:`str`: Message entities representing collapsed-by-default block quotation. - - .. versionadded:: 21.3 - """ - HASHTAG = "hashtag" - """:obj:`str`: Message entities representing a hashtag.""" - ITALIC = "italic" - """:obj:`str`: Message entities representing italic text.""" - MENTION = "mention" - """:obj:`str`: Message entities representing a mention.""" - PHONE_NUMBER = "phone_number" - """:obj:`str`: Message entities representing a phone number.""" - PRE = "pre" - """:obj:`str`: Message entities representing monowidth block.""" - SPOILER = "spoiler" - """:obj:`str`: Message entities representing spoiler text.""" - STRIKETHROUGH = "strikethrough" - """:obj:`str`: Message entities representing strikethrough text.""" - TEXT_LINK = "text_link" - """:obj:`str`: Message entities representing clickable text URLs.""" - TEXT_MENTION = "text_mention" - """:obj:`str`: Message entities representing text mention for users without usernames.""" - UNDERLINE = "underline" - """:obj:`str`: Message entities representing underline text.""" - URL = "url" - """:obj:`str`: Message entities representing a url.""" - - -class MessageLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Message`/ - :class:`telegram.InputTextMessageContent`/ - :meth:`telegram.Bot.send_message` & friends. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - # TODO add links to params? - MAX_TEXT_LENGTH = 4096 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.Game.text` parameter of :class:`telegram.Game` - * :paramref:`~telegram.Message.text` parameter of :class:`telegram.Message` - * :paramref:`~telegram.InputTextMessageContent.message_text` parameter of - :class:`telegram.InputTextMessageContent` - * :paramref:`~telegram.Bot.send_message.text` parameter of :meth:`telegram.Bot.send_message` - * :paramref:`~telegram.Bot.edit_message_text.text` parameter of - :meth:`telegram.Bot.edit_message_text` - """ - CAPTION_LENGTH = 1024 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.Message.caption` parameter of :class:`telegram.Message` - * :paramref:`~telegram.InputMedia.caption` parameter of :class:`telegram.InputMedia` - and its subclasses - * ``caption`` parameter of subclasses of :class:`telegram.InlineQueryResult` - * ``caption`` parameter of :meth:`telegram.Bot.send_photo`, :meth:`telegram.Bot.send_audio`, - :meth:`telegram.Bot.send_document`, :meth:`telegram.Bot.send_video`, - :meth:`telegram.Bot.send_animation`, :meth:`telegram.Bot.send_voice`, - :meth:`telegram.Bot.edit_message_caption`, :meth:`telegram.Bot.copy_message` - """ - # constants above this line are tested - MIN_TEXT_LENGTH = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.InputTextMessageContent.message_text` parameter of - :class:`telegram.InputTextMessageContent` and the - :paramref:`~telegram.Bot.edit_message_text.text` parameter of - :meth:`telegram.Bot.edit_message_text`. - """ - DEEP_LINK_LENGTH = 64 - """:obj:`int`: Maximum number of characters for a deep link.""" - # TODO this constant is not used anywhere - MESSAGE_ENTITIES = 100 - """:obj:`int`: Maximum number of entities that can be displayed in a message. Further entities - will simply be ignored by Telegram. - - Note: - This value is undocumented and might be changed by Telegram. - """ - - -class MessageOriginType(StringEnum): - """This enum contains the available types of :class:`telegram.MessageOrigin`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - USER = "user" - """:obj:`str`: A :class:`telegram.MessageOrigin` who is sent by an user.""" - HIDDEN_USER = "hidden_user" - """:obj:`str`: A :class:`telegram.MessageOrigin` who is sent by a hidden user.""" - CHAT = "chat" - """:obj:`str`: A :class:`telegram.MessageOrigin` who is sent by a chat.""" - CHANNEL = "channel" - """:obj:`str`: A :class:`telegram.MessageOrigin` who is sent by a channel.""" - - -class MessageType(StringEnum): - """This enum contains the available types of :class:`telegram.Message`. Here, a "type" means - a kind of message that is visually distinct from other kinds of messages in the Telegram app. - In particular, auxiliary attributes that can be present for multiple types of messages are - not considered in this enumeration. - - The enum members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - # Make sure that all attachment type constants are also listed in the - # MessageAttachmentType Enum! (Enums are not extendable) - - ANIMATION = "animation" - """:obj:`str`: Messages with :attr:`telegram.Message.animation`.""" - AUDIO = "audio" - """:obj:`str`: Messages with :attr:`telegram.Message.audio`.""" - BOOST_ADDED = "boost_added" - """:obj:`str`: Messages with :attr:`telegram.Message.boost_added`. - - .. versionadded:: 21.0 - """ - BUSINESS_CONNECTION_ID = "business_connection_id" - """:obj:`str`: Messages with :attr:`telegram.Message.business_connection_id`. - - .. versionadded:: 21.1 - """ - CHANNEL_CHAT_CREATED = "channel_chat_created" - """:obj:`str`: Messages with :attr:`telegram.Message.channel_chat_created`.""" - CHAT_SHARED = "chat_shared" - """:obj:`str`: Messages with :attr:`telegram.Message.chat_shared`. - - .. versionadded:: 20.8 - """ - CHAT_BACKGROUND_SET = "chat_background_set" - """:obj:`str`: Messages with :attr:`telegram.Message.chat_background_set`. - - .. versionadded:: 21.2 - """ - CONNECTED_WEBSITE = "connected_website" - """:obj:`str`: Messages with :attr:`telegram.Message.connected_website`.""" - CONTACT = "contact" - """:obj:`str`: Messages with :attr:`telegram.Message.contact`.""" - DELETE_CHAT_PHOTO = "delete_chat_photo" - """:obj:`str`: Messages with :attr:`telegram.Message.delete_chat_photo`.""" - DICE = "dice" - """:obj:`str`: Messages with :attr:`telegram.Message.dice`.""" - DOCUMENT = "document" - """:obj:`str`: Messages with :attr:`telegram.Message.document`.""" - EFFECT_ID = "effect_id" - """:obj:`str`: Messages with :attr:`telegram.Message.effect_id`. - - .. versionadded:: 21.3""" - FORUM_TOPIC_CREATED = "forum_topic_created" - """:obj:`str`: Messages with :attr:`telegram.Message.forum_topic_created`. - - .. versionadded:: 20.8 - """ - FORUM_TOPIC_CLOSED = "forum_topic_closed" - """:obj:`str`: Messages with :attr:`telegram.Message.forum_topic_closed`. - - .. versionadded:: 20.8 - """ - FORUM_TOPIC_EDITED = "forum_topic_edited" - """:obj:`str`: Messages with :attr:`telegram.Message.forum_topic_edited`. - - .. versionadded:: 20.8 - """ - FORUM_TOPIC_REOPENED = "forum_topic_reopened" - """:obj:`str`: Messages with :attr:`telegram.Message.forum_topic_reopened`. - - .. versionadded:: 20.8 - """ - GAME = "game" - """:obj:`str`: Messages with :attr:`telegram.Message.game`.""" - GENERAL_FORUM_TOPIC_HIDDEN = "general_forum_topic_hidden" - """:obj:`str`: Messages with :attr:`telegram.Message.general_forum_topic_hidden`. - - .. versionadded:: 20.8 - """ - GENERAL_FORUM_TOPIC_UNHIDDEN = "general_forum_topic_unhidden" - """:obj:`str`: Messages with :attr:`telegram.Message.general_forum_topic_unhidden`. - - .. versionadded:: 20.8 - """ - GIVEAWAY = "giveaway" - """:obj:`str`: Messages with :attr:`telegram.Message.giveaway`. - - .. versionadded:: 20.8 - """ - GIVEAWAY_CREATED = "giveaway_created" - """:obj:`str`: Messages with :attr:`telegram.Message.giveaway_created`. - - .. versionadded:: 20.8 - """ - GIVEAWAY_WINNERS = "giveaway_winners" - """:obj:`str`: Messages with :attr:`telegram.Message.giveaway_winners`. - - .. versionadded:: 20.8 - """ - GIVEAWAY_COMPLETED = "giveaway_completed" - """:obj:`str`: Messages with :attr:`telegram.Message.giveaway_completed`. - - .. versionadded:: 20.8 - """ - GROUP_CHAT_CREATED = "group_chat_created" - """:obj:`str`: Messages with :attr:`telegram.Message.group_chat_created`.""" - INVOICE = "invoice" - """:obj:`str`: Messages with :attr:`telegram.Message.invoice`.""" - LEFT_CHAT_MEMBER = "left_chat_member" - """:obj:`str`: Messages with :attr:`telegram.Message.left_chat_member`.""" - LOCATION = "location" - """:obj:`str`: Messages with :attr:`telegram.Message.location`.""" - MESSAGE_AUTO_DELETE_TIMER_CHANGED = "message_auto_delete_timer_changed" - """:obj:`str`: Messages with :attr:`telegram.Message.message_auto_delete_timer_changed`.""" - MIGRATE_TO_CHAT_ID = "migrate_to_chat_id" - """:obj:`str`: Messages with :attr:`telegram.Message.migrate_to_chat_id`.""" - NEW_CHAT_MEMBERS = "new_chat_members" - """:obj:`str`: Messages with :attr:`telegram.Message.new_chat_members`.""" - NEW_CHAT_TITLE = "new_chat_title" - """:obj:`str`: Messages with :attr:`telegram.Message.new_chat_title`.""" - NEW_CHAT_PHOTO = "new_chat_photo" - """:obj:`str`: Messages with :attr:`telegram.Message.new_chat_photo`.""" - PAID_MEDIA = "paid_media" - """:obj:`str`: Messages with :attr:`telegram.Message.paid_media`. - - .. versionadded:: 21.4 - """ - PASSPORT_DATA = "passport_data" - """:obj:`str`: Messages with :attr:`telegram.Message.passport_data`.""" - PHOTO = "photo" - """:obj:`str`: Messages with :attr:`telegram.Message.photo`.""" - PINNED_MESSAGE = "pinned_message" - """:obj:`str`: Messages with :attr:`telegram.Message.pinned_message`.""" - POLL = "poll" - """:obj:`str`: Messages with :attr:`telegram.Message.poll`.""" - PROXIMITY_ALERT_TRIGGERED = "proximity_alert_triggered" - """:obj:`str`: Messages with :attr:`telegram.Message.proximity_alert_triggered`.""" - REFUNDED_PAYMENT = "refunded_payment" - """:obj:`str`: Messages with :attr:`telegram.Message.refunded_payment`. - - .. versionadded:: 21.4 - """ - REPLY_TO_STORY = "reply_to_story" - """:obj:`str`: Messages with :attr:`telegram.Message.reply_to_story`. - - .. versionadded:: 21.0 - """ - SENDER_BOOST_COUNT = "sender_boost_count" - """:obj:`str`: Messages with :attr:`telegram.Message.sender_boost_count`. - - .. versionadded:: 21.0 - """ - SENDER_BUSINESS_BOT = "sender_business_bot" - """:obj:`str`: Messages with :attr:`telegram.Message.sender_business_bot`. - - .. versionadded:: 21.1 - """ - STICKER = "sticker" - """:obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" - STORY = "story" - """:obj:`str`: Messages with :attr:`telegram.Message.story`.""" - SUPERGROUP_CHAT_CREATED = "supergroup_chat_created" - """:obj:`str`: Messages with :attr:`telegram.Message.supergroup_chat_created`.""" - SUCCESSFUL_PAYMENT = "successful_payment" - """:obj:`str`: Messages with :attr:`telegram.Message.successful_payment`.""" - TEXT = "text" - """:obj:`str`: Messages with :attr:`telegram.Message.text`.""" - USERS_SHARED = "users_shared" - """:obj:`str`: Messages with :attr:`telegram.Message.users_shared`. - - .. versionadded:: 20.8 - """ - VENUE = "venue" - """:obj:`str`: Messages with :attr:`telegram.Message.venue`.""" - VIDEO = "video" - """:obj:`str`: Messages with :attr:`telegram.Message.video`.""" - VIDEO_CHAT_SCHEDULED = "video_chat_scheduled" - """:obj:`str`: Messages with :attr:`telegram.Message.video_chat_scheduled`.""" - VIDEO_CHAT_STARTED = "video_chat_started" - """:obj:`str`: Messages with :attr:`telegram.Message.video_chat_started`.""" - VIDEO_CHAT_ENDED = "video_chat_ended" - """:obj:`str`: Messages with :attr:`telegram.Message.video_chat_ended`.""" - VIDEO_CHAT_PARTICIPANTS_INVITED = "video_chat_participants_invited" - """:obj:`str`: Messages with :attr:`telegram.Message.video_chat_participants_invited`.""" - VIDEO_NOTE = "video_note" - """:obj:`str`: Messages with :attr:`telegram.Message.video_note`.""" - VOICE = "voice" - """:obj:`str`: Messages with :attr:`telegram.Message.voice`.""" - WEB_APP_DATA = "web_app_data" - """:obj:`str`: Messages with :attr:`telegram.Message.web_app_data`. - - .. versionadded:: 20.8 - """ - WRITE_ACCESS_ALLOWED = "write_access_allowed" - """:obj:`str`: Messages with :attr:`telegram.Message.write_access_allowed`. - - .. versionadded:: 20.8 - """ - - -class PaidMediaType(StringEnum): - """ - This enum contains the available types of :class:`telegram.PaidMedia`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - PREVIEW = "preview" - """:obj:`str`: The type of :class:`telegram.PaidMediaPreview`.""" - VIDEO = "video" - """:obj:`str`: The type of :class:`telegram.PaidMediaVideo`.""" - PHOTO = "photo" - """:obj:`str`: The type of :class:`telegram.PaidMediaPhoto`.""" - - -class PollingLimit(IntEnum): - """This enum contains limitations for :paramref:`telegram.Bot.get_updates.limit`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_LIMIT = 1 - """:obj:`int`: Minimum value allowed for the :paramref:`~telegram.Bot.get_updates.limit` - parameter of :meth:`telegram.Bot.get_updates`. - """ - MAX_LIMIT = 100 - """:obj:`int`: Maximum value allowed for the :paramref:`~telegram.Bot.get_updates.limit` - parameter of :meth:`telegram.Bot.get_updates`. - """ - - -class ProfileAccentColor(Enum): - """This enum contains the available accent colors for - :class:`telegram.ChatFullInfo.profile_accent_color_id`. - The members of this enum are named tuples with the following attributes: - - - ``identifier`` (:obj:`int`): The identifier of the accent color. - - ``name`` (:obj:`str`): Optional. The name of the accent color. - - ``light_colors`` (tuple[:obj:`str`]): Optional. The light colors of the accent color as HEX - value. - - ``dark_colors`` (tuple[:obj:`str`]): Optional. The dark colors of the accent color as HEX - value. - - Since Telegram gives no exact specification for the accent colors, future accent colors might - have a different data type. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - COLOR_000 = _AccentColor(identifier=0, light_colors=(0xBA5650,), dark_colors=(0x9C4540,)) - """Accent color 0. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_001 = _AccentColor(identifier=1, light_colors=(0xC27C3E,), dark_colors=(0x945E2C,)) - """Accent color 1. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_002 = _AccentColor(identifier=2, light_colors=(0x956AC8,), dark_colors=(0x715099,)) - """Accent color 2. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_003 = _AccentColor(identifier=3, light_colors=(0x49A355,), dark_colors=(0x33713B,)) - """Accent color 3. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_004 = _AccentColor(identifier=4, light_colors=(0x3E97AD,), dark_colors=(0x387E87,)) - """Accent color 4. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_005 = _AccentColor(identifier=5, light_colors=(0x5A8FBB,), dark_colors=(0x477194,)) - """Accent color 5. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_006 = _AccentColor(identifier=6, light_colors=(0xB85378,), dark_colors=(0x944763,)) - """Accent color 6. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_007 = _AccentColor(identifier=7, light_colors=(0x7F8B95,), dark_colors=(0x435261,)) - """Accent color 7. This contains one light color - - .. raw:: html - -
-
- - and one dark color - - .. raw:: html - -
-
- """ - COLOR_008 = _AccentColor( - identifier=8, light_colors=(0xC9565D, 0xD97C57), dark_colors=(0x994343, 0xAC583E) - ) - """Accent color 8. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_009 = _AccentColor( - identifier=9, light_colors=(0xCF7244, 0xCC9433), dark_colors=(0x8F552F, 0xA17232) - ) - """Accent color 9. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_010 = _AccentColor( - identifier=10, light_colors=(0x9662D4, 0xB966B6), dark_colors=(0x634691, 0x9250A2) - ) - """Accent color 10. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_011 = _AccentColor( - identifier=11, light_colors=(0x3D9755, 0x89A650), dark_colors=(0x296A43, 0x5F8F44) - ) - """Accent color 11. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_012 = _AccentColor( - identifier=12, light_colors=(0x3D95BA, 0x50AD98), dark_colors=(0x306C7C, 0x3E987E) - ) - """Accent color 12. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_013 = _AccentColor( - identifier=13, light_colors=(0x538BC2, 0x4DA8BD), dark_colors=(0x38618C, 0x458BA1) - ) - """Accent color 13. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_014 = _AccentColor( - identifier=14, light_colors=(0xB04F74, 0xD1666D), dark_colors=(0x884160, 0xA65259) - ) - """Accent color 14. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - COLOR_015 = _AccentColor( - identifier=15, light_colors=(0x637482, 0x7B8A97), dark_colors=(0x53606E, 0x384654) - ) - """Accent color 15. This contains two light colors - - .. raw:: html - -
-
-
-

- - and two dark colors - - .. raw:: html - -
-
-
-

- """ - - -class ReplyLimit(IntEnum): - """This enum contains limitations for :class:`telegram.ForceReply` - and :class:`telegram.ReplyKeyboardMarkup`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_INPUT_FIELD_PLACEHOLDER = 1 - """:obj:`int`: Minimum value allowed for - :paramref:`~telegram.ForceReply.input_field_placeholder` parameter of - :class:`telegram.ForceReply` and - :paramref:`~telegram.ReplyKeyboardMarkup.input_field_placeholder` parameter of - :class:`telegram.ReplyKeyboardMarkup` - """ - MAX_INPUT_FIELD_PLACEHOLDER = 64 - """:obj:`int`: Maximum value allowed for - :paramref:`~telegram.ForceReply.input_field_placeholder` parameter of - :class:`telegram.ForceReply` and - :paramref:`~telegram.ReplyKeyboardMarkup.input_field_placeholder` parameter of - :class:`telegram.ReplyKeyboardMarkup` - """ - - -class RevenueWithdrawalStateType(StringEnum): - """This enum contains the available types of :class:`telegram.RevenueWithdrawalState`. - The enum members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - PENDING = "pending" - """:obj:`str`: A withdrawal in progress.""" - SUCCEEDED = "succeeded" - """:obj:`str`: A withdrawal succeeded.""" - FAILED = "failed" - """:obj:`str`: A withdrawal failed and the transaction was refunded.""" - - -class StarTransactions(FloatEnum): - """This enum contains constants for :class:`telegram.StarTransaction`. - The enum members of this enumeration are instances of :class:`float` and can be treated as - such. - - .. versionadded:: 21.9 - """ - - __slots__ = () - - NANOSTAR_VALUE = 1 / 1000000000 - """:obj:`float`: The value of one nanostar as used in - :attr:`telegram.StarTransaction.nanostar_amount`. - """ - - -class StarTransactionsLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Bot.get_star_transactions` and - :class:`telegram.StarTransaction`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - MIN_LIMIT = 1 - """:obj:`int`: Minimum value allowed for the - :paramref:`~telegram.Bot.get_star_transactions.limit` parameter of - :meth:`telegram.Bot.get_star_transactions`.""" - MAX_LIMIT = 100 - """:obj:`int`: Maximum value allowed for the - :paramref:`~telegram.Bot.get_star_transactions.limit` parameter of - :meth:`telegram.Bot.get_star_transactions`.""" - NANOSTAR_MIN_AMOUNT = -999999999 - """:obj:`int`: Minimum value allowed for :paramref:`~telegram.AffiliateInfo.nanostar_amount` - parameter of :class:`telegram.AffiliateInfo`. - - .. versionadded:: 21.9 - """ - NANOSTAR_MAX_AMOUNT = 999999999 - """:obj:`int`: Maximum value allowed for :paramref:`~telegram.StarTransaction.nanostar_amount` - parameter of :class:`telegram.StarTransaction` and - :paramref:`~telegram.AffiliateInfo.nanostar_amount` parameter of - :class:`telegram.AffiliateInfo`. - - .. versionadded:: 21.9 - """ - - -class StickerFormat(StringEnum): - """This enum contains the available formats of :class:`telegram.Sticker` in the set. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.2 - """ - - __slots__ = () - - STATIC = "static" - """:obj:`str`: Static sticker.""" - ANIMATED = "animated" - """:obj:`str`: Animated sticker.""" - VIDEO = "video" - """:obj:`str`: Video sticker.""" - - -class StickerLimit(IntEnum): - """This enum contains limitations for various sticker methods, such as - :meth:`telegram.Bot.create_new_sticker_set`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_NAME_AND_TITLE = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.create_new_sticker_set.name` parameter or the - :paramref:`~telegram.Bot.create_new_sticker_set.title` parameter of - :meth:`telegram.Bot.create_new_sticker_set`. - """ - MAX_NAME_AND_TITLE = 64 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.create_new_sticker_set.name` parameter or the - :paramref:`~telegram.Bot.create_new_sticker_set.title` parameter of - :meth:`telegram.Bot.create_new_sticker_set`. - """ - MIN_STICKER_EMOJI = 1 - """:obj:`int`: Minimum number of emojis associated with a sticker, passed as the - :paramref:`~telegram.Bot.setStickerEmojiList.emoji_list` parameter of - :meth:`telegram.Bot.set_sticker_emoji_list`. - - .. versionadded:: 20.2 - """ - MAX_STICKER_EMOJI = 20 - """:obj:`int`: Maximum number of emojis associated with a sticker, passed as the - :paramref:`~telegram.Bot.setStickerEmojiList.emoji_list` parameter of - :meth:`telegram.Bot.set_sticker_emoji_list`. - - .. versionadded:: 20.2 - """ - MAX_SEARCH_KEYWORDS = 20 - """:obj:`int`: Maximum number of search keywords for a sticker, passed as the - :paramref:`~telegram.Bot.set_sticker_keywords.keywords` parameter of - :meth:`telegram.Bot.set_sticker_keywords`. - - .. versionadded:: 20.2 - """ - MAX_KEYWORD_LENGTH = 64 - """:obj:`int`: Maximum number of characters in a search keyword for a sticker, for each item in - :paramref:`~telegram.Bot.set_sticker_keywords.keywords` sequence of - :meth:`telegram.Bot.set_sticker_keywords`. - - .. versionadded:: 20.2 - """ - - -class StickerSetLimit(IntEnum): - """This enum contains limitations for various sticker set methods, such as - :meth:`telegram.Bot.create_new_sticker_set` and :meth:`telegram.Bot.add_sticker_to_set`. - - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.2 - """ - - __slots__ = () - - MIN_INITIAL_STICKERS = 1 - """:obj:`int`: Minimum number of stickers needed to create a sticker set, passed as the - :paramref:`~telegram.Bot.create_new_sticker_set.stickers` parameter of - :meth:`telegram.Bot.create_new_sticker_set`. - """ - MAX_INITIAL_STICKERS = 50 - """:obj:`int`: Maximum number of stickers allowed while creating a sticker set, passed as the - :paramref:`~telegram.Bot.create_new_sticker_set.stickers` parameter of - :meth:`telegram.Bot.create_new_sticker_set`. - """ - MAX_EMOJI_STICKERS = 200 - """:obj:`int`: Maximum number of stickers allowed in an emoji sticker set, as given in - :meth:`telegram.Bot.add_sticker_to_set`. - """ - MAX_ANIMATED_STICKERS = 50 - """:obj:`int`: Maximum number of stickers allowed in an animated or video sticker set, as given - in :meth:`telegram.Bot.add_sticker_to_set`. - - .. deprecated:: 21.1 - The animated sticker limit is now 120, the same as :attr:`MAX_STATIC_STICKERS`. - """ - MAX_STATIC_STICKERS = 120 - """:obj:`int`: Maximum number of stickers allowed in a static sticker set, as given in - :meth:`telegram.Bot.add_sticker_to_set`. - """ - MAX_STATIC_THUMBNAIL_SIZE = 128 - """:obj:`int`: Maximum size of the thumbnail if it is a **.WEBP** or **.PNG** in kilobytes, - as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`.""" - MAX_ANIMATED_THUMBNAIL_SIZE = 32 - """:obj:`int`: Maximum size of the thumbnail if it is a **.TGS** or **.WEBM** in kilobytes, - as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`.""" - STATIC_THUMB_DIMENSIONS = 100 - """:obj:`int`: Exact height and width of the thumbnail if it is a **.WEBP** or **.PNG** in - pixels, as given in :meth:`telegram.Bot.set_sticker_set_thumbnail`.""" - - -class StickerType(StringEnum): - """This enum contains the available types of :class:`telegram.Sticker`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - REGULAR = "regular" - """:obj:`str`: Regular sticker.""" - MASK = "mask" - """:obj:`str`: Mask sticker.""" - CUSTOM_EMOJI = "custom_emoji" - """:obj:`str`: Custom emoji sticker.""" - - -class TransactionPartnerType(StringEnum): - """This enum contains the available types of :class:`telegram.TransactionPartner`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 21.4 - """ - - __slots__ = () - - AFFILIATE_PROGRAM = "affiliate_program" - """:obj:`str`: Transaction with Affiliate Program. - - .. versionadded:: 21.9 - """ - FRAGMENT = "fragment" - """:obj:`str`: Withdrawal transaction with Fragment.""" - OTHER = "other" - """:obj:`str`: Transaction with unknown source or recipient.""" - TELEGRAM_ADS = "telegram_ads" - """:obj:`str`: Transaction with Telegram Ads.""" - TELEGRAM_API = "telegram_api" - """:obj:`str`: Transaction with with payment for - `paid broadcasting `_. - - ..versionadded:: 21.7 - """ - USER = "user" - """:obj:`str`: Transaction with a user.""" - - -class ParseMode(StringEnum): - """This enum contains the available parse modes. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MARKDOWN = "Markdown" - """:obj:`str`: Markdown parse mode. - - Note: - :attr:`MARKDOWN` is a legacy mode, retained by Telegram for backward compatibility. - You should use :attr:`MARKDOWN_V2` instead. - """ - MARKDOWN_V2 = "MarkdownV2" - """:obj:`str`: Markdown parse mode version 2.""" - HTML = "HTML" - """:obj:`str`: HTML parse mode.""" - - -class PollLimit(IntEnum): - """This enum contains limitations for :class:`telegram.Poll`/:class:`telegram.PollOption`/ - :meth:`telegram.Bot.send_poll`. The enum - members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_QUESTION_LENGTH = 1 - """:obj:`int`: Minimum value allowed for the :paramref:`~telegram.Poll.question` - parameter of :class:`telegram.Poll` and the :paramref:`~telegram.Bot.send_poll.question` - parameter of :meth:`telegram.Bot.send_poll`. - """ - MAX_QUESTION_LENGTH = 300 - """:obj:`int`: Maximum value allowed for the :paramref:`~telegram.Poll.question` - parameter of :class:`telegram.Poll` and the :paramref:`~telegram.Bot.send_poll.question` - parameter of :meth:`telegram.Bot.send_poll`. - """ - MIN_OPTION_LENGTH = 1 - """:obj:`int`: Minimum length of each :obj:`str` passed in a :obj:`list` - to the :paramref:`~telegram.Bot.send_poll.options` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MAX_OPTION_LENGTH = 100 - """:obj:`int`: Maximum length of each :obj:`str` passed in a :obj:`list` - to the :paramref:`~telegram.Bot.send_poll.options` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MIN_OPTION_NUMBER = 2 - """:obj:`int`: Minimum number of strings passed in a :obj:`list` - to the :paramref:`~telegram.Bot.send_poll.options` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MAX_OPTION_NUMBER = 10 - """:obj:`int`: Maximum number of strings passed in a :obj:`list` - to the :paramref:`~telegram.Bot.send_poll.options` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MAX_EXPLANATION_LENGTH = 200 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Poll.explanation` parameter of :class:`telegram.Poll` and the - :paramref:`~telegram.Bot.send_poll.explanation` parameter of :meth:`telegram.Bot.send_poll`. - """ - MAX_EXPLANATION_LINE_FEEDS = 2 - """:obj:`int`: Maximum number of line feeds in a :obj:`str` passed as the - :paramref:`~telegram.Bot.send_poll.explanation` parameter of :meth:`telegram.Bot.send_poll` - after entities parsing. - """ - MIN_OPEN_PERIOD = 5 - """:obj:`int`: Minimum value allowed for the - :paramref:`~telegram.Bot.send_poll.open_period` parameter of :meth:`telegram.Bot.send_poll`. - Also used in the :paramref:`~telegram.Bot.send_poll.close_date` parameter of - :meth:`telegram.Bot.send_poll`. - """ - MAX_OPEN_PERIOD = 600 - """:obj:`int`: Maximum value allowed for the - :paramref:`~telegram.Bot.send_poll.open_period` parameter of :meth:`telegram.Bot.send_poll`. - Also used in the :paramref:`~telegram.Bot.send_poll.close_date` parameter of - :meth:`telegram.Bot.send_poll`. - """ - - -class PollType(StringEnum): - """This enum contains the available types for :class:`telegram.Poll`/ - :meth:`telegram.Bot.send_poll`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - REGULAR = "regular" - """:obj:`str`: regular polls.""" - QUIZ = "quiz" - """:obj:`str`: quiz polls.""" - - -class UpdateType(StringEnum): - """This enum contains the available types of :class:`telegram.Update`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MESSAGE = "message" - """:obj:`str`: Updates with :attr:`telegram.Update.message`.""" - EDITED_MESSAGE = "edited_message" - """:obj:`str`: Updates with :attr:`telegram.Update.edited_message`.""" - CHANNEL_POST = "channel_post" - """:obj:`str`: Updates with :attr:`telegram.Update.channel_post`.""" - EDITED_CHANNEL_POST = "edited_channel_post" - """:obj:`str`: Updates with :attr:`telegram.Update.edited_channel_post`.""" - INLINE_QUERY = "inline_query" - """:obj:`str`: Updates with :attr:`telegram.Update.inline_query`.""" - CHOSEN_INLINE_RESULT = "chosen_inline_result" - """:obj:`str`: Updates with :attr:`telegram.Update.chosen_inline_result`.""" - CALLBACK_QUERY = "callback_query" - """:obj:`str`: Updates with :attr:`telegram.Update.callback_query`.""" - SHIPPING_QUERY = "shipping_query" - """:obj:`str`: Updates with :attr:`telegram.Update.shipping_query`.""" - PRE_CHECKOUT_QUERY = "pre_checkout_query" - """:obj:`str`: Updates with :attr:`telegram.Update.pre_checkout_query`.""" - POLL = "poll" - """:obj:`str`: Updates with :attr:`telegram.Update.poll`.""" - POLL_ANSWER = "poll_answer" - """:obj:`str`: Updates with :attr:`telegram.Update.poll_answer`.""" - MY_CHAT_MEMBER = "my_chat_member" - """:obj:`str`: Updates with :attr:`telegram.Update.my_chat_member`.""" - CHAT_MEMBER = "chat_member" - """:obj:`str`: Updates with :attr:`telegram.Update.chat_member`.""" - CHAT_JOIN_REQUEST = "chat_join_request" - """:obj:`str`: Updates with :attr:`telegram.Update.chat_join_request`.""" - CHAT_BOOST = "chat_boost" - """:obj:`str`: Updates with :attr:`telegram.Update.chat_boost`. - - .. versionadded:: 20.8 - """ - REMOVED_CHAT_BOOST = "removed_chat_boost" - """:obj:`str`: Updates with :attr:`telegram.Update.removed_chat_boost`. - - .. versionadded:: 20.8 - """ - MESSAGE_REACTION = "message_reaction" - """:obj:`str`: Updates with :attr:`telegram.Update.message_reaction`. - - .. versionadded:: 20.8 - """ - MESSAGE_REACTION_COUNT = "message_reaction_count" - """:obj:`str`: Updates with :attr:`telegram.Update.message_reaction_count`. - - .. versionadded:: 20.8 - """ - BUSINESS_CONNECTION = "business_connection" - """:obj:`str`: Updates with :attr:`telegram.Update.business_connection`. - - .. versionadded:: 21.1 - """ - BUSINESS_MESSAGE = "business_message" - """:obj:`str`: Updates with :attr:`telegram.Update.business_message`. - - .. versionadded:: 21.1 - """ - EDITED_BUSINESS_MESSAGE = "edited_business_message" - """:obj:`str`: Updates with :attr:`telegram.Update.edited_business_message`. - - .. versionadded:: 21.1 - """ - DELETED_BUSINESS_MESSAGES = "deleted_business_messages" - """:obj:`str`: Updates with :attr:`telegram.Update.deleted_business_messages`. - - .. versionadded:: 21.1 - """ - PURCHASED_PAID_MEDIA = "purchased_paid_media" - """:obj:`str`: Updates with :attr:`telegram.Update.purchased_paid_media`. - - .. versionadded:: 21.6 - """ - - -class InvoiceLimit(IntEnum): - """This enum contains limitations for :class:`telegram.InputInvoiceMessageContent`, - :meth:`telegram.Bot.send_invoice`, and :meth:`telegram.Bot.create_invoice_link`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_TITLE_LENGTH = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.title` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.title` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.title` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MAX_TITLE_LENGTH = 32 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.title` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.title` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.title` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MIN_DESCRIPTION_LENGTH = 1 - """:obj:`int`: Minimum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.description` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.description` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.description` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MAX_DESCRIPTION_LENGTH = 255 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.description` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.description` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.description` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MIN_PAYLOAD_LENGTH = 1 - """:obj:`int`: Minimum amount of bytes in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.payload` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.payload` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.payload` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MAX_PAYLOAD_LENGTH = 128 - """:obj:`int`: Maximum amount of bytes in a :obj:`str` passed as: - - * :paramref:`~telegram.InputInvoiceMessageContent.payload` parameter of - :class:`telegram.InputInvoiceMessageContent` - * :paramref:`~telegram.Bot.send_invoice.payload` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.payload` parameter of - :meth:`telegram.Bot.create_invoice_link`. - * :paramref:`~telegram.Bot.send_paid_media.payload` parameter of - :meth:`telegram.Bot.send_paid_media`. - """ - MAX_TIP_AMOUNTS = 4 - """:obj:`int`: Maximum length of a :obj:`Sequence` passed as: - - * :paramref:`~telegram.Bot.send_invoice.suggested_tip_amounts` parameter of - :meth:`telegram.Bot.send_invoice`. - * :paramref:`~telegram.Bot.create_invoice_link.suggested_tip_amounts` parameter of - :meth:`telegram.Bot.create_invoice_link`. - """ - MIN_STAR_COUNT = 1 - """:obj:`int`: Minimum amount of starts that must be paid to buy access to a paid media - passed as :paramref:`~telegram.Bot.send_paid_media.star_count` parameter of - :meth:`telegram.Bot.send_paid_media`. - - .. versionadded:: 21.6 - """ - MAX_STAR_COUNT = 2500 - """:obj:`int`: Maximum amount of starts that must be paid to buy access to a paid media - passed as :paramref:`~telegram.Bot.send_paid_media.star_count` parameter of - :meth:`telegram.Bot.send_paid_media`. - - .. versionadded:: 21.6 - """ - SUBSCRIPTION_PERIOD = dtm.timedelta(days=30).total_seconds() - """:obj:`int`: The period of time for which the subscription is active before - the next payment, passed as :paramref:`~telegram.Bot.create_invoice_link.subscription_period` - parameter of :meth:`telegram.Bot.create_invoice_link`. - - .. versionadded:: 21.8 - """ - SUBSCRIPTION_MAX_PRICE = 2500 - """:obj:`int`: The maximum price of a subscription created wtih - :meth:`telegram.Bot.create_invoice_link`. - - .. versionadded:: 21.9 - """ - - -class UserProfilePhotosLimit(IntEnum): - """This enum contains limitations for :paramref:`telegram.Bot.get_user_profile_photos.limit`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_LIMIT = 1 - """:obj:`int`: Minimum value allowed for - :paramref:`~telegram.Bot.get_user_profile_photos.limit` parameter of - :meth:`telegram.Bot.get_user_profile_photos`. - """ - MAX_LIMIT = 100 - """:obj:`int`: Maximum value allowed for - :paramref:`~telegram.Bot.get_user_profile_photos.limit` parameter of - :meth:`telegram.Bot.get_user_profile_photos`. - """ - - -class WebhookLimit(IntEnum): - """This enum contains limitations for :paramref:`telegram.Bot.set_webhook.max_connections` and - :paramref:`telegram.Bot.set_webhook.secret_token`. The enum members of this enumeration are - instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_CONNECTIONS_LIMIT = 1 - """:obj:`int`: Minimum value allowed for the - :paramref:`~telegram.Bot.set_webhook.max_connections` parameter of - :meth:`telegram.Bot.set_webhook`. - """ - MAX_CONNECTIONS_LIMIT = 100 - """:obj:`int`: Maximum value allowed for the - :paramref:`~telegram.Bot.set_webhook.max_connections` parameter of - :meth:`telegram.Bot.set_webhook`. - """ - MIN_SECRET_TOKEN_LENGTH = 1 - """:obj:`int`: Minimum length of the secret token for the - :paramref:`~telegram.Bot.set_webhook.secret_token` parameter of - :meth:`telegram.Bot.set_webhook`. - """ - MAX_SECRET_TOKEN_LENGTH = 256 - """:obj:`int`: Maximum length of the secret token for the - :paramref:`~telegram.Bot.set_webhook.secret_token` parameter of - :meth:`telegram.Bot.set_webhook`. - """ - - -class ForumTopicLimit(IntEnum): - """This enum contains limitations for :paramref:`telegram.Bot.create_forum_topic.name` and - :paramref:`telegram.Bot.edit_forum_topic.name`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - MIN_NAME_LENGTH = 1 - """:obj:`int`: Minimum length of a :obj:`str` passed as: - - * :paramref:`~telegram.Bot.create_forum_topic.name` parameter of - :meth:`telegram.Bot.create_forum_topic` - * :paramref:`~telegram.Bot.edit_forum_topic.name` parameter of - :meth:`telegram.Bot.edit_forum_topic` - * :paramref:`~telegram.Bot.edit_general_forum_topic.name` parameter of - :meth:`telegram.Bot.edit_general_forum_topic` - """ - MAX_NAME_LENGTH = 128 - """:obj:`int`: Maximum length of a :obj:`str` passed as: - - * :paramref:`~telegram.Bot.create_forum_topic.name` parameter of - :meth:`telegram.Bot.create_forum_topic` - * :paramref:`~telegram.Bot.edit_forum_topic.name` parameter of - :meth:`telegram.Bot.edit_forum_topic` - * :paramref:`~telegram.Bot.edit_general_forum_topic.name` parameter of - :meth:`telegram.Bot.edit_general_forum_topic` - """ - - -class ReactionType(StringEnum): - """This enum contains the available types of :class:`telegram.ReactionType`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - EMOJI = "emoji" - """:obj:`str`: A :class:`telegram.ReactionType` with a normal emoji.""" - CUSTOM_EMOJI = "custom_emoji" - """:obj:`str`: A :class:`telegram.ReactionType` with a custom emoji.""" - PAID = "paid" - """:obj:`str`: A :class:`telegram.ReactionType` with a paid reaction. - - .. versionadded:: 21.5 - """ - - -class ReactionEmoji(StringEnum): - """This enum contains the available emojis of :class:`telegram.ReactionTypeEmoji`. The enum - members of this enumeration are instances of :class:`str` and can be treated as such. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - THUMBS_UP = "👍" - """:obj:`str`: Thumbs Up""" - THUMBS_DOWN = "👎" - """:obj:`str`: Thumbs Down""" - RED_HEART = "❤" - """:obj:`str`: Red Heart""" - FIRE = "🔥" - """:obj:`str`: Fire""" - SMILING_FACE_WITH_HEARTS = "🥰" - """:obj:`str`: Smiling Face with Hearts""" - CLAPPING_HANDS = "👏" - """:obj:`str`: Clapping Hands""" - GRINNING_FACE_WITH_SMILING_EYES = "😁" - """:obj:`str`: Grinning face with smiling eyes""" - THINKING_FACE = "🤔" - """:obj:`str`: Thinking face""" - SHOCKED_FACE_WITH_EXPLODING_HEAD = "🤯" - """:obj:`str`: Shocked face with exploding head""" - FACE_SCREAMING_IN_FEAR = "😱" - """:obj:`str`: Face screaming in fear""" - SERIOUS_FACE_WITH_SYMBOLS_COVERING_MOUTH = "🤬" - """:obj:`str`: Serious face with symbols covering mouth""" - CRYING_FACE = "😢" - """:obj:`str`: Crying face""" - PARTY_POPPER = "🎉" - """:obj:`str`: Party popper""" - GRINNING_FACE_WITH_STAR_EYES = "🤩" - """:obj:`str`: Grinning face with star eyes""" - FACE_WITH_OPEN_MOUTH_VOMITING = "🤮" - """:obj:`str`: Face with open mouth vomiting""" - PILE_OF_POO = "💩" - """:obj:`str`: Pile of poo""" - PERSON_WITH_FOLDED_HANDS = "🙏" - """:obj:`str`: Person with folded hands""" - OK_HAND_SIGN = "👌" - """:obj:`str`: Ok hand sign""" - DOVE_OF_PEACE = "🕊" - """:obj:`str`: Dove of peace""" - CLOWN_FACE = "🤡" - """:obj:`str`: Clown face""" - YAWNING_FACE = "🥱" - """:obj:`str`: Yawning face""" - FACE_WITH_UNEVEN_EYES_AND_WAVY_MOUTH = "🥴" - """:obj:`str`: Face with uneven eyes and wavy mouth""" - SMILING_FACE_WITH_HEART_SHAPED_EYES = "😍" - """:obj:`str`: Smiling face with heart-shaped eyes""" - SPOUTING_WHALE = "🐳" - """:obj:`str`: Spouting whale""" - HEART_ON_FIRE = "❤️‍🔥" - """:obj:`str`: Heart on fire""" - NEW_MOON_WITH_FACE = "🌚" - """:obj:`str`: New moon with face""" - HOT_DOG = "🌭" - """:obj:`str`: Hot dog""" - HUNDRED_POINTS_SYMBOL = "💯" - """:obj:`str`: Hundred points symbol""" - ROLLING_ON_THE_FLOOR_LAUGHING = "🤣" - """:obj:`str`: Rolling on the floor laughing""" - HIGH_VOLTAGE_SIGN = "⚡" - """:obj:`str`: High voltage sign""" - BANANA = "🍌" - """:obj:`str`: Banana""" - TROPHY = "🏆" - """:obj:`str`: Trophy""" - BROKEN_HEART = "💔" - """:obj:`str`: Broken heart""" - FACE_WITH_ONE_EYEBROW_RAISED = "🤨" - """:obj:`str`: Face with one eyebrow raised""" - NEUTRAL_FACE = "😐" - """:obj:`str`: Neutral face""" - STRAWBERRY = "🍓" - """:obj:`str`: Strawberry""" - BOTTLE_WITH_POPPING_CORK = "🍾" - """:obj:`str`: Bottle with popping cork""" - KISS_MARK = "💋" - """:obj:`str`: Kiss mark""" - REVERSED_HAND_WITH_MIDDLE_FINGER_EXTENDED = "🖕" - """:obj:`str`: Reversed hand with middle finger extended""" - SMILING_FACE_WITH_HORNS = "😈" - """:obj:`str`: Smiling face with horns""" - SLEEPING_FACE = "😴" - """:obj:`str`: Sleeping face""" - LOUDLY_CRYING_FACE = "😭" - """:obj:`str`: Loudly crying face""" - NERD_FACE = "🤓" - """:obj:`str`: Nerd face""" - GHOST = "👻" - """:obj:`str`: Ghost""" - MAN_TECHNOLOGIST = "👨‍💻" - """:obj:`str`: Man Technologist""" - EYES = "👀" - """:obj:`str`: Eyes""" - JACK_O_LANTERN = "🎃" - """:obj:`str`: Jack-o-lantern""" - SEE_NO_EVIL_MONKEY = "🙈" - """:obj:`str`: See-no-evil monkey""" - SMILING_FACE_WITH_HALO = "😇" - """:obj:`str`: Smiling face with halo""" - FEARFUL_FACE = "😨" - """:obj:`str`: Fearful face""" - HANDSHAKE = "🤝" - """:obj:`str`: Handshake""" - WRITING_HAND = "✍" - """:obj:`str`: Writing hand""" - HUGGING_FACE = "🤗" - """:obj:`str`: Hugging face""" - SALUTING_FACE = "🫡" - """:obj:`str`: Saluting face""" - FATHER_CHRISTMAS = "🎅" - """:obj:`str`: Father christmas""" - CHRISTMAS_TREE = "🎄" - """:obj:`str`: Christmas tree""" - SNOWMAN = "☃" - """:obj:`str`: Snowman""" - NAIL_POLISH = "💅" - """:obj:`str`: Nail polish""" - GRINNING_FACE_WITH_ONE_LARGE_AND_ONE_SMALL_EYE = "🤪" - """:obj:`str`: Grinning face with one large and one small eye""" - MOYAI = "🗿" - """:obj:`str`: Moyai""" - SQUARED_COOL = "🆒" - """:obj:`str`: Squared cool""" - HEART_WITH_ARROW = "💘" - """:obj:`str`: Heart with arrow""" - HEAR_NO_EVIL_MONKEY = "🙉" - """:obj:`str`: Hear-no-evil monkey""" - UNICORN_FACE = "🦄" - """:obj:`str`: Unicorn face""" - FACE_THROWING_A_KISS = "😘" - """:obj:`str`: Face throwing a kiss""" - PILL = "💊" - """:obj:`str`: Pill""" - SPEAK_NO_EVIL_MONKEY = "🙊" - """:obj:`str`: Speak-no-evil monkey""" - SMILING_FACE_WITH_SUNGLASSES = "😎" - """:obj:`str`: Smiling face with sunglasses""" - ALIEN_MONSTER = "👾" - """:obj:`str`: Alien monster""" - MAN_SHRUGGING = "🤷‍♂️" - """:obj:`str`: Man Shrugging""" - SHRUG = "🤷" - """:obj:`str`: Shrug""" - WOMAN_SHRUGGING = "🤷‍♀️" - """:obj:`str`: Woman Shrugging""" - POUTING_FACE = "😡" - """:obj:`str`: Pouting face""" - - -class VerifyLimit(IntEnum): - """This enum contains limitations for :meth:`~telegram.Bot.verify_chat` and - :meth:`~telegram.Bot.verify_user`. - The enum members of this enumeration are instances of :class:`int` and can be treated as such. - - .. versionadded:: 21.10 - """ - - __slots__ = () - - MAX_TEXT_LENGTH = 70 - """:obj:`int`: Maximum number of characters in a :obj:`str` passed as the - :paramref:`~telegram.Bot.verify_chat.custom_description` or - :paramref:`~telegram.Bot.verify_user.custom_description` parameter. - """ diff --git a/venv/lib/python3.11/site-packages/telegram/error.py b/venv/lib/python3.11/site-packages/telegram/error.py deleted file mode 100755 index 2de0361..0000000 --- a/venv/lib/python3.11/site-packages/telegram/error.py +++ /dev/null @@ -1,252 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains classes that represent Telegram errors. - -.. versionchanged:: 20.0 - Replaced ``Unauthorized`` by :class:`Forbidden`. -""" - -__all__ = ( - "BadRequest", - "ChatMigrated", - "Conflict", - "EndPointNotFound", - "Forbidden", - "InvalidToken", - "NetworkError", - "PassportDecryptionError", - "RetryAfter", - "TelegramError", - "TimedOut", -) - -from typing import Optional, Union - - -class TelegramError(Exception): - """ - Base class for Telegram errors. - - Tip: - Objects of this type can be serialized via Python's :mod:`pickle` module and pickled - objects from one version of PTB are usually loadable in future versions. However, we can - not guarantee that this compatibility will always be provided. At least a manual one-time - conversion of the data may be needed on major updates of the library. - - .. seealso:: :wiki:`Exceptions, Warnings and Logging ` - """ - - __slots__ = ("message",) - - def __init__(self, message: str): - super().__init__() - - msg = message.removeprefix("Error: ") - msg = msg.removeprefix("[Error]: ") - msg = msg.removeprefix("Bad Request: ") - if msg != message: - # api_error - capitalize the msg... - msg = msg.capitalize() - self.message: str = msg - - def __str__(self) -> str: - """Gives the string representation of exceptions message. - - Returns: - :obj:`str` - """ - return self.message - - def __repr__(self) -> str: - """Gives an unambiguous string representation of the exception. - - Returns: - :obj:`str` - """ - return f"{self.__class__.__name__}('{self.message}')" - - def __reduce__(self) -> tuple[type, tuple[str]]: - """Defines how to serialize the exception for pickle. - - .. seealso:: - :py:meth:`object.__reduce__`, :mod:`pickle`. - - Returns: - :obj:`tuple` - """ - return self.__class__, (self.message,) - - -class Forbidden(TelegramError): - """Raised when the bot has not enough rights to perform the requested action. - - Examples: - :any:`Raw API Bot ` - - .. versionchanged:: 20.0 - This class was previously named ``Unauthorized``. - """ - - __slots__ = () - - -class InvalidToken(TelegramError): - """Raised when the token is invalid. - - Args: - message (:obj:`str`, optional): Any additional information about the exception. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - def __init__(self, message: Optional[str] = None) -> None: - super().__init__("Invalid token" if message is None else message) - - -class EndPointNotFound(TelegramError): - """Raised when the requested endpoint is not found. Only relevant for - :meth:`telegram.Bot.do_api_request`. - - .. versionadded:: 20.8 - """ - - __slots__ = () - - -class NetworkError(TelegramError): - """Base class for exceptions due to networking errors. - - Tip: - This exception (and its subclasses) usually originates from the networking backend - used by :class:`~telegram.request.HTTPXRequest`, or a custom implementation of - :class:`~telegram.request.BaseRequest`. In this case, the original exception can be - accessed via the ``__cause__`` - `attribute `_. - - Examples: - :any:`Raw API Bot ` - - .. seealso:: - :wiki:`Handling network errors ` - """ - - __slots__ = () - - -class BadRequest(NetworkError): - """Raised when Telegram could not process the request correctly.""" - - __slots__ = () - - -class TimedOut(NetworkError): - """Raised when a request took too long to finish. - - .. seealso:: - :wiki:`Handling network errors ` - - Args: - message (:obj:`str`, optional): Any additional information about the exception. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - def __init__(self, message: Optional[str] = None) -> None: - super().__init__(message or "Timed out") - - -class ChatMigrated(TelegramError): - """ - Raised when the requested group chat migrated to supergroup and has a new chat id. - - .. seealso:: - :wiki:`Storing Bot, User and Chat Related Data ` - - Args: - new_chat_id (:obj:`int`): The new chat id of the group. - - Attributes: - new_chat_id (:obj:`int`): The new chat id of the group. - - """ - - __slots__ = ("new_chat_id",) - - def __init__(self, new_chat_id: int): - super().__init__(f"Group migrated to supergroup. New chat id: {new_chat_id}") - self.new_chat_id: int = new_chat_id - - def __reduce__(self) -> tuple[type, tuple[int]]: # type: ignore[override] - return self.__class__, (self.new_chat_id,) - - -class RetryAfter(TelegramError): - """ - Raised when flood limits where exceeded. - - .. versionchanged:: 20.0 - :attr:`retry_after` is now an integer to comply with the Bot API. - - Args: - retry_after (:obj:`int`): Time in seconds, after which the bot can retry the request. - - Attributes: - retry_after (:obj:`int`): Time in seconds, after which the bot can retry the request. - - """ - - __slots__ = ("retry_after",) - - def __init__(self, retry_after: int): - super().__init__(f"Flood control exceeded. Retry in {retry_after} seconds") - self.retry_after: int = retry_after - - def __reduce__(self) -> tuple[type, tuple[float]]: # type: ignore[override] - return self.__class__, (self.retry_after,) - - -class Conflict(TelegramError): - """Raised when a long poll or webhook conflicts with another one.""" - - __slots__ = () - - def __reduce__(self) -> tuple[type, tuple[str]]: - return self.__class__, (self.message,) - - -class PassportDecryptionError(TelegramError): - """Something went wrong with decryption. - - .. versionchanged:: 20.0 - This class was previously named ``TelegramDecryptionError`` and was available via - ``telegram.TelegramDecryptionError``. - """ - - __slots__ = ("_msg",) - - def __init__(self, message: Union[str, Exception]): - super().__init__(f"PassportDecryptionError: {message}") - self._msg = str(message) - - def __reduce__(self) -> tuple[type, tuple[str]]: - return self.__class__, (self._msg,) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__init__.py b/venv/lib/python3.11/site-packages/telegram/ext/__init__.py deleted file mode 100755 index 7cd6578..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/__init__.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""Extensions over the Telegram Bot API to facilitate bot making""" - -__all__ = ( - "AIORateLimiter", - "Application", - "ApplicationBuilder", - "ApplicationHandlerStop", - "BaseHandler", - "BasePersistence", - "BaseRateLimiter", - "BaseUpdateProcessor", - "BusinessConnectionHandler", - "BusinessMessagesDeletedHandler", - "CallbackContext", - "CallbackDataCache", - "CallbackQueryHandler", - "ChatBoostHandler", - "ChatJoinRequestHandler", - "ChatMemberHandler", - "ChosenInlineResultHandler", - "CommandHandler", - "ContextTypes", - "ConversationHandler", - "Defaults", - "DictPersistence", - "ExtBot", - "InlineQueryHandler", - "InvalidCallbackData", - "Job", - "JobQueue", - "MessageHandler", - "MessageReactionHandler", - "PaidMediaPurchasedHandler", - "PersistenceInput", - "PicklePersistence", - "PollAnswerHandler", - "PollHandler", - "PreCheckoutQueryHandler", - "PrefixHandler", - "ShippingQueryHandler", - "SimpleUpdateProcessor", - "StringCommandHandler", - "StringRegexHandler", - "TypeHandler", - "Updater", - "filters", -) - -from . import filters -from ._aioratelimiter import AIORateLimiter -from ._application import Application, ApplicationHandlerStop -from ._applicationbuilder import ApplicationBuilder -from ._basepersistence import BasePersistence, PersistenceInput -from ._baseratelimiter import BaseRateLimiter -from ._baseupdateprocessor import BaseUpdateProcessor, SimpleUpdateProcessor -from ._callbackcontext import CallbackContext -from ._callbackdatacache import CallbackDataCache, InvalidCallbackData -from ._contexttypes import ContextTypes -from ._defaults import Defaults -from ._dictpersistence import DictPersistence -from ._extbot import ExtBot -from ._handlers.basehandler import BaseHandler -from ._handlers.businessconnectionhandler import BusinessConnectionHandler -from ._handlers.businessmessagesdeletedhandler import BusinessMessagesDeletedHandler -from ._handlers.callbackqueryhandler import CallbackQueryHandler -from ._handlers.chatboosthandler import ChatBoostHandler -from ._handlers.chatjoinrequesthandler import ChatJoinRequestHandler -from ._handlers.chatmemberhandler import ChatMemberHandler -from ._handlers.choseninlineresulthandler import ChosenInlineResultHandler -from ._handlers.commandhandler import CommandHandler -from ._handlers.conversationhandler import ConversationHandler -from ._handlers.inlinequeryhandler import InlineQueryHandler -from ._handlers.messagehandler import MessageHandler -from ._handlers.messagereactionhandler import MessageReactionHandler -from ._handlers.paidmediapurchasedhandler import PaidMediaPurchasedHandler -from ._handlers.pollanswerhandler import PollAnswerHandler -from ._handlers.pollhandler import PollHandler -from ._handlers.precheckoutqueryhandler import PreCheckoutQueryHandler -from ._handlers.prefixhandler import PrefixHandler -from ._handlers.shippingqueryhandler import ShippingQueryHandler -from ._handlers.stringcommandhandler import StringCommandHandler -from ._handlers.stringregexhandler import StringRegexHandler -from ._handlers.typehandler import TypeHandler -from ._jobqueue import Job, JobQueue -from ._picklepersistence import PicklePersistence -from ._updater import Updater diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 59c3c8dcc4b72d9ac0281eae263757d21fb63fb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3694 zcmZuzOH&(15FYU`nD_f>Kp1Q+V^A=5{D@y5`~VwU2B%V)N|kE08qk^@e+noE)sRlfO@o|zrAYozK@f78=Dz1`FONx%2@b|Luu^~-PX|LjNT zZ@Dm^mKc2cFN4spsDd!6WN@a^QfZ|vtQEIr5a2f2#@cba!tL||>%bkX6L+fh1$vQn z;Vy+cXgBM@J**e^s&yyrWBs^a;fr*D4dOvIgoo6+iw?69Jfd(n9c5#9jE&=QweF!4 zY!Xi@+)Jm}G@e$tk6vOkct+uVI?LwpoWcV%%jWUC!h`fOTfhqn579+-1z%Bkm|kT| zcuCKg~#X(wt`m_9;d4;kMjyo(687UUQ>9I-el`|UEwKui`~Yz z6`rPFvpe{X!k6e>b`RfEc!u6*-{5Z)o}~}iL;O(TIr@k_#*Y=w(kE;KZzw!ZH(3D} z6uwNi*i-ye;RX7PJ;%=#UZgMBHr`hF3f*BZ@k@oT(pPL3@3PnUwOTLHH>`+@3SXmd z*&f~loZCma>pwkw`Y|9i-*Ibx);%UX8&pa59iilqTP(Zj2HB0`b~bRc2bS$nC$IvN zErXR=M^5c9w=DWLw%_c5^_9b%fN;^h;d#`ttpJV`Ly5&^-Jun57)#h*ShWfzd_QnK z(Ys26hk-IkWeV2>L&ARW@02ka^jo9)X%!#vR zYZtbyL*j2ik^!lh{r-YQY1y)m;L(7548))@Y*~R-uq3Zgiwq2v}-h0Ha)3a0h3NB+%AmiE-zuCJJ zkN9F3R&ZawDztIw+#&}S9N~-pEyoU$1-t+k4c94#bf{DY!`roEi#ipPp3GRZ?zm;q z318q^C!#N|n+Y`*ulI-emE5IXUBHS>YErHy8pQ7IB+O5zyB}LC(32`4Xq@t=300wDBiA3ZQ9f!O<8T~ z)TWElw4_Zv+SDseQ`$75)tFY}T1{wmK`Y7c5WHKfKCOW2rEx&3L9K?g8rEu5t4Xb9 zw3^jwPOHmWEoil<)fKI-YIRMkoL1MRYT?tM_$6(c*J>Hm>)gKRD3vO%T`EZcqXz(~ zx{3ah<+vQ?nrcenvW%jqWHpGTQBpCSw3ju<$5-XY# zjk|0lG23uAxqp!CXPji4iK&DWP+VD(p>dE6D6(mX_rQ%@bE9#S4JxM7ZcI_7@sPcn z%+prP=_uypiaCv^Y;Q4(_IZI~c0evz_pPr#l<0(fmSs@Qt(NaWdJmi!nyF_}JJvq8!zLAi}3ACxA z(NtD)w#9hL4_MWlB1b;i5`IjwsUsvIq?{DF+UZM>bdfBuubjB#S`$oCNirQdKW0zz z3rx{_w+x}7AJ2#ehS5_$D#>Az)FV1edayZ{6!ZuB1mEa$F<*5V$uo=FZhpr-bl3Ah zH2GsvJI+(5ocB(Gs#{xMU0cih@CRqbgTDy!??WE=N&QL6!-(cfC8y>DrP8W*^11T? zb1QX99`WxXfc!=9{{ad+ZOvpdr&m#CD-)u^Y1@tNmY+LLf5@QBScpcG5~1ZVEfIPc zHj@aghiQq><3`<$=F nm&K3J%`h#^s&T$P=im8!ti=#DkqE7YX^GHG*i86$(DDBR_F$o$ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_aioratelimiter.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_aioratelimiter.cpython-311.pyc deleted file mode 100755 index b0d0a8d0a0907a354eb36b4beefe3364dd2539b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12917 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 VMjA2ByTMWJ7lFf`e{>!8{2!Rce5wEd diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_application.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_application.cpython-311.pyc deleted file mode 100755 index 4a775e127e996324eca8937e38e7cecbadf91349..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93606 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_applicationbuilder.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_applicationbuilder.cpython-311.pyc deleted file mode 100755 index 6d3afd4692e18d20bc360f44282abac28a91e770..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61164 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_basepersistence.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_basepersistence.cpython-311.pyc deleted file mode 100755 index bc9cc5ab967a0c3d5cf10a669189017172f33f05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21219 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 HUg!SoI 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseupdateprocessor.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_baseupdateprocessor.cpython-311.pyc deleted file mode 100755 index 8ce4a077d7da2d963e4b7e9e7f64d02ad35427dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7991 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackcontext.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_callbackcontext.cpython-311.pyc deleted file mode 100755 index b215eedf228c30ee83142a44ecf27e5857c597b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19978 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

gzv|tw)&o^47uc=_hB9>r*VAz5=RL?q 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_contexttypes.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_contexttypes.cpython-311.pyc deleted file mode 100755 index 56cad643a3fdbac487e527b96359a372d5db56cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9556 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_defaults.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_defaults.cpython-311.pyc deleted file mode 100755 index 8d0ff1d420cacaf6bb17db8e9b136d1ecd76e2bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19063 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�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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_picklepersistence.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_picklepersistence.cpython-311.pyc deleted file mode 100755 index f0510ca9ecfcd89402e0c039fb9484592f854ac5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30106 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 Jq-WUqe*yi_yd(es diff --git a/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_updater.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/__pycache__/_updater.cpython-311.pyc deleted file mode 100755 index 7927b2d4f40bbce264a3a175eb904ed1976be4bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40422 zcmeHwdvIIVncu~W07$&}5cno9Nr@yV5!BPNXjwM(vK8BuY|(a1*#SV_OA!(X(D#Ct z#ZX?y_O3-&ZJ4Y)R-5cDJCnG|+L@}`?bL0vQ`prqK@%yzn$;JNqQd+vFD=X}re-GAcu*K;`j%jJJ`X67=-{dbCJN1b|c zN3wC;dz`>cbAnB)CZ(s$s!5?OX6q`xgS!fra37a3M4uT4;VRqk> zYF%iXZe!QpRQp25bO*bxPjxPIO?NGHPj|C;L#k(?ce;0hpXL|(ru!E9r~7T3muloo z4J>S)-n_77dJ9terw7yi0Zts+%tqaB1f`?p4PN+&P=*lYDq5m>OOfo*rg7 zhfncX=*+x^9vbaDJAl=nRGUhOv`+B9+6Z+micEF zg+x}Aw(;lYle6=DR!WL^oZ%M|XOTn_6WL_?G(RP##M4q@fuG4_Wj>kCE+wGLJep+qW`m`NdveR`Z z*|TC6SB`_3Y{?f>2ZhzZtw!+FHIrFN3$yAFvs0fMxg)t~f{7d^7Dtl`6UsjA^a5<@ zPdF^N-*Qg71dmuJc*VLor%;c$TWAnHqF1apz{t1~e0XMhBKQ$+Fg^DQfjN&5L_R*` z>7TO;AzTNfd1y{g;sHs z&?bh3cKmmUh?z?5tcZ72#JelvJ*ah?=r?jOu7qAZ3z_0P;_YI`X&Y)`H|`r(f>)@U z3k!X3xu!eyT7K0UQY$NKa<^Ldi(O~BwN4f8r_O=7Hemq$-6Qsjys(+|^A@GI5e~9m z_X|T}pShoeVZ_6xwns$2FoGWH7yaVE2K}@39?z+*+mOaI9>U$)TG=n774Jro-&n=H z?OGj#9diz&{>Bv>#V%ndMsc$?LyWU<6g}Y=hLJP1m}-2t8h+Itscd0o@ARWJrtvnl z;-G7y4q0I4JB!i_NX4d0j8;shY_{!UJNvuvZ*5!-4Q%t=S{&L!RT9(GP9d z5?V=o!hS$##25#xT8{|_z9PKP=!}^9>=D%Ce)^4S)FM2JUfGJZY63OehVwz3M{z!c zb5sZb!9FhaU?wJB!s^Qqt%6kN#O&-m@aPglt};KDkr>Ja_T)w28&Tq4NhbJI2B>v0 zlS&baMUt8Gyqrx)4C5yFa|+_9=W)mkSw#6~#90w|SI~1#NFpz$fp3>^6L>kp${8m# zHXc`skFlq5K9LrH)z9-YBCpg>;OC^w0?VJOBof-6M=B5sh%fMo#YHKzC?!E3q|Qg{ zS;Av!)DXB`<}-6h1=2!k@oXYZ886AGMncB#e0nySVFZWxY8K_D6F|K(kr^mS$txPg zb3q&*=NHds=QC;LE;X0E&J$)<8!C;n(&-r;1MEd5J*oi8Cd@>9AWeH<=97M${ zN%0)N-+cQ(e4E~gapkRpL;?X2L7}1CG{0ZHF{<7;5Z7yqEM*X1vjC3MqJT>8+#cPo zJf&_J0az|%2r3iO>7@ngeu6cE!Q{+RR^;Pxz=af(lc!?}d`a=RUY!ws3dCq8jq%f7 z2mF}dM-&Z9XU_2|Tw@xky;KvL5*uRB{$nG2m5$0iH)5tbS}VjK?uy7`Yq;>_VwwI3b;u z4dA0yVR*dqRZxQQ$T+JAC15j)%?LK@RH87d*TFp3joj3E7=4-+2+EFK=Z6iS|$w3JR`X)ZZ1041NfhouNseW{Cr5d>dsvUK#R z%*+`~$CqYxb_{8V#iRJ0ze4aHw_;o2Vz^R{6+2=&yC={yoh20LnVu7iIkoo$4$pvl zlq2ict~l;7IS$p0KyQTFmk`W9jKh)!PkPdiJ)@hyfcqCMBx&(THE^AnF@w zh=O4X1}WHrpyXEjtK@u=hBTmYJn9gKjkq?{Y*1ZC*Z}s`erz7&uIeNPutXdsCpf-2 zqmnZ9FQ)SsC&uP83*y*9LYmEteJyi3vug}9ehkIFGL}ltj47CES9HgYF&S&_=ptBJ zU^aP7oAP6r@?$C#Nzp}cwJ`=}vDk9xS%ue*YIhb;s62z}m2Z0p8tf3d5N-7b#pLbTy#xchSIJL$`5iWDChr)QlvAAIB|{(lwxNswZL z#ph4axi80lcTfr^?M6_llSE*O^sEkUxJdx@CjRe0fWtk(*#MwkfYv%<)rS=%-h^D_ zn~vwW_Z)xVv~lUk0GHK4m*XHA>9SEyrh7(?cgyJwPLrdoZ~!fPVmm6VFLx^pfMO)j zK!?Xv`eH>xr^dvV`Ta)ZK%5~1Z5#{~23{UrVp{iTX(zm7yenv;65La0Aa&WKq|YRh zvRLu@xcKVqc>Kt#vmz5_#K-w#b3kl7ZYy^PYe@8>zza(f(SUks48LsCTB8vV2GXQ5 z=|B#%AU_!Gr;=j{Sv0W1BtX4h&s8jW_3D&7TCP8`F}RQk9(ZXF!cx6Kjx0B6y=B~c z4Qb>h1pfnnfZedu+f-}{zc=>Xv3%1&p=luJtNr`@X0WZy*}Y9hK<|xycl0}Bm&bCx zzUp7m*I0Jpjn6;-yj;hHS}r!ov|_#0(aZhG;DpOj@}NIsS(4Sb=?e5;sgB*6nVi+v zNxVS-$Uyu6E))>|G5{{v2pE?S-U9%sb7h{WK7PN}(G}1)8L>(GQJ095^}qB8uBAsQ zm_Q&?-D!xG5%E&*GfHr|(L5mR)*7WJp`bb*O$tEa-soZ1WPWS}a7zWQIU=wBFTn5hy-32B=Sq1^^ zY&L>9S^$Ztw(1mc?ZeS%^rg5)EKw&+kjRpNoyjbPj3}pvvV3x3F(op3Qze%byo>b} z<%4G4#_|^wNuZJ1O1zy*rcxT~qDetfl7*MhCSptx8S2zHRjuaIF^-yy$59Jo%3`#M zXo%RQCY%)1^DwT=^A5Oz$s{efLb>xjN=l6E>)dBeTqt@~_{jMaPcAr-4^9+<6FJXB z^>ET~vEdBi0wf1_2505KfY}HD8D6fehFc|kmV+9osW)i7mWecYox2rmzH}ky>8dW3 zN_-RlcfOB6n`lPKQkNM&)W!>f%_{$f>>Sc;)SvQZ$GUlHYd0&16<{X2ftdscNFO~V zla4!=e{f7^^Aw@D+F*W=fez%gnOWk01qp7SPmz%tXW73os4vP$dIw_1lo}d1fh{g&KruL=@Tw zLM3DEmw_W_GK}khe~)V|m}#3cj!9d|xw9t={W_-h8015Kw7) zg|gQ}jYYWW34YuEjz1UPllMGO@H~*yer&d#My1&CD_X~Y^?z`b{KRB|OMx7S$R{_A z8Nk9gnM_KL1+ivk&Oynx zq=-dJEdu0=u|+X0V5IcB0g;qwFSc2 zx}L_khn{jfNb#7$68CrLCf>+*UPh?xvs*N_dvMI53{O^gZ(c`oq^Gy_<-#upP%z)RxXc)ZrMF_Rcp@gkLF zncxr)GV*jTl}ThlBxh7*J4qWc^GVjpMBy`H_M9lDYqnTNO^(*VL@!9=2u51s^%Wo>%j!Q z@%RqZL$9MH=c@H?!Q93!7hL81>$i^3=AJ*+B&4C#f|IV1djemg&^W|2&T^C6@S?F~PyazR#I2E90f ze|jmMVei5GqpH>;`~g$GON#^{UuT17O>4#tTF=!0vggPqgYsA;1C%d0xaP8~BV1K| zRcr8?4k!{CsL0vqL5$Qh>b2Q=#5|X@z6EtuYdY_(Dve%H;hw?UZ(ceRFaga1h-&5@ zkMFFUNK`0lC=kC5<%FiB*{F6}Dq_L)1x6OLO!G(}txZg5DQi}tlHIA$bEvAMsA)EW zf-ne&IJBL$^EDPZeYA*`vS!3auVN{&P$E{~;~^Gg3*KZVEm{|t-wG&NivAtJ;@{?x zw)V$wf2b>{%-`)`R}}tt!%Z@HGtvJyFt^QI#P4>r%_aZcP($x(uycO{<6OZX^23@X z=_x~=`jUlSy$gY;*i~$VMeZBL?}+ZJiK!-LNsB|43g>xEcRvd@8tgAj1LSC8W;Uu- z9~37y< zUYFv;`2_;^k#r_ILfV!DKMrZr!gzdEvm58JroPk!qG@j8l{Yzld|4J zS~rxuWW;}jB%0C~Re@y9(vuVnQo!_YJ8%UX7*?oe+a&42=aQ48G15bnd;~$nr|64~ zMzaRiYB{x6X*so4k@J$MmGyv3B0LT9>8xm){g!GhZ&HUXYPtO%@Txon8LTSbe$>JF zI?9~W8~CHsg`RyMMe{w!3O&czotsUaWxK7h>$bzu9QZYdpv*b^0a(1Wv|WCv%<FX1G5$a3mi-S_mJ_g^m`RTMNyb=}|&?6w8O>g>XCF}ke z%Fb4Q_?P_95B&c)_=Dh@|5mu;MmTak94YpX6}twCeWP@-c^6#_?kz?hrt6NO;=qn_ zE7v-5oAb3c{hER@=WD!2@L3nv*!G_PyZ&6y{(R`+Lg?XK=;2~`;6`}(dU!Y=9w~%J za-kZ(o1s?awIlh^(L#t?hTrEmn@R2F4;w*|-?HYs>@S8k!7#!fRtzIr+NcjEY}K84 zn>zT{_u0$$F%Y$qP#x}Cf=qz>FLod9b9^##(0yp9{ii!@i2QVC^I@0kXD%@5Hhf@1(?rr!kRuIx4k= zHg0tTvm^-5JrEyrA3ENL(EkHn@DG7DXNZsQqr?hvKg7u{vp#Une$ji;b+PWE<05y_ ze$hGS7V6&eUGNF+tS^1l?-Tyu0k+3d&RfXuxMNHLtt)O zc3z|UOMz`pk}JjnwxvW#$6g%;edHyF|KSLt_H6Y;~suBeFE^!L);dr6Nj0p-I&|M4|6THpQkanV!o` zEx%wuXl8K{5W18WUtI*3CkogU!Jk-Sl$=H&XvRb!#KBC#1|D|oi%OEjX(I9<%ZEsx zG)Ylu5-s`_EmfdkA~=;AOkz&OY_=7*70iE(5_o2zZ-w=FN+Bag=$->?Wyz~lAeIzh zDD75jQ*yu#u2iSQ*vv5zMT}h7P1!TLiTasY_J9s}T{#qTpi!NWF))T;Y+-7>yyIET zj@3dFMEAoy8yw+*Xw@q(qm}a45qz%F3-%U&SCQZR1J4b9_jP`Ev9q_(si9)vUSMOO z;?29tL9TDlZO+pN^oyX(c{(=^*4%6E&tV(Y(r4gGc6BSXiD6N@L5#q0h zc+e)B_TB2{%Wkf*?>6UbL|F(xx*(|M+Pc=V+8@x|=j9-BpfilHTFac*f5cX7?Ys=q z#M5}hcC)4PM$6{wEt`>R`!-NKo5G-YHUWF)O$L&qIZthjMMTf5ojkukHNsp~BWjKi-kwdU)+{p=J11bL-k}c@xI(_qXlj{;XwU z)bUAO*Tk^nlVKOGrI+!f%E+%7H}8-kB#itJYDeuwk<8IQv{x=kYzcQvE{`73?OEqx zDlMh~_6mEff&rtgRgjEINt6W}I0nvMz^7sg3rjSrr`Z-RtZJ-cR-R<}fqOw;?f2d# z5F9`muXC_qy5Z}-?(5F=JeB+UshqDn?|ZS}doic|n4!dS5VMi-21p_Dc%9xl;i(2yNW)$_tmV@PfwbJ9388fa;6yi#;zt@>gEQqxcSs68dx9-c6 zIzWC-1GTL?kX_Y*6gsIR*jF8^HlRNHDv?1OB0mM41O4fXJVSpyHY;42kfTwoP(>aQ znmei6eMelA%a4Ek)F)d^MYO@hD8BXue8cqaZ>-ih>~u7=|KS@JQXpD28Ddf&nvTX^EMJRNKn4 zyjz_qQ7b!aAeUNieL$1@KO%n>zo<5f#nAL^husgR69J)uK)J5b-&72DT%NxX9=RSK zQ4r6qu5Jb27>K8lYu$RA^Ag{O0P8$qg!>CV|Ez`KpgKQZ(E@OHH$r{aLw#ktV^iFA z+ue1aNsrI7`YKm`jc%Fe(n?h=7~LyPj=f7{>aV<-bu&-^ihGuzHWt3a*~u- z85ky)Xkcy}V5UX;qMBoAm~~{Nv)D`p<11!uAnims(sl}VAt*UOh(V~qr~^aFP)oqT zBoDf1g|Tf+up-Hn*((&V%>qGO#bE=2gXi(X!N?1Vj7*oqwa5Hf8rAP1AiRr1p&h_r zdqawW+m5_vXTh^G=h+EF4U_lGJDH*nL%FBe)&WD)vX=|?+~!=tdh~R#9zE^7NAOud z&wDWM87g>&a-N~Gv)|kH!+mqbcepInSVK|sr8DY%e$RZ}IB z0;S}G6%n8_mSx^HoJ;BCt5PT4n$>N*5TOb3CjRgIF)&&+c7*kv3DZ>y0AQ)-m%b&~ zF9ghXfh#sMD`%y8lzjA36ShTXV6?a81RIq-`UQrhX zFuTV(L&yQUM;&*=?$O+v6;^>PAA5x z9&1`CX7zHh@lh8WtyGwYZ;+~jnT6e?VnOL8G0;kIr5-kvz7;=&CV;#Tbm#-qYw9Pn zmEyXdMr#qBg$C=$z=|@sPU~XTVQuwqT#m1@9A-ty8^x$rlzv!I>LXyWqNG{H4p>pv z(Vuk|z+%$Wa@~qjzgNSGvJPy1An|WoOgs2aD&~|4US1%&jke^fZVrfIQdST%>%hnv zRTLDZt#l?`6Rj)8ehFf_O%Ji$kVz%&AkUJh;FTm)lFHT~H9K9S#;9}fFG3RHgDjMw zCdFwyPE{Nq!!}S_+(5fa*)eTti$f_ZXZVvRpVU-5il$K@pAHEW3|m26r3EfY+Ylb* zk3fZb_sUe&LEf+uQGNnm1(+%fI@%fdIskdl)UxVcbT(B1UIu3pmutGYNU#ngW?DCKs97iQuVU*{M6KsW(SwGTBpF887u4 z@0zzg@TzZw=M~o*vT373E&IPJowl}xhd|rtXYvd%l1QCPoR>%Lb8Hwik$I%06ZB3Z zQ79-W>T1PKkY&qwn7G0!NKv#mY8vigwe9q31n*+UEYtHF2D!CbXm#{J17$dSAW_>_ zv{@$kn5Bgv3sqMVOpvFWGa4q*@i@4oSy9=_&uCcdMnQ{b1*)*RlBhP%v?b4CL2~TG z=!8Oon3kPP`tCaV_>P@>qp)X=?%?;+sz5VROh?JF21JC(L^LCv9;4V8wznrz^BFmN zARaTin(9TfOf&1KHhiXs)CCwtaEqCx6jl;w{Mph&<4iStiZtrDOU!T$Q&H9MRGR=% z*lA&XOK0Wi$!AZTIR4Dkk;Ad)j~smb`0*!V6g?S-Y%>K~OfQ&tP{jp8#USydeTRK9 zpP&WxRmedPE1N8t#cMqNV3nn}woqyV;O5o&Ir|+TQx^?%O^HX)Qw7idrk1GrqBo=)@pcvS1bMdGr>2l z@><7LLG+PViT+3ueIrAYk(@ivfLnc)W?z)dI!I8ZO!KO$Pfkp2!%9sC@$jlcE5J4$ zF0b@ufNVVATZnn8V)_>oIi{>(CVxaUbLlXpp|ugqwCRpE?X7ni-M5WtSxjk(;Iqz3 zgU{TsQ*=whd(utTtf}Vab;o3uRzbp0N(0AkY#0aX#k@=Iw{8V#A_}Y~t!9(DyVl+0 z2dC&*63VQEF80%oHVzb>0n^k2~F_wyr;{%ptW)X%~(W>dFSM+Zb z@|d8R0iDimXzZ58^?+4jBt6N)6_!ZRbh6cfiD8ID0>J?Y0;;yOlz>|y2){n6DO*P& zJRY4`OpcyplAKZIHx;DkJZM%3ogrR^;aD<_jkrY7sA6X}nMsXWl|6Hn0*XV!-$Wop zAD@~!0ZuZzBu9@Pf9Bw^!-tPdDm0nt5gczQqWI*T=6(-#ttvpRSCaXbpf*BI4v%nH z%P4}T!zUlpH?zLD>kMHXtvO1gzR?a6V*wKGNrDhPq9#(D!$y^pm3Tdb4xFiOh~i?f zh7ITl8zUlos5vxVtUgNCjOHMHiB_FBszfm6*;R+9-_{4p@EX4nT6H{dqmT;s0~eK z$?KHTcPdLvI;+e%nX%8PofthG#Z15&k(^Z+fJIozCSltE;=LA;ugp4a0103hNW_7z z$Jzs@LRrw}lQ7vudtiP_OnO>W#)U?RwGuXqB<;XPu!Usmyx}KMYXypc2_u`AYB>rw z&ngW904*}OY3-#$35<0nZIvNt4+(a#`48J!nf3{h1RA}Vf_98~b0Iw#^}njg<);pv z;0bD&TR!Z7h2jq~0-BjM#*T*=LN#HBdO5WulSdjRh%k`|DiKmiIWW3IRm$N-lYbAb z>U3s{B&)tj>_P4viCbb#F%d?!CK?H-*pgCX5uyShAkrLfnrR>tZFe6=_sZ(?U{wzp zXv>1ecT^>$nt(MXP=ZdAF{J92O~~w+!)hjgAa9@;3?02iZiUK3wgFNc^4Ca0YR!VFmxTcd5!-Da;bQ9dF2JnQZf{0@=BVeY>_6Q z`R4Wu5MGe0Op?EW?+2ky2nBe}ESxh;yaA1-6&~+Olm`>5Vh|w>5E7EW=9jvuSo#A9 zex9$ZacX%DX6{!3ET{-tgY{@IL!3-znk z-#ujgy}R1_+ZQTxekdoMw#G>t^ojoPXCAJl=gQmx&J*bht32DgY>v1UI9i-n!0P`$n?4=l_Zy|&9dj?<4AibluLHfI?R$#dTZ--7#kNk>MxEcPnyL3jRNM9T?s7M?R}WIV5R|zf zSs2_c_^e;IS3i^w9WI0p=R${nBYX7+@}a$j(B2&T-JiWWnf{Z#`V+S5ZoW-j|Lc4A z|9uS6hDl&du;DZIK;DY^@M&cC(fy8}_8g2J_1k~$vmx?xfAdk^^>f}!*Zb=qt8@RQ z*M@M`tjHr%s5kL{r-TVnt(4x#$gWatx8m5qIa-CnQg*>+*zrB?kL(v5W)&wCnI@+- zxYm`tD}Jk8`-R|2-M54l_qS%Ci1nl9>TyO_t7dhjDio}`((sH|OKGk9h0sc9oqD0_ zAjdRTWuodb)SSPr;)SAe(}l*YVM+`?Th@|R8sD(P9=h?hM#CN&@lcj51=NE%#R;y2 zRs!#%2Mnuss6TZ@?TS|(gL2tCirVYkN=UK`&a_Q%W&8A-+!aQNd=mDTR|F-jlkBW1PF z1}x|;Unk4assm1gDpdB?9GLN^cXC9#9I|3^vhLVE%}Q;r>zsiGIjn2~uHYSCfJAtk@3bq(l!y!Ujq$!5owP z_Yfx_5kx75Y$LdWy_1|Og;gslmFdu2%a+_H6tCf>hC@#tJ2E*Hn|OBW@lp`JbA%Yl zA7db+lWBbQ<|GIM+UCV9;>c-{;_5gAgSE6qC$c>ZglnbC6ueFWP0La}87anQ&Syn@ zA%+nlF=BH-i$t1gB7a5$vHe{JUBvJ{>ywSBp^^i%j(x{ryk6E_7yz)a-My+f~_}#{nvy2>$~#7p+azoOr8dd zty``SLUxeKlEJNT-bT&;}`RRX9|I5E;?Y+v1@CwwU5H~E#*zjvaNwE+Ypqw2C{6sYtVrLFP*&+7`h%9x+>-ZL;1k&LST2! zv*Ax}!{C3?w(npQ_i0n`-~*0N`$7kII6mFs!nO2AcsQ%CZ-~_4-+})-1p4G`^n38n zxMD+SU$K9WV;G9eKwvWNfKu-Z+xU+->HA1)^>i!I(ze{DTLe~2o_|R|w*^VycG$x; zcjkf*;&i7#EgSZ0x#sYFCG3N$yANlkj@7FDJS)x%Zmh!8U+h@3NiHv36tC1# z^FL7UQiTMkW{f2R3!Nml+;}(r3z%H%t2;Bf9=qVN)PT4hA((6rJ>KN55c_(Cv?^ilfhuzqvr2@&6^gGKhDUX zRz>vy-iOn0Oa3~gp{1d-;I-mPw&%)(FOkpo3-#z#d!;Kt7+<*s&skP$VE6iTQ$~J!tJKwchow)u%nEH_istvEr6G%#_L*osI&RD6kKz# z9bOpch(GZM0FM)*L|i3LAB)K>8fG5)Mg$0inGG+A&=d4AG6?vXeXr^*z$BYHiBBNF ziU!^mNi@fV0F>!CA7{cFRn-q!IdP*GHz67gSSo9sP;~$ zzYWRwhF$^Soo-TXSq2mUZSZH^!S?)X+pU>|7a~=wj!xgIq3K{q!$A^c`Xa_5Tx;$j z6wL>jVQ0a7aiI$AHkHp@4ys^D z`7ljBI<=~Ff?4ddFnKEjnM8X5$$K9AY#|K=n=a%r9RP{(goMmgYc`-u5PPSg1g|PU zod_n7t=?fu*n)_oJ0Ywg?>ZDrvFer)U3FEh;rg!OlU!|ArPXg)*Nh7rytnGE%_CZC zP?49-QU`tIhKG0CoZXD;4E$8-@7>G|yoekw5btSPqYYluk{|UNJFGR@!(knCVE1YG zf^)@LdoQ!KMc8H9itmH5KkFI|ezJkwdR7~u5+C>qCv}@KP3`@y*!)ys@(QfQ{6g2} zYOQs{+UE^DqV zqct{}7(00M^fv%GauSG9-P%!X?j{mFQtTeQ^1?qn_5D-1*5S%uX!w`in+x6BueD!m z|7V?l-kI-yxX}IZ#mSp(y@j@|SHJd8kN@fM{I-V++aAuh9VoONxOnVlf8+<-ijBSN z?YYp_zi2J&J5hGn2LiV_1mGVAXlGFO#=+`S7Z0xuflq1bDl~5X;q!$p59J&87aGA+ z*!_@kB7hGG)VmQ81Z#(jEp6{T@!coB^VH?1*6;_W0*|l{NlDD!K;iy=+LmOxXXIyG zF+o+0R30wWe&uj3$m6FwjyUx3seI_^Lg?vS=;>l>*V@vp=Dr)v!`GXK^UWiL=8>Fl zL?&kM)4q;F9>-5T&O<);PlGmu%bh2QIo3%B3y@AO+qcN4@g9y_k1U6#u;mWEDdEg& zi%fgo*v1co$!E&(hxo({G)5pwq_cSKS3L;SEIxk(qWy0nZa}B9n>mboB`58=W>ZHx zA7k{4L~MveQVNN-nKAadXD zBbI!cjbsc+RVMKh_9)RG9SS4-CT=cw>RgFRW103){RP4D|0Gz}HY$~OH+r}J5c`I3 zx{u(qL7jizb?sE%Gg0u+R~?G2y%&8&_|{L|=32cw%l2mf@LlEyfnZ0mrG4!Pfn7&= zGsh3F`PO`&f7S=tIsw)mBOu7}eb;wo3fy^Us1O>;g@%f~{p%-x5X<-Orq{GTGzyG# zCpm7x?rJU2A#eM&tslwx(4j&Iob(}lx=4GE&dR&JRIJI13EovU#O3-Q%7^wBLQF(Y zJGJ2p-RXZG%(@X4L+xwcE8Fx+f@|Kgm%voUBBqcA9^hD&V|BU9`&Vq;DuKtUs9#?0|Gg6G=v0Mpodk1R>Jku1Hsx*ty)MR7JtLRTB3)OdtgfuDU*%lNKn%GxDdrOwE z!xtU_Wtprd>5GaBa1KbuB48aDVXB~fpnJvSGKnR0#vnaSrU@n?r^$*@*}nWBMrT$V zAv!zo&&be!jf;2fUtZa;%7J~Q9MxkTAXj}ltI^Iu<$-W z2^qqW3F0+EW|J`=@rIV%QOTtCnJ>kL){{kGm4A|jh$8`@M11gLJHLgzu5$P9bUc_B;z&yCr zK+<^CGGDO?U`hct*1AnV4e)5dN}vrkR1JnqoxREO&|g=m3=*+3LRi_(UITtiS>7-F zm|p22`1v*psf3@cdEd5zZ(Gi{?LOdV@Osl=v85Lqp^N-jv2#mt%Raj3j=-x*^ANnM zkT*62@LWQ>JSKqY*k`Lc#^QZYs$ySLU69)^O}|Ku5fSI zuqG*sE>&-N^eDXX)0(Y&o??FfAL8Mx|6wq4rd1o!*OXk$U<018UZw<$YH+Ks%G4LU27AqV#bUa&Yk5qkSM{g0RxbU8 zQGz=Xk$;Ylj6p}=b7l62`}57)3(ecfaZbmzvma0VS>{^i7p=LI-?)D48@XfOD27_E z?D&pv%}wiA@Vmic%b|~-|HWA-XUM++0+4;?045%qd%P!qaXR<>bUt*d5IU6$ohpVw z<0+n3jD?u+wT2I{z!L|$YhOvOXgQEwsum%&&9>NK|9T$$NyQm@jze@8*Z z^#1pB?>|vcpx{3vkV)_zX9tfE9KoXsOYl1G8z0Xy{4cnu7vIACAi`HURIf)o*W7Z^ zU3R*>?LVF(cLeSC2m*d3B~D~3^QD6xpSR2G5rJuP+WQArG8V?X7s z9_zK2n+j5h$RF4t=()m5z?6rUSB>wDS!#Gc5;G88rg!e6rWI}ih;FAp>jI9g;HF&Z z+n6MKGvBS2!?7=D)-C^()Da57uDU@QQ?a^9@Csv9{Zr{WK~7w`Wv8wBKJ5)s_B=CH zzlPIIn|L?=OzSiE`dS$oW9ouossSC7%U#TtSzTvItZYixw;ZB2G745radf#uTa!ub zHXLD+Xzfd69+T#u8YCSwlT5WG{FTm3 zm?jaqDMxKW>3ux>KubcpWz)y7*muSCXY_eY_K8f#@}tH)ecoy$YkUS1h*5oZlJR0u z&B4_$wwf>RHe29A1V?HY4Q-P?lD-~63P~t|U^_jV%3$Y6bP{~r7SzWy2li96@)MSS zg`3OG8kn0VNQ$8S8+fWf`>lrHB{&;)czg8^Sf0rHo-X*F&iS4uj%(|UCZd@0O~Zwz z;he9=59S^KYQ_DH8yT_O?t)-)H4%*T*I#mQ324|+8?{&m7wYo{Ej>*3bfjWd;~R#2 zR{or+V@xQq5>V*NYF0F`vC_o~R%T^)ZPiOf)<-l_yUhq{Jil4+PIYW+7cn{l-2AihWPKv%o!Jkp^&naN)s6WS5$wgI?n13)SPmd}m;tkw1tivtH ziC7i+aUJnsDi#_bi*EKd>2uNi#mi8^H*&)lz3z+VecKDZ?K$7}Up97DDqn2=5t5*c zz?)kk9La@h{K%Y3NyJj#rsTh-fJHY9*b-kO6+CwiT|8Xy^};(BtK#LcOyJ@Jv??7*>Z8)_BCfgt2Mll68A)Q>5srHop>j*NUsR`&||FI z7>@a*GeAD!_Bbc@xj)%&Lx?3aLPOIrCij!E7=8VHAw%Cwz_l+Hdl`O0)FZIris+``00lJD zpgE-PvHR)!YDY9P1&P)m=@313z|KKBLRVz+i5+g)^9u9!7$q5}fUWgpj$3ju(}j`) zB66vP9uZ+Jk$_9Fw49+U2B$mdiX6&G#Ii|{9&i$gB_uK~W@eVsdvx`O2;g3fK1x2T zxUXSGXA&*2jCCxzm?5V0I^8HzKv+g12$z0L!CngXP|%|V#B0j`6K#B5|0~-gE>9W4 zO;7nbTSH^r>&MC+LD!46TW}2Mq6@MzjF#Q(lB){)L#~!9D`gI+Yd&_W3^sdRJ-3=V zuIyg-7doSbrm?aMcaSUYjlzJi?4~FpEz=0^bzgx_3nwGE?ZBhAzRn(&>wGS#h^#?ZvuiH^*AhfIexTUeUhEqv4(~2T z_7u17rHfsAi(|WrhaWGu9<{r$4}-#6tzBgoi=t_p%5HY);ktUuUUpf}wf0_Fx|}ID zu&9q~N)v=Fu=SChW^gUW=n^5c5#?|+g+gUPJRi(mec*418bG5PB(*+F- zYR@h`S}nXR3O~b2mEo@)34L0X{VW>L5(il{L@jS*mrYttn_0BQ(wI%`UKoCgFI_0N zvPfIarnIwX9RwJi?2@Yr=N%ljnRE@3XT_~!#gS;SufMn@q7K*Q;bL!Jad4!#XJ5Jd zEE_ipZ-v5Z^5urIi`{~y@20hrm(G^mEDGz*aM{Z);k>bRZRyI%_03maD6|e00>kA7 z_Q1yl!fWD{L+dS9jupa#1^-al&mIJ*3xe!2#DyWJy8KePkwq)Ulif4MlSRYartT{z zFF#doWzjaSqr2SBE<32B<;x4@P8RLb>vh$W>)u{y-BAeaR2$es1K-P%aaG~Gi`%xH zItieRPKv;nwW)`CCu}ZgVJW;7YA(B26ur|_cC$;RXV_&uwX=a;GMLZ-)z9t)^a|=7 z7i14Y)g9N!9vA?_qAgnIZDLWtO4}9p_x*+7V7ZmuY18_uokcsSuR7Ufm)2L^EZU=2 z#oSj)Q+a}{K9-ENT4}o)9<_6IP4J59+P97!UpQTJu+v9M>=#&&a5MMJv+QgHwCFUw z^&)$-Tz}N&+Ig$F6QI(5WwOw`73&4=V8*p{U3uxs@vBq0E^HFpiM4}nd$@2r)(*O? z=bGEFZqTKV+WP$WUxINtmJYfTpo$0CC07+r+qvz#;l#YSd5b>0|)V6t(V;_>aomHFS}Q-P2>g^^|9W(lqo|)g!}?rcYis^E<@UYG_okby}R7ZE?cw# zQR)z;y0@|?tU5}i)Nsb$;sU>K4Ys*l;AyNuV3P|Z#|8nzgOTmheI{>Yx-@f* zXp9^R$We96hO&v0p?yXG5c#0&%xtZEgFc-_1vMf`sipEMl*y7rmNKPHm5-FlGOB`z zky1cUz$EpG3_nZ-w^Bg1E2VxT4ZilP)>)NxDQ*HKWk*T}y|PBHG$>y9m^BykdRp>m znJCm9Be?#W(ldoY=fn(XDp+<+$mi3uhZGyJrxNMJX;h2RC|0`V3(tOq#5*AUFJwXz zPT3A!C@5x|tvtv<(3j(8Z*hUw*y~hO%pi7tdg~$F&ynL6B^MAn_pBe3KGLN&@j9Arb%ufDb_y8_n(uuq6Nu z-)`^$lQM0|3G6U7oXBIup%OSN+fdBJOkyXTjGfTg($tM6?P6iwTi^(9z+A60eho^$G)Q>RXy`dV>up##TXz5b<_uD$AX z{71S_k34a5|Lr1&WP}+nu)c;YbR=lYuWQcJYP3l$Igq!*H3I1-oVbi;~OXZ z!<*Q7@p%2j=Hbl~4Z{uWx@3II#Ma@hPDhU8s3YQg%@Ha6YL3J4b^PbYa3gzCh9~7x z<5zR>4FAQmCibiX&nhj?n%T1|JX<3*XOwGU&#LjP#`0_%d$tzOYAw%N*|T+cRwp%O z)VV#!A#IPWzqR43PP7sKMH>SJ{M$C7l;2Wn2TJXTY_gQvDN5C&)MiVmT`09H(qJjI zTa?;@Qd=#h_Mp_BNTa3HUQwzErJ60J_Mz0iui|6Au6~kZc)uvof)d*-B@Qqswc^=! z%d;ogvjCp$keVd-S6!$V|M@ZeBzw9OPj^XAX27?CJ==|Edn~oKp^a^ky_PRKDB8IX zrS@mg)ge~j0X%uaQr}_JcR1slpAvOFi4tv=5>KPV(~*Og7Ca+L9YU$YmQwAk4Nu|O z(^7lJ_a0%-p24&BjFxw>Cr9w4!%|}>+R+*5w6vp3w4)29x-F%;S&c{W?3m@*QPg-e z(qpOdn5gktlsay~Ru8N31fKO;YJ3(oJ{#$?)OcLf*pE^tEu~JN)QQM*mQuZ<)Bs8i zT1xeyR9|GsQmS8+I)zfFEu~JP)XB&hOR48Xsk12cyrt9tN)1GYEu{uUsTWY{BbHJ_ zC^Zy$(NgM^D0L2{f|gRJQR;ML#8T>vC>27f^OjO)QR-|YY$^4;C>22|$x><Qe!A}!BXlYi~^!~_LAkUF%$jg=*&xsnxQEI|cD#&V_#Iu;?*$8SJiA-5) z42c>)ic+$r)OnOTABkH^g+-|ZN=;izMNlddxtPJ{B~j)Q%3QXT8AX}V$Q8?*#zd(Z zl=_&Z)CKm%SMltc)2eKdpj%A&*#l=wwUi8xBc zGfE^xiO-_M=Q7$n&DuPNC!e>#U>$q*OL+FnmiJu5doD&^w|vhf@vbkR)W5Lk43|;r za^#DaQddN&d6fDUOQ{)@nu&bLQtD%()UTq{O-l=}qSV#M8vMC2=$QlAv1zKT*`vy^%jrCyCJT1vep zO1*_rziBD;DU|wDrZOfZxMX7I~)NMcTwv1ETw({rG6puO-rd8k=#K?^S45z&K3?`h{pXBvB>nex} zPe?L;W3qobF8MD-6Bqn#;qg#B-Zqku#-%YiG!c+4Cjz}vJRTa8j)f*8b1>yQkF)em(_fM!oonne-SN-#wNoTLX%@sq^-@rduL#0VWA(#=77Ij zG&Lkk{>hksJcdlNKO7n#51k*ETK&;c|CQKuBc4vjqmyI)kUu;fPsAp~H~P^mKb55t z?D?c$x*UxsaL!(Vw{U2*`V$wVNq-!$2w(6gVsz=BlrH(>R{*ukZT^uF0k*)$_{p_E z_<|IEIXFEP2_>W^{?j}%5>VSdAWg(BN)cAm$cXrokr6)wbihA^7l>Y>C=N1j4n3(3>Vh6TA)pLVN9n zP~3lB!e{fwN7^{t0hAU2dEQu*ymTQ7xDY61DHOS)(oU;i3XB0Z;_Cva9bd??bqP?P ziY7wi(HSYiGOCUD8=%>K;)Dt_!+X^iPD%v87+UF%PDT?^UYYiS=%l{`A2!|*ic0~1 zS70n)sQFY}lA8j7fQA#B`Xi`12I_AbkG?D!z9RwZ9~o)ZUKF1ik0$&87yJ6{iP(1P zID&TVK5MA!><~c$^v4jW<~6i$2=CC^SJ?b?Iv21=7qs{F^tKQ6^!KF;+lPkQJC5~s z^$n%n?Wa0>`qM>6`uhimg6*B1U7hLtj`ou*qpRas`w%Ysdwbja=zf163J#?Uy1Ki& zI);Kho#}$^{(&>?160g)w7s`0?K#?Wx~u(6`}65i^(=U%r?0PTU@%>FtbH)p+tu0A z9vnQ`-*cjCAYDbbP7d@Bp}wxpAiaT_mEY5My1%ERD_z+$7;HZ^)K5+C2#S}beYo2_ z(BB*E@9sX))7OWcwgqJunpPY#(Y* zyH6hLAL>uLPWA&r-jf4ey*;OTgQo`3F!w;$$rI0~OV|(U4h|0W4?LePAMEPu>>3Di zcy;ujA{eTVPIYwP?cJwN1W&d<&%o;sBlo4j7Tzjop&%1N=(O3G0v6FA528UFH3T|Y;Zap2FD+r9zPkn!rtm4B29aF zPElbYzhcdGQ7231osNc%#1j9RM%#VOIUwXC9qE$L`FKJOg%cA};zBIaoSQD}h>eef zzfmJSJrF^}!_%HY>7&!qWLQE$cW(&nH=TbH{7;f6n_X#7Uu-~1Ov@eQ<~;g-CaluM;zR(fQe5`S(Xr?xzJGF38c&yH-c4lO;vdF86)$<3 zUgAvW4t5OTr+|>tH4%F$ibfYth2*#t35sZ@PIq*Tg}6hw0I zjxw8^R14KvZh2NFl^JS5n?)@Z)|{}am7^ZFR3YU{m7_WO*Xd_?e-+wY#k85Vax>Z& zS_HJHhY6NS`U{CO4&FHQ32=Dz${(LT&p0oM{ZVukNKfcOoEe8hlTe2y&POL9UbyCP zKAN}`Mb)t>&}AYf$AvI#pM+AP$wgIk28dtyw`!N1)|!ZyfO9wV{Qa_BNyf_4Z~As+O_68_ys8pZ2zWqkiDT5cgH_&eLj z<1zoGnEWzCF6n_2G06A?dWk=ADW(=N)-%dgG8F<%>a_qt{j@w@-)#6k^*)KzAe69| z>zkW3iK!MA;B3+xsmUw-Yos=_D8YZbd zbp<4$vo0(xQ@w8T5E66b56z*Bc!g8CM|`aKLa`mrT|HoLlaZu zk`X#Yf$B$btjLW`p{Fl517AAMwI}D<6P>)y5DG>{CO9h#5X}6C5BnQ0H;$mSm!hEd z*d+8r391Kl5n_y_75XQLZ$eF@Eq05bZh^m&}4#CurO4gghcAL?2lcVRKHTa56znf5Kz-DNHPaM>va;o zNRn9-)G>izy&Q)l#?gXN&T!=^N&qHN1l3+u!JDAbu?o3l;rQUdh$GwiSZo}4YV)_n z&cD<)G9*t+BQ#K8aN>X^Qkfo)K&@o;fZ8#>fsV>cbce>{C<47ul8Gm9MH=0SbqoN5 z0ho`WsONB$fXq|~#1kO^I^K#Q3)&q{OoztBGqeZ-Fz#r1o!L+^)3n76 zjK@Mj4n2&<7;M|+F)(yqm7lk+i6a|u7-??v_YwGb@4@Hr!U2CLhcvo8|C9t&G#ZGB z=URn^H~K}rM1@rGnF~;V2+0H{fl>mPpUS8e`P+?`f;zR@soA2hqZl*@&Z);Sj*ati zq__$00L)EDGDgxYkEsf^`pFm83B(Znt|#v&R>Ng)rXl|6x7yLQCU6ShwQj?l#8J5&ho07Q3ioW}!GSLpTB$%Da}3VomuP;dSr zy?YCi>yD+JdvAN^hF(9XRJA6nTJJW@x^5IM)iut#6wlfu`@4^fj(!3lpv(Iu!(8)Gh;x=KXoBSOp=U8WW=Bmi(n-5 zX#-5|8u$tBab{uwh*l*A0EMVYFr>Gf>Ed87>!ICDI=_`8hkzhiLIQ&`QJ#DrKk58n zkctIo%Jo`7E9~AMQRZqS*Bw7Bca*N5A6k@>zP%~mUd6XJ>Dens@a&PPVbDko{R2Ni zVhBxM5%w>^F`?`eCg@m^By^SQLz4uj1<;)!1kzWCOdf?G3SzRL2RRB%$uAQ=jmXan z29YH=Q)a?F-TF6_)r|U6N#CB7Z;#^Jll1Ia0rmALYGni#HsB1!jfg+{Q-*o!mKyR& z!D4-uTSq5gFiolViXgzv8H1H5z!5GpsxWf| zc26O)s6@g!LhXFRf;;8gs`$1hJzF_V0IAwRf`JJKKTa}f!aU^x!Qc$-G*SdCUjICJ zfj*jK0^-5q0Onw#C?OR%t{U0ZbJT6HX z2E{P8r{3e+e<6b1! z9m^1Sl{c;=Jv9&i^}D&4X1e(*RdckL)I>R>y-ZV_Sz|z$L7)8rwYHeIHV>^;eEy`z z&zhTd(2x%@FC%|ctaigTmDSg|?(K$(dit~=hV z+houoA0B|4^g&aWF%#g$bn8rbk$OGjGr)^T@Smt<0<8q78#7RDd8-I0>aj`yeH{5! z0MYAA0J4354hT>n>bu^OS z*)dg#E0=avj4QWxm4~Z5^~#0~*P)sYnsvk|jT$8@p z*eD=yo=mXN%Y#DXax;O-aUg566_g?vcSVAh@`jHzkNl}l(ZVKm6r+yT0=zXeXs5x8 z$cAwMo98uDxdN{foaMoAVWzj(s0q~BzLKzmIg8*F#^GeMf0PeTsEmyo7mmTin zz>=@(#w*LYID5}mrTChc-8fwai(CW2zno7O9(J*HxqvPT*~Rwn7w4B2{=k7`*^yts z8QEJoecjD2Hoj!DDDo)Y$j-nk_476I2=1q$j&OGoSWCRY;74J)Bu0%ZXrGZ-7$>l& z#K&WaI0W{yR3sMyUVfD-4O22sNsJPil8cmFL6Y`N$uzl=xWa^0Ixo&lgnTe;sy>HoJPSzB-_tHIMf_sg0&zP+7xVJ1j%t>W|d+q#Y%DFZ(S>wnn zS5- zh4r}VG^<2%?N!Hure+!Q8x<~dnL#XWVWv(j33yahiZm-iuECj1m4z1JELpJ0h{r?> z1{LEcptWFnlBN+}&^3H@K8z+BMqb2o{-_VLh9hk>Aw)zj)Fe&qG^r5wDrl>i%`oea z)Za2^H{jrh-bU0;ui|~i^aATlifyx)nMlf_5v!l6sug^)lGF)04Bu?9IbvGD9iN6Y zW1=dZ$D5Wev!MB{TyEZFU4lk+Vs_y=mun>GW@-hG;eE;ERv17>h(C!;??XqZb$H7@ zec;A{cZxRNE84h_mnv#hiXe}i1y3$jRDbc{FCCn}sBAots(3=Fcp~Y2V#!xIJIz_~ zr%;8dGg1f3#sB*>+`y_Y)+uKGm}&cBT6F@Rlr*2DPW7StuSlUn$-)E}n{F|tCCeP!>jOq_0pv^J& zG~mHN!PN=|v}PYuiR52IDfzRMe2$ViN|?Sv+7DM+UZpclbCEmfvX>HiBMkn00xB$x zj|YPoATv533_QcBfaDJoLiL31MO*>h>c8cjd{S>HDR-1rkapv9SCL%CkBwZ$UG~T} zsdwa6F6R`uz4K$Fop=|UZtuHOdFPenlfBBGKBc9f-PIG)2P$7X$BO88^)pUg)c!F3 zYscdd^s7=0B6$`;?`49%7)(E3K8zNICIDm`LC*!aD(|w&c~f6C33|quxUjeKb~e2= z33kSP186qG(oJ{^$j^g2+m4UNF0rX+F1%U&oLu96=C3NocADmZ>BfM_AO^GKq!)lA zC;4m&k4tq*+(wPCt>__j3u7wW@72Ub=7eQ-Ga5Mfae+id1VtK7mr8i0Cv&5$NpcF~v8b@R6m&e{5duMCgy{&C` z_NTTUQMMjQ`g&&*pZnNnJ~qEU<*QeG^+{j-+wP>NmvPKhh~n=&iYOLJnN<=C7L#G( zBB!ArfgCny2V4-#pCQPShAt+xxdg5-0hTkYQGir_139_qEqNr-OHx<DNZq(rx}QYg(sC+|x{KE_!ZP-A>#&mppJ>*>yr` z>eYoQJ6oN^rSC9FT-Anr|C4x83!-mc-44w1fSDcT*vxoT-!-rTZ#8nYIdp%YO zDtTX`*$j5TZ7z8NIl?h6NGese8h^h3nbJWzYi0*Rn|NdztA4as8KhDV~W~f$n zXcIHdf}s#T=6iX=l&`daY%C)-t2(RV2fP@kuA_ zvol*dVByEaGfblT)NF?LR6GE3_YO>Bk;jD8CCf2c9p`)>o3WkGWsQKIVHR zwaIlyQY9TqNk`Jt!TD}!cD_s2JUL7W8~nUVXN=MQ5}kdX5_+%v%ars`V#|SvEim3d zY&pJ!D-#EH(^!X+5=WVzTXO5>TgaeUmp$<~-A~Pfz2avPR$lyMCfq{mbnhSwDSq^X z_$@QN(p_W|7Sc{9&)Mmmzd)Hg!RPgq3JEi*`GGML@0|3#1U2o@#zy~$TXvkfz)|3c zl);Jc>l(LBb_^It0-hQTxflc@xgsL^Z+Zf(6+D0xToXvK(`!3`Hj zyjUet$VzyPwSd>tdJ>;hil=3KMM*~4a;f~K3bmmTpHzmNl_*zgc}qDPk5!>-mdh`p zMCcF*!A?wI3Ng-?YBJw1tVUqYj=BdJ8)}&4#d+9@gg9suLplF0)pblb#&X`H8*_B$ zyf(kO#z+%YF@HUt*K?0sL+t^7?=<;!lP|uuYJ)AH&|JIpH)yx)Ul5ZYrhdJ-LJEQj zUjQ7_MTX|dlep6-{~l8IkX?sexKs~1Cq8wbxYLhbI)WE#l2V`imh*{A>rT4NWmjtz z%4p~E_C%4|RB~9=pCrg%KpbY@wRnXw-wJQdMH|$GS5&ulF7NmdZ>=`gV0de>`CCa} zF#ZSMAHv)N8;dZu%8>ODd>Kb)VHAdCZY|(KmQdR4=BkAmv0TX@f$zs*R5R9?d`&ea z<5!6H{%^<+-upwZqoBl2%~-dUTt#Y@ihN4ZI$>yRSlYOGwo~!eE!C1wvhO`_>5YEO zQx-IQuX4kD;^xP{-Fn;g7bVKE^Xy!GYtmbXzvWz%VE643E|Ga>h)pM^rW5HR zh|;MbzgR(0ItQp^DoP2BiX9F!waIWdpL9kY*K&;V{i<`t5>8ek_iApZ4&;wnUb1oZ};9YgkK-mxHhI0;qKqgBl zhu*F+=T-M_IO!fey%FB*NaW!}91RZH13lTTK7ZbEBXP-bIrn+TC6p14Oqh)RedJHO z$d;RSk+mT0IWApcI!$w){0Dd_-(fk3qhXyVu$OkeoGxT&Wd2iedMOdR>MfmzSu!kp zn5oPlcy{-*m;3 z5~+$-rJ{A&kz2NJsj_CiZ0_jX(btd8&!j4w>GbpX|K7&U3+*>AB{%F{tVJ@{IbZhq zqwl}}ZpAuKcQIb9Cg^f=uDRzvpFf9x=mW)D-hco7_k0zzMa((1m`p%j?_txyW-JM!#bmZeQwzP9c+)-AqpXIpAhx3Z~w zK5uCq92A^uTb4FA&-X5^+c>}X{iWiv8|RiCMWX)P;yTPbDHZT`aF#VLt=pQc+=@Eq z67SV+xEXk-cHh0)eYZzbwTG43!?VYis7YCi=yO$JBO#JxW(3=Z6T2}UkgDaE5wZ|Q zT^Ei0jQ6MVaHa8aJaxa359HjNLvJZJIVIhRuEr|t_k5+sYAxB8QtyB78>?7K@|9pd(quj0nXlfIn`4Q~dh zQ}fLHd2X)o;gM;GXX?oW6b2YSPRv5fI>eNJ3z_8Kri4sh*0G|^*ZfC(jr==QB!UFW zN?$W~5we{RV}rwIDR&r2+6%n}K?V3kqG5{c4=KkPO1?`88%TbLF(h#;2J>U*ZTXrMZ2%oESkGeEhojiVVx%V z{iri@y@qvKBXC*}rc5e9{s>schSeJWF)WMbvtB4_STrw&XOBKWr3D^b254j2-C4%8 ztQ~@drHi?UQO%=;dOe)Q{X0M2<0D+M#hURG}}f(MCc)z+2;FtpW$h zVs2H(L43rsw4r%%c=32@!+|?5+&S@fTk6oM)cVsjQX<2Bu@W{n(JrHeb0Aj zZZGtVr0)>^78`Eu;AfP24sn1#W(k?uIw$lAT|72dtlDnMgyeC279Z3zVfZ0LAaOLt z*8Y~j^!K>RDgvJ-Gpfsd#<}n;35_$(JK~pLWlgn8(}Gu;by+xa65QEgo`cdk;j4I>E(mFFvPVUk-WGw7 zN&xSE1qy@n`zq#+DwSKzD<=Eoe~+iUN^n`*b84d)#PnhuB-} z;a<$!AV7|g^N#!F_*y~zulEW+6;J&N5dTjEaY~w3fcRz(@y#6KWF2tZCLH2a+f1>CK*szvG&0SKF3XgoP|#4pFNoN!ZPtDmkKUu0Hk{6=7%$^rF4~0}1A@*k6=ypz?=80*9eKNSBzlh~uBK#kVsYAg? z1$dZ;Bm-W+->(9b+C>Lqg&j`;r>=GYq>tK!i^A`!S7mq)u~s`l!|J# z0aO?IMEnRIy$`)+=K)OXcunJ|JFslOnA~vib~O_H@5GB(z@74(Q#|LA>L2F^_SzRg zjQ-yzz05pvx?X97Co~4Mh#zJc!2)b}CYKnmFpN6J`@IEFwu1=S+tS7T=H-FQWZ@~MN`t-w6y!lZ(=NSV)oLFkHY}i z%H2xtPA5GlI55tk_**OZp+8G)W21?GMQ5K!l6JGs!whlU3H?=iG*8K|QIhEsN34zU zx4qQhw{Qhis{fXAyyTHVNu8r?J@?26!WkmR9ds^u7OOBF(sAp`oh^5B?+)Jee0xW7 zM~~9{tl~e;vpgX6y4wpE)e+VbGB7^k*6`bLi>8KDL z$|G+>6`^lH31$7hTg0QDz>3h2${`pBVqy6>^H6y>F{uk7L~{&j7A4KYTCipw9Febg zMwB-2CouP@Zh_L*5t#}EC=eOqJd3D*Bhc^=S~ke;erS2X+tO4I&%6tX&{(}y5@>S3 z%*YLISEHYSH_~bk(INc2YCj8~MvKvCbu3xh0{(U^v7_4vo(FTfdrR!_06o&7&4D8 zC15ZASF}ZC&eUQnb7pt5Fy}P_-n=%AMUPRxrhy8vX#X}gt8e1b$qmomPACVC;#d3; zZ$7SgjwjW>m3T9CH^!SgaYEhAIIYbrz|Pk^#*tj7!z}g8P(ruM=`&fOsPaAdfBy+2 zUvM6GIGG4|vGN*(;!C*4k5A|5gGKB|f#bB}i%zHGMwMnqd@CpIB64Ho@K$a*C$KY} z$H|1rK9d{x2L*@5q)F-Wl>F38qZzaueSt&cF(^y%rvh3=>~-OYZ^x_O|69l3f{P~0 zhw*p&;@tk%4=yw)^}Fv??B@53DT6K|=3yr4O1d=6X(Gtl6_w(;xPcM+JnH6d)RlHk zqVJB=Yz%PyuCLtqlDpMP`}4SwDj!ym`i2$XaMCl(-u+flrWrzC>qJ6j_0oj+C1aXr zs3o(!CAu^zB56WNt)pxcmnJ8i3z+iAai3sPWrY-OelIX#LBD)(@dC=w)oM~s!qh&K zuqeO{I_{IW&n7I`=)w?%**vb$ys9zckP0x<0WUn1z&wUAa5qlO)3VH_IB1CxVo`@Cu_7~ z-Tthj9ZPIL-n-NgyceYLsYZjSBN@kr4oFB;A@{V*h7CL%loCWQ$`qC!gH}c#+=Y<_JK~0%4^7BkjNS#U zX3iO{=nYkwpkb0YbXO3I%Lxzjsp@nNqlcbZj4b4-wHbezVAe|WAru=xp<8_&|M{U0 zpsF%Nvmg|b%tP?FegVHMfCVhKzfb2(=gyH4fM0-;!N@AO33Az115|Ywh*Fc=uMr1* z5$_;gUQ{(V_C`Eav{@-4V@g5GyK8D*e`%pQwWe8F(>!~0X-lhR?3LWmbvyFSar}tC z!82^sbyo45O{#yKEk0n>HG)>qC{`D?@>b*2PquNZp5H9vFFUX0$Znt}XUrMJSSyOr zD|`$PsfDYw7#nhYYF6Tq9ax4ShdnXqGKDNA_`=>3+;ojsE z+InE*q5;_h5>7?bc9U?`jCZ6LWeQhvbcd_^TA1&c0Z$i&`WXZ&JXy$p zny}`?CJ@8bS=xwAAckuI8@o4P+lOJoEDW=Hd&S!;@vK(hiWZ>JMi1*4>}Z3EHI^^0 zlj;m#R81RHNb6Cq#+s8UPaB{-)utz+s;ExKm>v+0|4ef){#8l!6Vp!*kLTQg$L|#XdQIj)3Esa{}|NU}2$&`#{ z+}cn6oAW?Ik?%bE5kJVs&EQE-KJD7uv&%^2%2R7tF_-G(1AmMKwHK=e*>9$thTpGa zK~<*BIdja+U&z|rJ{f!ZI^^|8nhSM-DOc0owUiJ{5noD5$h19*jO~CangXtkNTW*? z3vty!UaOhak=;SQ&W1=d0sJe(fiK}(z=5;6$=9<1b?wsT?KH4nx3mdz7;f|5+r0J5 z``+9~Ztm|kG=913%`Tk!-t&0h@zmb))XpDBc{VGa%}LMZCAzono@d?sv6N?v;@Of^ z|5g&s00pNmLMNu9)g^g+is>e98mFVvWkGBRz@Y|jA_CXU7TZtH%=ViE10n#(&Vf_O zfm5teCKZrKg%SFfSW~V#ra~BdbxqQ-zO&7JpNVJ(G zXf9_Ybpp>@uD%ZnJ3^CD5i4alXSD$g0`@K@OJP#)OtlgqHfOXwmq| zw~Tl}&@|u$>r??;oCv(M5MFi?^s!D63B$`4!VAAll?%Q5s+ikW5$s2 zXF~EMj0U=8fNTz8CRME>F19bAxn6(B-x7{ZU1?DbB5_PC(B4&imodx`tI@PHT#HSM zG;0REfucOb{2&FgX(TQXr^DV!qf+7uHWEQ=Bat20mIe`@@II=$mA0Z0`;oBCmPGhE zWYlFY_64Q7)dRE5YLq)(mmw#gqE&;2k==)koM;PZ6ZR}qJ?eHp0sSKn)0Uhh|7ka* zDBqumCUtowut7n!n}buU5FG~dcGyHJ%(kV}mp#i{i98x9X+qK`w<1-oI3$tNKDJk)ft3(d zq6uu4BVBCbGWJT8Da&7hs_rLH1y|!|v%VX?`KME!7CO;l zar_TJtu&Az{Yq{&V2jjRv9o1F8+)0N6(m%ss)9YTOj-UfVgWKk7P&{jD5s<9L#euj zcB*a(AA%petH+Sg;Qp(JTQSD zX)m@Nu$B zM&krZxz+c@ij7ysG8Y}012sI=ta5yLF?T-8mp2m$(tszO6OG8ES@C57BtDsG3o|7l zyi#VfA{6#MK|4p0d^Yt1?lMqoNBVq@#7BsXp(Yq0s@J_!z5QPG_QkPO^?s##|EzbZ zs2WR#3mRy(>NN~#i=SAk-u(K^Z-40g&qW*?^dsyKcUp^O4hx2dtBLn z{O!bFypr7iVygO_QhhF2dXBFdPI@;#XwB~oT9divSNHHB(@`YXe&Pu$J4{$&D}aeQ z*s-$v3F>vTRZMw(Gahv=@B?SlOb$F_0d?)5`j}VBUYuw?DHYe8M)#LYS`!{Am72W{ zqguK2yl`fl9o9%UwDCV#PiSmHO~U=8=6JH^_(J;|74y&i%9@*N zaFOxH_#5*(g6Wj}isTV$hwG(Sbdu8>QJ;OhteR{MTT88Y9`*30(EU!>vR+ZD14JPG zgFq`u>d?>McAR*Q(@D=dp9oG=d1h7+@) zgc%++{OP^>R~>I;*rz|~gagt{9ZZGHLD(3ROQi?&I%ap$0G4H8byf)Z2|^nfgjgW1 z!8;A#4k&HUCD#q&FI6(6lnf<3Lkv4_<@R9p%9x}97H|oTT!e8B{+o$gA zzq|kKy~%_9%D$7h!T-L`BOD{wvMbNMZ{h4>`1a;o7nChn-iGTto$MzwDa~^~v2giz z?(L3mdX&Z|>G2bHBJ3wKDP;?{o$luO=7o-%)CJtldP1)k;m4Y3Wn9T?LE509VIg;+ z<4w%;;&gF{{pbmmsS^2EndO{fcgy^f3xhW?;K8Y$Xw}o*4URmYf|cc{f9t~Lh47nA zROi;k1pCnwDzrw;xSZ#6Z^P{J<~J`8bhq8!%YHJG`T}?J!r)@Xn`bGCW%F&g^5Q2m zS%V4|D;5WD)$qCiG2F>a>hs;ri@A#(xA6Tqy^Zh3Pi9i?!Qy#%4&#S>!SIurR6gvI z`BNh3+bI$B?G*DXQ&R$q2>PbpBAA)aIXfkq52IUXhpH9azl>X%^Wc%3VYVU>v!z(X zqR*CMhSQCiQ4i+1F}JPXkHAq(EUot-lqZGb%=Wwh&-DP0q>hQFtiHsw)m0a@L%vbtswGiuttYxkbL1_vy$>O}K3wpdDq zm6WME(a0){q^zyT$!w&;Urn>fWm-ue#zIOJuVf+Bnh5*iq`qmTu%Tw?+h_!Z->FR$`BpC9koQ^r6?KJo~dYC85u}eEkAZZ z@I`C`p(u7j*C%d_5n0);C?hIFVJszxj*O_lq#IzS=Ml#e=we}!xwUkqb)gU?T%|3= ziP;BFo#AsLMjDW<`-uw+DpT-g)^y-mz%u{eO&Vw+>coK0x8}yxq-Px$US#X*Gg&;4 zlQ*FoCm+U>C36%6gSd0%+gdkUl|h^l47j+UIwEQ_bD=ww39dZ`ip$DiR-#0$WmG2} zm@4BFc>L1u$Hej%0Su-Ut0rycb7EPVk@lJlqh$;m##=oA@BQ_tjJ!;+!E4p0FWtEG zj<4aKuVLX#%C}wdZBKf(Gu-?buyR-X_5nT-h~0ij%1^{Vxdh(0PzGqZD(1g_JZRAx zrNZB0O4M?wm}v(Y%R@*^YdX@t46!>?$qDkF}(!4^f zdN%Z8L$qFM4KwD@U`?j*^YST5o~Oii^hCNEQ`ojpPyGWECir9XWzha!Bk7 z<8;?8!b*dm+h^~LD*L+Fd1jL5aR(MU7IWV`M(T3lb|w4Co>Y3=yB6Y$d)~ZEd3N3I zWIqp;aJE996UKk-aEY_k$LMe~d&5f15|HAY%4P-B^~mTH^v zs-}sKW9>sGIBR1M+Fd9!7Rs zOQ{l+Dv6X^O8FuckW7_w0N)=f0kj6E&y!;Ut*znURo8j2m5lHLAnuoS+;fWWTZUBN zhV9zZrYZ9A0I{AS+M)+Y>+9<}0RV^z_jmb;2-B*Z40$PwXHvc>Y2MB|f5>}~$ejmCE zf55~a`()}$w5{z*-5C}m-kta3#H{=1hG1i;T-}q9F91|EBp2`1|AcB}V#Vov0r4yy zy+*@~+Dy^uuc3F`=Ux^|6}7J)QYspLEALjxy^8%wFOQ#P+wIdHwI2CA^;W7SqwiO) znJqxvo`M4l6e*_Qz#@zz_{o~^zCTK})o6V`gPwi_L3}>&>7Y0YC1~m=gD*ED`YhOD z8ZIX))H_PS@C9GTBLIX0gq(_caMl;cz;oK{kzRA{YQ*)ej;lXCPTf=sT2 z)yK#wPY(2)ZXfE(f;j`H6wMT@CFJ)WTYX*6f{1u8M7mXI$IaILIOH0Kea z%d~#ZG6rcM&z~G?lRrvdY_D&w)4PSBFkGu|F_3VXY-Tq|BfmF!>rR2c%qf4%h6kQRF-!}9fHTLP;cB=~u(nd{Fkx$2WH9zu+vz`mb8 z1q|6vgA~v(M1*E>BPN#`H<-dTQfy!kTi{gyHN8;Yfl5NJg7dMlf3F%;i!I|o$Q5qL zw2u-JIMP29?C9_9ZSU)Zh4aW2e?%G$O^?HzuLpABF-X*v*!~fOAdx9tFu7&Jf)^q~ z9`xmj30V08{*#FFC3XuII|(!Q@3`s%uGPb~KZBZ$ExITDA=Y+7Mg9@QfMB6u)W!L1 zL3q|dM)t`S-moUt7@A+<*Fm-Vpc>{&n`wFY=w2!Sxn;D^wA4Kl{>IHohq}%V!4^7B zzzI``0K-I-fDDbaXf(p1YZpI^5EW!NG1-P~&E-Iaj#q7QJCkohs#O##VHCgNEc+z;sO3IvRz88#(S@K=SC}X0AHp86m;UV|1~`4xwiB zfM9|kn6rl=Bp62`JQ}FY`Z7G#v54KZST$wp*N6rt@DmJ1C!>jA@Q?6`@u%?!w#+4e z3$17|MVh%=n_PQ7x%SD$XOZZC&z(oDF(^^f)ld>8_!`I zJs6g$M+`y#*ya`ZMt)$2A=NU18}QYlI@yshtasG?x%hxGR*0OMuT~_7-!;R2&|$1O z;Zy5%FguHJ5&g=ZNSU=Fu5!2Bj@rW7N8o~*&D@Zl!HMREwALIN$G9nt?)t(TFIlm47&gI0(O*QDyx$?DU0o%7C{d0*MC z)E~T8a}YN&{um)Nd(s{)7!ISyS5b}LNcochNIEYzItpuzoP!IMc!`42?$M|mPuRG_ zm6+T7C)B`8D8Xh#6yHYDcGfOc)XeRBue2JQIV_YZrJHBn?{Rl!XTcdK1$1-YEd0uZ zvi0eEHBTpNPTlSL(-X;|Q};Sgr7BJ<6{nNl(}*tng%18*ch4wYr*N98KCK|FJgroo zPWjF#J_Kes!@t!z1kpA^-}j4@e3p{WQNsLv*oTMdlG&EChY=v*$Ry+}pV|(gpZ^u$ZZZ$|r+f{HuOaDaVBcqb~}c znS55nmJh|;ZzYm16$;g@h^cN~Qr*(-U}rQeA>x%AlT0r~(|LSXr#^X(zW;Mb!uWpe z(1hpD;mL=Yfcz?|`npyfma5a@c^WgbBcUyJr_BhA?BBfekeqwfIfgB~STs*fc))r1 zBNWL*7YpQ4Xk2{^_g*bG+cW8iIsby;{c4-A?H5kD0NbP{?U1_(h5r?eH$QLEH4&B_ zF~*w*tvpr|;t3yjdDl;}I_2KGQ>DSY?v(YN#d^5kIZ@Q`wND7kCo_SV}qw`-EaBY0Z$ zUQsDr(F(RL)$Cn#-zrSj?8V<~=Zzk6f&Li!VsXehKh1xa>P8m3Zaw=>>!EwChf=Li zDXmYv)7pKnwfk=T?IWqyex>h=!iM5=E9Sn{u@h>-@VrHjZaumR=(v{_fWHoZ5}6a znqh=+6-`npgMIA3K+_NblDJEd#|jb@Vhk4KYd5zXKufcEPV!>Z6&=M zmRfh-I-c~k&n9ln%n#jsA&FJfzNR~H@onb_`g3Z3ai-iiyZEwM<8(3go-X>XuF2^M zriZU8%sVHBTwS3u%Q?BKrd_~ss6%mSFSSs&Cj_H4iZbuaBSM4)A zQu-u{Y_F)5;_G!G$xfFEr0;pCO>oMjMuR>#)Zde4JKz8$||WmMH$I zd;B9YdBnfBb@lIWdSOqif3HoMpUy z56kB90NKe77K+$1R1%K-#*k-*Fyr}b0OSF0bbsJu5J6zFmnDYD>D#E5?&;WJRBP;7 zpSvFLW9nuq2C8J+N^l#gy61$-I}Ma+hBEc#hk&%^AejkM%{<( zav%Z{0m_-Tdj_I;?E#z^>FOFZRXmOsaoOn|Z4s zQ==oji(7JZKS0)8I~PDSUn3CtSMfdd)QkwKFsN?JIj#aP>7`z5{#aGbok+Tz3wsvg zZ$3flYZnb5K19m(vERUJ9zNxb`WjyQSV*^!!LE~3gjEslH-1LA zt0!D{XZyg=U^cR?&_S;eZO_U?`xGPErxowhN%e09qIEO0%5Q;oo>?u)K4T!+XBf#o ze9D`2>v5560f!s3j8#$W@BWNpS5L7n8oOj8*m4c<8oi!fnO+YwdVNaqf^fxOc6wza zZTYuBHvLp9Exdn_g7CDiAFy!Pt4>%e9t%TdhOK})w3+?}zJkD(RUyV$>SqMHdII%y z_xCeJI2)0!VMMCJUnA79l?fF}094;2iuXuT{mV|MX^&dH{JWsmbF1a89R}Xo!FcP# zr@U3)dR)A7Dqe~8!iVY$i(IHj$#05kam zz7Cm<;%G!H|2ie46w74wmPyx;zfK8RYvtQ?Mtwy7CMEO+`Cn3!;bF-#Q}W+25{&;B zytS;?&jib1Hwrjpvso9qFwx+zTino>gIaythsDaOiI?C$Oa@9C0*Us&mzou+_GFj1PJV=b zlOmwa)O-^}VK-Crcov%3&E8-ET4BchLYmdU{i2NfY_xBeC!_ z?JvFqhJLIPWQD9VW)EHn*(vG?^q$;<*v^`TSzpJf=ZH>7v~Z)To+c!AAV70;vL5qQ zY&oRAU-q+wjF^J++Z2W!7&)kV?WIMU>n%5$S1bx^G|^G zwy9D=Tg-tlr(nprFbF4h{5~M{4n4)Vgi_Pjs$DoGXmI+^_=( zz9d20qGSz}W>}8L1rB)OMCfJCY55nkx=gH=>VIgM5Dl)T6*2hOg&I^tt7L7yEGxoslbV){@5_5*IrbR$1(K-FU zPg}Tr7-ufCb9Uy^o2$<2r4g(F(08&VJyGAuk`}5M*8#}Y*f7v37T9R*j9_8TujWKt zZ z1AX8O%xru>#+fztJd~}mY0lHNU-{pX^7I#!@P#uJp-)yEp1VDntUSm6mUA6tRbmy4$I*01&H7Gb`@P2Y zRAYzI*dc0v{?6n(PYv9AY9RI0kn+?}vhI2Qr@nMmO8I}ocbS#)Pk8N>@9TV#v0>TD zb!;|lpZ6m6wl=Eear$7*(AwDEv zY=MLuCn82p_mF{B-$vN@KpkMw2q#UuBSE}x zN*ABF-Er$MKYttRX!Ivp&o>kl9Hb!(erO1TpH(EhW4wbVhS56hP$};IA>6VZmE>wM zI$Q`azB-#%udv&O5Fd~aKL9B(NKNfkl@7!3<6-Sxl%JW$%=Ru)f3!!MU;Bd;c^m7N z`VFdeiy5DwMrz+c)?{wHg1R^on3&qbtj$<}W_X)bU;J^|qErz7G})m%DrV#~5h6`j zs|U$!rhEK!SfF(5%YTNZswOCEwl0KK4$1C5&;+Gcsma)Ue6wbP+SCjaRIf?YChMPr z391-B;*U&F1B!Pbss61b?FhIGpcH?{EbZhfd--FOAbgRh(U_FWB!~R32?XqmZ=&Lr zOh?)Wb3sr_po`GTeqPN;9qi zdg;v3%jJ)UT7SM2lOrMkJWMqc<5UMzI#Hc;nJS%_+KY57 zI*Jr_1a@Z+(y7SkOm1N63Qpq}>2~6BVy4dc_RHH50*AttW0bTVA&`&<=5?fK4$_(E zR9|y_b{Wc|da+p?qCS}nX6d5#lP6E~bhHok^!Lfs%hT?j-u9ziGLeG3i4u}ZGC?k# z+kWymH&-$nce;T6U{UW>I=8dGBke+RHl5pbwkw_6dvb3&_h?UdI``R=N9l4;I`?E} zcRJ_f^Xc5d)3`Nsb|~#0Y9BZ{oX$Pdemb3dw)aFjcev+dri%;BgtF<-YeY+Lqw&|Z zf6FpS6rM%_(@g>*pC2!^IvAMHc5hoXv)>Yjps+fIZ z?r5s0PARG*r;}~Vt|#5l9IVNF@%QQO5A;VDoi)^8YeEgi-5=+*anjhDbg0k6~ zxn`w&%Yvkox26iVD+SxHA6arWf2dXyB9m2nQr^9acQ41}kMu*5t`;sKh`#OBzIr^# zbl;KK4mB_`yI^F7!UqF$9;T4GMn|P^q9?LaXi5?|Oz1qqjB|m+UWCy8S*DyzwWf&a z=6zr*^8ZeKID*7}Zuvg(7)o|i=D$`mvs*J|TtdYIUESSX9YevMPJ3uQx{@sK#+yT5 zLOYnjiL1qih-lDQ*~(J3q7lZg80==3*k&(iJurs!pj|eLS+RbMC?h--#ff1a9@r&IBCCe^={lun3G-v2vsLc>Yp{)jAE zkn=SUluytM^IbcreQSrr)yS^Q%8 zA5o3`-;tQ%=EUn}1lbAxViVwOhyb}Ah2Iwu&dLXp8%_Mtp82j?R22rhWAY`oLHXmBRVCm=^d{`X8XdzXni@Jy2C_1} zL4u-&0sQ;ILCRM#cT}ltN%^)ZzHLd*HUeiI;0J{=b^p*?h}&ot%ILKmaPi_zG09NXGy;2Igpl(ZV8XqQ14(@YLe56I58tJXZd9zreA*g-d5 z+C)Hta(Vaxdl8x~ci4*!0erbT7qlA$#^BqVgDen7Mh(s|`7(FIBE<{AZlRALYRd%} ziOHXh_ylESdYKA2)$=Rfiu;)9lrlVRQMEHm7$2)CobmNO%Y za*JA^7}3ln)I9B-+0-CTg~y@@j5A5Jh-k^jFs+1mIihvvC1{~QvhGrgCPV2G1_%NM z`Kv|8E+pu^f>_AQZb%xJ#^lh1Fpd6fqet3n25?ag&-NQV`lF*7(#U0#*chqGvV>k1 zpT-q)0)(#s@GwacszcKtl`+4Jja*0#UU{QOIBUYC+CW&u6T{Q8jCa5{hD~`hh6=<| zuTl47Gwbf6KdojTHewcGC!l$U=9XD)IHqa(O zvwg{;!%G#_b9=v6R5dsGms<~{ik?u4SlFDvQpF~vVtdlN{oMyYYfBX!REl6Zbrv+T za$A$$t?&6NW)obarmZ1Oh6BPK{lDLh~yd;pfwr$YRZFvly%!iwpZdztr^9}O*Fp-?8>L9Yy<%PF@XBdv@iN8 z*eCM=uvQgQ8*rbs2RH3XIkVmj?u;!me}^DGtU|ommwg6^c}yG!TI4>;PW!JtOAsQy|K}#ac_-Hlnyljt; zGQtNX_g271fa4>;@ev?=*d`nwRGYr*nTn6#nI7y9I`D{l%B4$#$3k(o>|$^#1`~w* zxI0D}>>@$7RxKD8Z_I|6jFt(+ya&L>O-9k}DPKVG1(Ke?3LT}I5JSnkR6a{b*})OB zgCk}KA;vc0h@skM)~Zu3$Jz&jy?ZLs5{XHkT1|G4;R1#)R%Gg0EoRA_N*l7ae z?Z=IsD#8xjM)*sEw6dGtYLB6Hb}bZG`fnC2?c&iVlAhfwU}+s;iITrt0ZV&0miBNg z?IA4LCLBvt+st|+mQD`z4`Kecs}uWu^$m6PnYX@pc!}!?_Do)k!TIKKV<$f<-eZps zpV|(AgMS1J$SSee0b3#ScLqnfeKiX`*V?pCfHFT1(D@tErf4u>56aC1N=jUm`9G+c*{zv6 zl>mDNgYBn=`g`H&)DaXDDUS$O;5|MRn~H{oh4*p8v=lH+(EGs0<8gSZWr63KjCKiF zRuOnA30T=-*+`EmDW}X;YG!szmxX}kQ2$B5vA1h*5YA$c2*(n%mu&z2qoW8u``CN4 z4`8JEjUYVt*!%2zb(OhQ0*IRd7qb-Hmh!bKzSg9tbp^O?BS=!>r}9~(;C9Ymw{!lw zo%pM5!uc!Jrtf$QlyndD_XhjByAftK3r3EiZ)BSw%oZsdQ4~CgqELXT!hF-JR*$?F z)rCgTjBXJ(L5ob1-A{&1^#S;7u0|{!3;Dsq*&dAJSX4F*!iI4?q6RTB&-Aoo-bPH+ zz!!&HFQcJxZT`Z41XlL;lRa7-5w;Mxl^Ne@q6B7n*xxbX!_3%_xnzXV%m*Xt>mh$5 zaJ$hXJNP?e+<^c8wf8R2QDo_vV5XiaDV2JJUc5wt07-zv`z4-25+Di$Er~}_(1}nc zpejIeq@b$k>Nf4Jo>sNXW7@86W1Dv4+3H^UxO&amX?yY7Gt2haUXI7d6N%$AT6x-2 zp5s35S#NvAK<~DD*5m!Ydv8QWL`LdSf|}lQoQOXowfeXXRf=qw+DMtjF4!T}^roc=I8m9YWe#g>DQDHm-j3l*mms>}c=0RpkT36_ zX?FXIkQ#lfy@K4_Nd@1sXoILI61MTyu9dV&ilez~yIoRi`UE@dmJ)EQfK+aS*i>dt zjfpFba{o(Y!|Mny*WNXTPd^)={ht|c{Io>F;Ni8rWMc?aj^ zc;5PWRHOB-$bgRLpw7du-?Hz}bman1!sS{y!P^AORUc=NDrb4=-E_Yko%xO00ZcMN zO<}gk{0RRIc5SBf-(XwM**z?6ozz??Rlr|DA^IT#Qds|eUS+s)5J_3==qs$uZCj?j zoanA0qaVX825Q^*S36QAQL`jE8OSeM1iv$1&ArwCrQPrC9_t)$T7Bo5jFR+y+|T=J z-|eD18&g`7sWle0PWww!3bM8cucoT9uoG7)X12O&S4>6*k?f*xV zH4%J6sI+`cv6kA5mx7j$G1d|Gge}O%GRD%58QQT21GKAIZdPr0T(#>_)vo(Lld5Vr ztJ;y|`4g;c&euPOEc6ZRpBo8;m6qs}>G$_phm}^Dr)Dp)8ojIr?XF&Q+)^Li` zYkjP`7-WOI5^7k{oa|8}`EnI+*jCp2=VZOpiq;tTn!Th0zHkDbB^SJn@nuvK{IlU6HvT7BiXgYF8!d&G_TGVFEl*fi_ zoj}TmG@F5~l60Ge*zQwXe7M+XNva-;58-gjBKbtfx^hVfwpdv##7eKJw0kVv!84g3 z2x)MR;O|d*E^RlgVmfteHpiZLjR{P9SEBt9YtK*{_fj^CfDr37;acQQZT;(saU z-8vY9zlSHk8JwtwH;p%-_Yjju%o=}|d{U?q^Z`8Wl2U$Bv;(G6JT|xMdV{L6Eu%Vw z73-mEAWgCnxj;%V7M+rR4=&t_Kd#^UsDA7H+EjhJS>J9a$ya}2T3VI@br*7wFZ}I% zJM00lEGKsGhAl>)b@_cL_tr4U>b%S9P-+R4zEk*a;p0%vyO>3cx$f z&`u+?lhXFZuZL14&1Ok6-DhuI?{F0c@AoM%`zP04;C#L*XED)jF;8?;%C12nOlRYvZZF(QX{lflHv0}8f1&D z4|0+eScqc35copQ7joTpLn@eS(0|@=S`WQy=j*y_$y$Ltq#or}qLaz?Y; z1|1zOv#J~jj0MJW$8yf+#&g915Iey;m$*wCY4PNda~`f=-VVK!>mMWe8^|{;c}$%* ztehOnVzk8e$?To`^p??TyTSoijdHLu%b!h)-0edh+%#hQ3Z7T{nhSgO;boLB4$-;> z5xbCB|9uA+U(U6U(Y)+FM)TW6@8qS|fc}TZUqdGh1V*;vNpZzrt|#rg>d6M@lbEaR zE=Wx4^A3FSqy(9wR zL2X2WP@o#4d)|B7CrfY-%fR=FZ=JvW+U+Zk%5f+or{Y8qW8c&o?p%BSQ)c7#N7{C* z5OMcIc{lmEanGa1Jr5Q>Ja4uiOEn%h8;?KIj!zca1*D6zuf(+BVmF&7*xiqdFX!0o zUW%7xZhE;7W}xAjAMcCP#ejx119H+-|7MpS(K3cZ({%fga2hC*%AC(`R%(b2q4|_l+)z~ow)%M}S zp(I(5F-Wp_1ai@7p_5MCqy+n^k}pK>l%!#)Ak9aj%vVSmE{<$P$Z116eQ$+v^tgHS z62^qpBAC^895|!0tB(Nr7~~S;T%bQ!&d$g?gI``fk$TFhFunz2O$y z%=)E!g9cSYu2%eE`2zHY(yE)u$F*x8)vmp_AXU55tljx2yc1nPJtUs=06_>WGkHR9 zB7#FaaH%HxF;*)&-FHqD9>(S}92!i78T=HxRN|ME6@=lN&>e~JlZTLr&@90@mlyzi zp9@y&FIkO08$G*6Fnl6{LoSKI*R09rdX4`ibc2n49XbD)V%vvhHD=jjN)q#g>x>U; z>mS#)JgRN^o)(3M^II+E%1)!Q3&f~veG-R9FdQl_ zihNJ2aZF$KoZ`3_3M^h>*0)X;VGer22c8k&s)|=t7>PwykspNvmDQdRmj3x+!{mQQddhF5za{YITmK=Gb_wZ~&8 zN^*?H`5cdTa4+-o4(2AeB&=SX3+#~yfwmt#5&e^@SlKm2Cmp~~zrnf0>XcbEvcJLp z$+^>-h$>GQl_&0>xViDMw&D@|K)imhFr{rZwXL}A`IDnh9g-D`8(Xn<_N<&1h1;=+ zyB1$%k*irG7cx91>&p0H-k(NrD^+>I1S~sYmYpy{CuCV#c6-)7QsgB9F^+|XRSfV! z-ut%%6f!1Cg!Tj;sV)x39okpYRUGNne}j*H4M40LOtTOM@r5Kz;kPK%OiP6jV&+%+D{rb7C@p zuX|VT_dRHMaLw3x*xb@1ZW(=AqWW1a2&?Q`TsLG0+o;nCq2 z&4m0BQHnqD(I1$qsQ#}&HT`ecC*lD9B<2fPC-|TF@DHqq#jWe5Hk}R}=|3_@`sBxs z!sy{elP7P4h4@n^ENY;L^N{VG#`OLIi9_&5d^l}-&s%BJ`=dt=9dgm82vp?fDRqKV zZXXq-*XQSRoYzWG9EQXCd^oHx;K_e%7GWF6X#(WLNMEO~lsQmDZ2Oc!As5oQ#XHah zAxLQ9_bHp8t0NfE*hau<+GIj_R>LL`>;bWx5FH+r$5{u(A?P-U@&lLk#QC}yFB}K0SB%|`-^u~*cOCyaAt0Q{SM3V;x zMi4JX98<%_ov=BSkxlH47FsG}XHPVUuJ58UtJdhtI1o+GKLeMN!(@PsF}+sZJ~*TgUPbT(42Vm^7lsDu97*nI!mWARYl$~W(6+PKc00S;@p~Biez<27H2owt z%N#KYMEhuhrGn9L&?RKho;LTE>8@S7EWfF(R*z^J*!@OxV>5Obt(n?RIVV!mS)72s z_9%Q`d3vkra;+SxhzfK*diD*pL+r{44_HW=U%mRp7qPY?Pb%IMdN*m&-*>ZJg#O*@_Myz3Fs;q1-2r+85&Pb1;Sko2&{ zb>XYF$^kLPzE@NC-m7^4<-5cFcC&9sS@f+i2_|oMvIy>=S0_ z6NdFCB{{LYK98bYd?8N+U(Vvfy``hCfbkbvAwT|`SWd0GTVu|H|mdj$I&DDh+aWj(azC*0KA|MK9j= z1`GN+et{*{zsa0>u8Rrw;0)*@E{yZ?d*QE6csx%c}YEPt5$hbzsUhmEa=%?&-~$|E9q20*rmm1p;|KUPPc`O>r?)(g)Z zFZ?KDIsJcNA7mIy)2Yn;OJ#MG@R@`2{?l3c4^#Lg_(w3%Vdc+TY012|>*%4m9zQIJ z^$CYb9dsh_V%Ly*E?adQe9iQFT&9leZp0pZFy9x*9?9HXJ(4c~exB0(ou7~|BHQL7>TO;|)Y}4)mXEZ8jI=@# zb+_pwf_QO83S#xfOSouAFA3t|c&Tz47J*Z+2x9V<#lwm6 zL`C`;EE~#UEmk=NZUt~Pv8<@V>!VWN3L*^rpxFPEfwWflcPPeF1_KToGwI<%STI4p zq9IeXyAw8NLeSvWB(1`f43{ZJuZ%);m-DNTP;7A+*^2Of15%*pLT7-v(}NeJ9f(HV zowh8)NR2Ht8AE7QO2yeF^YplB5(o~d7xMuXnUK-bK5Vj94|2}HmEkLIULL**X*Z75 z58~#~SyuAu2;?uZ@{rZENZ_jM9vfNJ*p;e8JS8>RwswxXTbb@`v@>$9GiKEkA4;zr zxbo&oi`s&sv#Vcg$ANYn=RM?i-r}PZSJuiw;Ez(XzGFwbdiVDpId=3TR!$wdlM5Hb zD}v*rt4W5PQ%tAjchp5d8els6i-VTwp5x!RnRMh<#C1)#1>ILJA>8XF`0z+vK1ZKs zXU~G+bhgK#iuEX0Yg|my^%d7L_6QW+*&1>3Opnzi5F#p>xO6@p$_e;b`>S;uj-7~H zF&sEBx(=$ps1~Ui(!H|sEd8jcu!MfUgO`f)GxRg3)`$bqm4m}081CqztYC8B z8u-G_LC-l{Jj-T)%GVLeEP=JKSmWERLp59{yTg;Ra(pBmau6mu zrK(|?=)~;9)=jI~P$@<`6Xyr6UK$nSMh>ohn1U0Qva#I?eVt67F0}HDHlc4j4BDHa z2lDsSNQYB#>Jrjpi!^|WBoHAc@Of|-@=9D!VO$qud##=N39@y z3XlBP>wOYMo-rY9U!U)jZVe%N4-`i4ZZDDS{`~)RAAnb7`wiT4s8o?d=Etj|#mYB$ z{ZH(PyxrqNFeyg2nA^qNOo>9wk`94L$!UBCxV6~UTLCk_V}8zdln4ideCBQIm2B6L znernSZ0ip>(|@Fk_hLoy)4_R2H`$m!m1{%i zl*B>DOvZ$@*fEY}aTJ&KsSam| zbh+qn5k_5|`{m&Et`pv5UsStwv;9 zDzeRtY`d`^F{&o>X6t7$nBPDzj`+HF^8R^qQ;Bs09Hl3Is>axVbuVuHUmoomKLwez^YPM^MEx!0}I}R64mhq8CW$6 zYay@}WnjU%TcS2zpMh1UuoeR=nt?SBSo7jbGO*?=tfjze$iP|vtOfC98CVMy)^cF2 z$iP|ztVQw046J&E)dZ~O46Mb#S{z@QffZF)tAMpS18WJemc&~!u$C&UR$#5kz-jV@ ztd$C@4OrVVuvP(UReVPV)@p^d6Ii=4uv&oC65pMH)vB=e0INL%YYnj0#P?=ktyNeZ z!0ODvS_iCk@h%Sq*DIWTz}cUHvjI38;s-o98x>ABa1LhRYy!@v_)8hJ+pMq-0qbxE z7918Nw#0ifu(m3!BfvVEfwc`-+v1ZRqKWqSnT(S5Dy&ZeE0%%P0j!Sr z*$k}C_y7dBPcc(ov_2F!C=5LPBIG>xDQ4#x z=Jb)uJA69h<6YI=%pLiP3*Tx-V8-~@T=nRWS_UHG-L#;GYOJPjD2rCNv@M z>}~IOiMrdK&RAbpzy9+~35%4D-mZ2yoSrBVzxoce_u@wd+)wvNN7N^}_V#u6cTH4u zb{*>K?~>xvQ65Q|sDzW?V~3Ta+m1s=`hcmq?y0<855f^S%d2ue*xPmFXjc#J&fkx( z-u6TEKWt}xpu4lPt7l@NU)r%Am0D@LpYJ$w_$aH|IZ>Xzr)pAusB2%pQv{q?qCE5p z-^Vf4$o}rbUA^|Jx|8lGyj@bKS{k`4$_ji%z<-J||z#lw(wEbls$esuv>w}CMQ#>i*FY8D7 z@$Sy9BeEe~M4DLaxO23<7e1W3kGA*p_r>5LTN2#yKwrm!uFhkJfL7_ei%|0bRwUAjMcVqu z+U`f%?gs@aZNI7Qe^MgS!XjYL{hk+xK%wLaG92IT&}l-6Nt9ZwoW+A`m?w-#pie zwDlrw_haqQBkj;b(52th`X@Jtw2dOo!}rNeB5kus^YpXHEh25JNb}Znn@DT(%k#QOa`6{@@D`8z6=hZm^li&*&!#~Ht=`qxm8@x-3 zB6r|U0bh5asm51UAhpuWGVKK2H5pi&i*sD1E_P)a>wta6UYzx!?bj7(SzfdW^@Jv@ zH+Z~E78!#UBgMsWIDxOF{kcIsT>`v?YeWX`#*^6jj{ zHy^_n4%+Z_H!i-i0@+!<&CasKS99i+73bJXJVFA8aNk9Ey`NbpSqXAx?mAxCzE z5;1m@vMhh|8lUM!)=hErk4bBFmR=6lRVi&XL>41FMR0?O62Uap%HIW*|4mk&1&dn9 zGklR}_{s_-&wh_Qv$UVBt{&--=;z3?dRM-&j$sTD#{M~xIF}s4iD5A}eIA_2R1|WI z^8eF0Fs=fsPg!8>bycE2`<72#PsPMXAijIXU6<0j`a5osC~ow)ypDK zPRFHT9L0ap1F91H7gsN}cNZrL8S?YOpI9fIf5oivRq~_wOD$}2- z9?3MLs*0 zf|+LF_zubO9g^e1DS0iK0}6|~yYN4#LZr$Z+zMNXC%t7qNdsiorZTCl=BnXgT0>#&hv zgx5{M;dH!ctI_`noM>TYS;qBx$=CIguj|QIUm*GVL-KXGKVMbE>zLZKnE{~OG8Bz^XRZ`J^KWX@Xf^t&~ zpR$;zeLuqUokaXQ3sL_uiSIuIy!*FvB>gIPtCY6}h60xQf_@xT)WM7^7he2uSfY-P zi>Sacr6S>3NpZek)WCmqte-_A6sL}Y;BMKbJ*Dk6wY^4o?-b0dk4;UXpMY_PnRN#= zemCrY<8n7CSkw`eQ(;F?&V?QHn~S^Ipqvr^f!$%V?~FL@=KUP|N41BvLl<;xXUu3! z@`OfqMfC{xFVHUe@mE{tO0{*>Wm&2W$t!f&L-C19>n^+>se4&Qu4j5VEOS#G;gjUn z0@OlmQE>NZqfys;ztG&;o6`DBtjAQ+_4!x^wDHX5pY`?sZpEG4dj4KmFY6 zM%D8{-UJcTb8mC(X5T&RomM(ig}f6Cnc|d}m9Wfx=kng|M%G zX!O#|=EpgVn>70n2M5LZzZU)3Cn~7ecb#3o6!e-2uVl+A@bv3ME3?q_DqKxRaA6HL zXifM0&Qm{T>{Rb33*6oD=n(eAaEL`ZzI(w7ugHifZ5ls&OQ)!zBKhZLK=Me;-L@JK z_=cP2^Rm<2ZE-h8ntK#oNA=-1hAt!aQagIxXum#m;X>kL*tnht54^J6*Z>QTA&i?U z*}v<1^jul0tyuCdNb8mbx23c;Q)@HAZBq=4x>%NM^#x$gJIpl8e70TAXWQj`ww?2t zFOc(DJz1@)nsh61vKmv)k?S5M2mD*ZxF``nI`AfZAHQ%DBY3rx<;6x+f&NVPC^26^ZG=GnnX}O?*Z19&0yoRfDq`t>K1V_B|>Fq=8^GHWAuVxp! z@7N-@ntsKXH+rI197h9zu;I|f(&gLeC6Z1)<<=%cR!t~+iBMAOliAJZI=<=HN|i&iKX+^mxEbfn_>j+ zmLqVt9D%zz0)2rTfh);+e-jgjP4XPM?y((XW0KRe9W|S?bxD|+eWKr0p+fw;@}^G@YBtdWidCZz5z7; zUx}EWC^wVr{u8Cc)?OIx&yn<=PH9)I4P$%C(Qf4rH-|Aqd=J7ato^<@243AU^%hmRg zk&h#AR~RO%F$7VWDsGoYLQGdqarnP-K&=7kreJ4DERCk`$Fu*1Nb4*l{UENghy%{^ zUW4Ga{h7Uz!t+i#p<|@A4-P_00fz#^uYU~hq}N$wY(SKW<+3c)f2euhNtu;Z1Iov2Y-$_Tv2LE@G-$A>c<}UBio?irebaB3CC$CHbE^Bn*($jyDfR0ctC!HND$1T;O+ zf0=-r)%uqSxM8ZlN5I`X{VN3AxY2)wfO>rW7O$vZ)_;{(R8;D}#w%*j^k3%{^*Z`( zUUAv4f0b8UdFsExD=tKIF5z^_w))q2MR802ORnMCK!9`3GY5j zC&8CmN!i#kqpH;?UXv~1fJ-p!7nJ2u9^B`7IIIy6_n7`Usf7+OT zCN=+zIsc52S390}n2yR&jZAR!(@%K!SvrYF3~%l*mLD**Zh0>8#-Yiaocy-QP+mTc z8Ds*wR>NJ^L#2lUT0Nbpbs3fWQkDD6%6&IpVqDG8WN}_TOxrWTt;5V?1M^Vn;lR9= zMqRV9=7dpqGF5ldtUGDsRgdSrM0)t=0cUU-c{Ce!O-Ac+qwYki?u1!)BAo{eg7fmd zK-Oa;>!Fguf%&TpRAueU#=KLhd8f>Ir;NNByER^>2u976Gj=ZCYKW@Mx-KyM%ggtI zTY@{A*&>w`4lG<_ENC@0#*77LQwz?T3(gvOb#`4~OqQ4L1$P8(cQ6-~6b>wHGnQ-{ zFWrR$N=pk6aCvC~f)Fn)F!Jgr3ly(mn3R|A1$RWh-Nn3AQaG?|m(j3uymSxpTE@JV zF|TFFD{AKjW0<^rFSsS@wVrvYq;LQXuWdA1`i zTV<>}Wz2geHSZO3-YbIZIq1U}2i|Iks@-Z~|MS$P@#fDOtNV=F{#0$hS=*1QjOQI> z7v^@hKfJq$`E&%?DEp~!pm~4LXxcX(+Jkt{%_L7V$g|ug5BEs(^8Fy4Br=8h+3Ddx zSuH&pwi%J_smOLSvi-*X$(&&R*2#kB(mZTE<>h<9ty0!xEi0mu!hxEGn`exs!$x&a zs=CLl?zz!3o_Bx*@*;~2pF<9Ux}G{LyZK3@xyPtJlBzypRv)qJ0EKg2z8A=`u$`?? zN#VefZANtKcxWqlvxK}^0^Tf|EC`U`Xp4V;5q$CV7twc{j-+ajnzcto$5mYpnzy`s zFOXC3ZdOGl`A@y2=(hEF`A`F80=@!pmwBjko@&p01*jqI-;|kk{mGnsR3u{0L@3fR zUCn%^Qn~n#<-=@_XDs{9;3^lcMe_3f;9b#O+r_}K)5C$r&Y-cPV?4AA%x)yJ8^P>` z$pV$1Kanr{5P9*x}?BfKqRAEUc zpkAy9up&NAK+ED99MVvNsF?OI_u`I?7AhiT(dlc>x~P>N{C@_L^m(PWVs4kEv?fz)GQv}ZJQGW>UMwq? z5Iu|XzF8{oo2Bxe(awr|fgIY*^17DRlh}PicxZPG`q?ki;p$K37i+&VgrK4`T$P_j zow9GOxi`&*>qhO9`+NubE1U7d8{h>ui>HB@w7#;vW2`@=EF*@=Ue^v z8o#~9Tz@##(qp#t7~!5N^eRPZA{|Ga;DI%(O6-VIi5*cYu_HnymK{n~zl>a+PBRp% zd%6$PG1DAbU1pPqYQ>?!8STjY(rg&LVYZA82ZrZm#Q`nk$K9R64EXs;q%=#X4x)SL zC-L+|2z^9oTC)uE8V?0j_kefSK(Z4#dPX{4uT_!nRn^_9y}j6+w=q?<$*kIBlw&m* ztl09sx`nq++>V)xHl^w|n{}Iws?C%6xl{UUD2yq>zk2U9ICnJq6F;g_bE4+^B(TtABn?4M#XIHV?nLuxWOBqoFGQ1bO0`C9Fr_l3+b zN4A#RR5^+$0z+3X|8z2TqGCi=Pfh%ApqquwwcZ9PMxP*4TKq=kV^H zQumq1aIKkOOsqJYx#CpmVWs+PHi}oKidUM&E2;Wy=hB()MSplxtn`kE<(d6dI8Z)s z>`kM7t5LQsRkqD6+jir?WKJFyMBzfJKr_M3mM6UXES*#th*XcAFy^l}N;jlRH<+ax zZtPQejLUt-TCNbunwSPzR^=@`s?{YQG;F_@vZ7oVrs@Z}dAI9|-Kz=?uHVIpLE zNJS}F%I2TXN#Ai^JMWGK&IjWKZj4GquWGmyJ4Pd319Oar0`@+Kvg$c92OTz;Q*oejC$UqYQKvu&; zxMhGPmV@>x72z61Y+td_g`kh{9)guC;aQa(tq7T&3=cXok{HnGVI6VY7!!#{@UDm& zWL?;vRn^UiVQV)`wX5ls#twK;AHLjz8!WQ%j9*M%85hnO9n)Uns;GOTa1VonHkVtS zQ8N3E2@jO}jvcZbWU3gM?$}M9RwtuPB=0LSHeYg7KYIpooJOzWxS{hN0*sE(SNp&v zE0~jAC;C^<;0(wvD6Ya*Cf*nr9F1Zn1tS>5+0^Y=Q-Z@+hSOfc!F`E2WNiX3hD*%;9J3855#l6ntLS}&;20JEwBdzafs~A`8|$cVHy2J z{~@w=JdnX*vDk&RB^#vw3Le%60dQl0*WxZ4k!1Cw(Hn9bkB?lRpB{Fqceci0cri2@ zi+zD_xMO(e#|T`tt$Qrb3@!RzsPvt}cMBhf>K=vapxv!nM(1qnjq*K4%T7Y;@5AbK zlSP4|d5AewRE(Lts2DT76UbNlG)fI}0XzusTYhd-Ie9SE*)V6?8^KTK=#jT_UL^s< z$C>A~05}uG!s%TkVc{g`^*LNmR3>d+SVqPZWuAUyQJGDdD8wW}+h;}TsH8N#N?xza zq_h-izC=3j!y_PbNtsy^HAxB*G0?KRi;na%y;iR_@NFu$0Q?D54&_V}6s zkPTsV*;DP$PseL(2kJA>4H2Usb8og66{b?jxvCG34SiAhVopGH{#-f%FD zne{8FJ(?WiiE$BgcyNH>KM;_E?@AdwM7&Xvw>3@6dZb^PuuqM?j*}aRE{xFhj7M)z z_lN+FH(0c7@Dg%sJ8Qp+dJ`j;-h3(X=DA@6s69NOzjk%xY+IXrmvK_(2f;cw~ zXY>`Cmgu96tD}u@N;*nv@tUqm8_(Ef5$CeV3Mf7Wv@&>IY;gF})yr3!ROZbt?AF$F z40h(0DY?}WAQ%aBiw}3x2GD)e$GBGfu7!tPcp+5=1L;pL}S^vKPd<2YAqS`XWzverq z9ZyoGSi5B`@7=IVq`1G|s6T)i`nz*>I~>y1!dDs<8eoiwb!8OaalQPT5}A0Rt8 zPN8R)9dZTx#Gx1cGA*ZWlPDAoUGCpY1WhCzze9>_!V}`{|LzW>WU+Yp-wvm=<)*gW z2rnOBv-yL!jIw=WufO}&tCv>;^?&!Ua58k}L{6X%6z6YT{SYxc|Hk%Kc(U;^S)4)(}{{A4} z`uyf=pWicwvT3Zl>-A3wou8*`LDqlTx(x(QW!<_}8@@7rqj$r%92>snKJgnX6qbzN z=*6l8R;5q;MonSK_>EqyDqvOl#BZ!tSTcU27pn$XH9qkhYZaD^-{{4v16G|+{Kk3l zrC4V*=)2H&2I?UXi>cfZUQG^1zVEo+xAu?c99K<7RO`ofbgOd0fi31?-F}gzH?$p3 z!Xq)lVPFA&q_4jZ&olU%lpm(p!A|4d%t7_tI%$YjV!$hl|jWKoV}(LW;%zX*`|8eE*MK8jI)OA^-u z)y*jF^u6=u=A*{R)5hl0M)4j5pk&;cpyb>c zysm;p*`eg$XURWXtah}?$-llq6ls6*)YZ(L8dN&+jXC|ZPQx|nT?ag}%O;OTD!g11 zeB|I0A15Dk^)KL_F8KHkul$)gFSCM*jXxsA*8}rL;KTA7vwZp8exrOHgolbo>G*)FbWskmGUP{VGG-30;Q0+2qICLW>HY1Nr|mi|`$cbnTD9NZ0-tjQGk5Br`ux zX3p~&jL*f{>!M5|J@0vOit)B=%F-3Lii<%?$LuJ%V}!R&G0Z9zFPv@p0ti{iynNXb zENYWOtxb-!HV!mjAldQ`*=BpmA2ryytl+)@*hG` zN4pe7RmqAsnuj+{_wo#9{1d-%5^?9G|2!yJJ_TPkNxp27e4#l{g8r?N{;iV!t)#y%ko5l&=|A6Rx_Ul@uksxznKh_u3Yr5l36Q# z#*cc>JZGLQbW+U2trs=_i4ish7aOLklVV^u2_6*_mk_lZ?~WSf8;tUSd)Le@$BZ)r z#+CtY9;$G7zH6om@3>3qUjy~`W#uK!xgcWGoC_lM^yXZ@NnS4V;iZ>}eLc*x`a8qeE7Q!_4g{o$=JvpFM7yX>dJf$F6<4;zi$M%BSo z)j_lB;ElsPLbq|UAoHNDIDC6^b>?YXX==8~DBYYY-E5X_rm2}YKb(gnwID1~zNH0UWCd}%ppysa7ccb)yw=vP|^PbnTHZ zGhE!=>}H*EB?ck?w< zV{x&ec$2hC8@e)j7F*aI!XL_E|B7t6-CWsiOVCSZz`&s8y>!dt#p@VUP4$1Tpfwy)KW5<#Mb#G z?AXI*QXi(15n(EMK6+(Xl4vODYJhEc$4V(%L&b>X*(ePG95+RUaZIl>aemjIH?@4!$pk!-We>AiY|KHIx=eOPa!edpP;st8bnMabXGoj1@m&kc`W zMEw)AMNyfykHW$R1|QCh9rTGh2_y^_XG<2xP#C&m*PR{6K>_s7tYi^5;?3T(Z=z7O zP+x?pOkV&nXz8aoS#WC;BR24qTO2e#be{fk&oFm@oB4sUV$NH+9|YZ}Phn!110zO< zau+j1ZqGM!^@Xg4T^IdZC>(cf`$4@H>CO4lh>(enXN5T-D@7FfSpa^NGtk4tYxRij|V2D@;y6c)zO!2zmA zE=2W#L8rY^lon42LWh@1ay4luY?}nJt*9$e9ky-267?Lss_Qh0V?{xKG3zMmTNX(q zZ*OAss(!^W@A0P15XWmRZLjvtpuQG;Ouvc_Ck!{G73oCCYWHgwOab!5T z6GhKauMhIVZ8pX`imndc_=x~QYlztKTc9g-oIg8S>*Lxm_tq>L>*# zQ3D^UpCq;JgE}s2wTUv%+;qK45ZiP2*GTVE7QOYCaMfI$T}g3}tnDL!b1V1<uxqAWpS8a4_E{&MY_P`E z@$UB6-XlEcLlM-ysz9wjx(+kl6gSe^&8!;BGC394 zI?KQ3YdMR~vgTgX!xEvh>^DRGMyP*$(emf0vz#bYlU(MTPUtP`tg3o7mpRZ{CQ)yQ ziO^iW`?E%2O{22JzJ+`xv?>IbmeQsfUlQu<dHdZ z{_7FdY1Qw1bXEO#I9Ms4xinTEK}E?y?ve=q95=j0)^K!KI?DQwTSs}{=7?8ENz!v~ z(5a%ty=gU+l9IDhP%>NhK(=eeuE@{S`bjaHX6h$PsEm~LNnWp1oOaxsPtq>}qkoJI zpz=U@^*gV>`}*UuWsl01-8r5rTWyxDHbSd2y8^f<7jw^5UHr#(qkWW@Xa$^-a{t@X zU6N?iX^UmsXTl554lQ@wS%AeAyK0gf)2lGQ%dSs4SsQQ@5v8n@bxK~ZR{U_^Ugpn| z#z$q1cMDQwYs|7WMo5NbeNp;N4pOP#e9Wu=oxoSWxd+YD3I38VNgiV^qY&RhjfCp zeskWP4Y%vls!eg_)o+%*{YmOK7vCDZ({THu$m{M#PnN`~QqNJp*>b1h&fxn^)KRwF z9Ti{M0rZ<|@ATc(-apA_*4|qtzGel);1o<41S9NEp1PX3ezOoB0lDaU(HhPayOY1F zAfl?EmTl|#F8X+Vs!<>*mIx;y4dpHc*Lg}0ji;g7}bAKuO=j5`8T z`TwhO)k%@{qHi9#J_#dr@#jUgl+}^IEhhC2LABko91Dt*TDv9kK z#(8dtwKMdLy%O(?kG5?!Q35Ns=MukXjbJt3M%)Sg86IdBm`gd5rVI*K+cuSEq&yz zj{!n^p?M{DI*uIc>2Ll8osqvL3S*3F7K`bB#i39FFp)cOZcyKgM7@Jgl)+<^vLj8l zGO3eET?AZp==%u{08A9X9RzHK^lsicNbnNDA*O{ab+F#Tdxu$?+}P*OBLqhYK0(k+ zAU5r}?LSd%;kL%Ejt*T)w$klHQWy+ORN84UOiGS2Afw(-^jpMiuv3M59f=*2c2sax z2QP@IE}i%3#{nkh`8_TRJHdyV352&?ajasLKVK#I83L04<07Ds6Mz8${VxePW$1rR zkWawjt#gk=Uq!H*poa7~O%USGRs!y4>NwO8(8rii%&ULStF^pZNAQ$C(PsiWHF5fX z;ZNE)=^F?NIY_yn*GqU6;Z+5%%6L`Ft8!i~;8g{$7W1l-R}H+BdqG8%a$ z-lR>u5-$fX!^Nzo7w}4q&3azFM-V4C2k?{7j?2T0i@Qtz2b2rS2a>-Ga!%$3gTcua zmBGBp07289U`fu6!pXfkaQSWo%H`j9py-D9Hy&s({QkxRZASLL@xUU(?{7S?-k9$1 z!;Io4a|(kwSjas$P#y>_^R#L_u-tI}jR&?F?!WQCVZ-llJh0Jl|4kO0%?V-)-yc2^ z_n$da_vJSR!;^tbaP#03-hGx%>JKjCqnY4l8$$8%Q9G$8SR3rbp%s64^U@QM^30jO z@nle-WdGt>7m@l*eod;cYdH%9ra!!iLn%yoCg7xmJMw~6II@xf#u!m5ScP*iR#GHT zSaKtNv(zZ4PZiXg1@$*_#{(K-d<9|tlnI0j>tG`@Q0b8Xd~F^y5HZg7UtKgF*v%Xm z2`U57n>Ow;2bCTPMCOgXV$?glX&2)-PjEhh0R|hGhZl^UVIB?4LnTE5MP*|JH;)*h zWvS3IGqmhR{&-;fWIo)5B@=LMIu!d@VJ!v~kM!YU~eDAC567z)z%4PQ7O z*g07+Ke!jw@P}+SQ=U1~+ujNWyMU7YYi!dKnflEA&}VY>oZzZShyi}^iMapFnfhwJ zJ%Z2@$5^{rN``nwSj|{B12Tr!q{3^=@R}P%YJ5}&c__{wa*!~EUDJMQZC-FSspob=MRmlM)X!ZfX{W~;Z_g9GaYo$_uS8BKP(Ee?Nv;*F zxJr)%!qsEj80EC2B~{X5mbBamjR$ry2cA^S03y6ykS7(bqzL>r8(M?W++k>)DXr7g zI`Q%z5A0(eYnX=@$UN3C50w-NR4+G>&B`vLYG0}fhH3kZKn3Erfq>z>Amfu}01>M) z$QY+qQY0|1#i&EP)=wC9y{Wohv#!?&;7p*(#XB~b>GD|&5PJ#+o@25WaVkAiblobW z7BNnHj9P>qJYv=!F#?R4DO=-DR}6HJ)J@lho4bvsy@uA2(mG7717x)`VQAQ(7u*yx zJwwM@Ns)lI1e4Q>-A3h}ROKGCa?g!2mB&&_2AO~a!Cg)`D*Yg4!@2gRJwY+aW&h$t zCsLouuSxZ_4`Tt^=}aKUU=!P_((z`j8#`qzT4$85PnE7WOV{7Pn^6%RvrQf+8y65E zFM_L>hf0bBD(dliZ)h{hx2MXto8{YYl#T~F*p5ObD4G%A)o2{7rI zfRhp)$UR*U3{3|7;S+KHnKSh>;ln{9_`@gS{xfIlIdqs=vC1U|ss6H@eLoX0Tq^E9 zOD7!-25K6O>J_Q#CbPQ92vm*-4onuT2+}vHKcrB}lxNQL-e4dUzA^gQYj0np{2<;N zdvn-sfA~b)f96a*n0H8U!ygJEhe^)@jt4#oS~*^(hvL0?lrJ26%UH6-DBGGU z+iI3=y%AQ@)?An_WZ#}(5XvHdXp}~uh@@xE2iVj6-zj1)_Xu4O*o@jHqqsR$+-w#L zc{wMz`8f#f_WTF#shN;hGn*gB1AFE^w|T`Q_M_EuZgtB@m5XmKGM4QyDt4wScA6DC zZ$!oeoh;uw*NFMYXTk}T%^!QsSiI4QY)VBonUPI5O2z~2%z@#JGk^$h9At1}D=8v} ZtFiikQQe)Y?l!Bt<)AeJ2ZYk%{{u`dbZ-Cv diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_aioratelimiter.py b/venv/lib/python3.11/site-packages/telegram/ext/_aioratelimiter.py deleted file mode 100755 index c990a54..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_aioratelimiter.py +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an implementation of the BaseRateLimiter class based on the aiolimiter -library. -""" -import asyncio -import contextlib -import sys -from collections.abc import AsyncIterator, Coroutine -from typing import Any, Callable, Optional, Union - -try: - from aiolimiter import AsyncLimiter - - AIO_LIMITER_AVAILABLE = True -except ImportError: - AIO_LIMITER_AVAILABLE = False - -from telegram._utils.logging import get_logger -from telegram._utils.types import JSONDict -from telegram.error import RetryAfter -from telegram.ext._baseratelimiter import BaseRateLimiter - -# Useful for something like: -# async with group_limiter if group else null_context(): -# so we don't have to differentiate between "I'm using a context manager" and "I'm not" -if sys.version_info >= (3, 10): - null_context = contextlib.nullcontext # pylint: disable=invalid-name -else: - - @contextlib.asynccontextmanager - async def null_context() -> AsyncIterator[None]: - yield None - - -_LOGGER = get_logger(__name__, class_name="AIORateLimiter") - - -class AIORateLimiter(BaseRateLimiter[int]): - """ - Implementation of :class:`~telegram.ext.BaseRateLimiter` using the library - `aiolimiter `_. - - Important: - If you want to use this class, you must install PTB with the optional requirement - ``rate-limiter``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[rate-limiter]" - - The rate limiting is applied by combining two levels of throttling and :meth:`process_request` - roughly boils down to:: - - async with group_limiter(group_id): - async with overall_limiter: - await callback(*args, **kwargs) - - Here, ``group_id`` is determined by checking if there is a ``chat_id`` parameter in the - :paramref:`~telegram.ext.BaseRateLimiter.process_request.data`. - The ``overall_limiter`` is applied only if a ``chat_id`` argument is present at all. - - Attention: - * Some bot methods accept a ``chat_id`` parameter in form of a ``@username`` for - supergroups and channels. As we can't know which ``@username`` corresponds to which - integer ``chat_id``, these will be treated as different groups, which may lead to - exceeding the rate limit. - * As channels can't be differentiated from supergroups by the ``@username`` or integer - ``chat_id``, this also applies the group related rate limits to channels. - * A :exc:`~telegram.error.RetryAfter` exception will halt *all* requests for - :attr:`~telegram.error.RetryAfter.retry_after` + 0.1 seconds. This may be stricter than - necessary in some cases, e.g. the bot may hit a rate limit in one group but might still - be allowed to send messages in another group. - - Tip: - With `Bot API 7.1 `_ - (PTB v27.1), Telegram introduced the parameter - :paramref:`~telegram.Bot.send_message.allow_paid_broadcast`. - This allows bots to send up to - :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second by - paying a fee in Telegram Stars. - - .. caution:: - This class currently doesn't take the - :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` parameter into account. - This means that the rate limiting is applied just like for any other message. - - Note: - This class is to be understood as minimal effort reference implementation. - If you would like to handle rate limiting in a more sophisticated, fine-tuned way, we - welcome you to implement your own subclass of :class:`~telegram.ext.BaseRateLimiter`. - Feel free to check out the source code of this class for inspiration. - - .. seealso:: :wiki:`Avoiding Flood Limits ` - - .. versionadded:: 20.0 - - Args: - overall_max_rate (:obj:`float`): The maximum number of requests allowed for the entire bot - per :paramref:`overall_time_period`. When set to 0, no rate limiting will be applied. - Defaults to ``30``. - overall_time_period (:obj:`float`): The time period (in seconds) during which the - :paramref:`overall_max_rate` is enforced. When set to 0, no rate limiting will be - applied. Defaults to 1. - group_max_rate (:obj:`float`): The maximum number of requests allowed for requests related - to groups and channels per :paramref:`group_time_period`. When set to 0, no rate - limiting will be applied. Defaults to 20. - group_time_period (:obj:`float`): The time period (in seconds) during which the - :paramref:`group_max_rate` is enforced. When set to 0, no rate limiting will be - applied. Defaults to 60. - max_retries (:obj:`int`): The maximum number of retries to be made in case of a - :exc:`~telegram.error.RetryAfter` exception. - If set to 0, no retries will be made. Defaults to ``0``. - - """ - - __slots__ = ( - "_base_limiter", - "_group_limiters", - "_group_max_rate", - "_group_time_period", - "_max_retries", - "_retry_after_event", - ) - - def __init__( - self, - overall_max_rate: float = 30, - overall_time_period: float = 1, - group_max_rate: float = 20, - group_time_period: float = 60, - max_retries: int = 0, - ) -> None: - if not AIO_LIMITER_AVAILABLE: - raise RuntimeError( - "To use `AIORateLimiter`, PTB must be installed via `pip install " - '"python-telegram-bot[rate-limiter]"`.' - ) - if overall_max_rate and overall_time_period: - self._base_limiter: Optional[AsyncLimiter] = AsyncLimiter( - max_rate=overall_max_rate, time_period=overall_time_period - ) - else: - self._base_limiter = None - - if group_max_rate and group_time_period: - self._group_max_rate: float = group_max_rate - self._group_time_period: float = group_time_period - else: - self._group_max_rate = 0 - self._group_time_period = 0 - - self._group_limiters: dict[Union[str, int], AsyncLimiter] = {} - self._max_retries: int = max_retries - self._retry_after_event = asyncio.Event() - self._retry_after_event.set() - - async def initialize(self) -> None: - """Does nothing.""" - - async def shutdown(self) -> None: - """Does nothing.""" - - def _get_group_limiter(self, group_id: Union[str, int, bool]) -> "AsyncLimiter": - # Remove limiters that haven't been used for so long that all their capacity is unused - # We only do that if we have a lot of limiters lying around to avoid looping on every call - # This is a minimal effort approach - a full-fledged cache could use a TTL approach - # or at least adapt the threshold dynamically depending on the number of active limiters - if len(self._group_limiters) > 512: - # We copy to avoid modifying the dict while we iterate over it - for key, limiter in self._group_limiters.copy().items(): - if key == group_id: - continue - if limiter.has_capacity(limiter.max_rate): - del self._group_limiters[key] - - if group_id not in self._group_limiters: - self._group_limiters[group_id] = AsyncLimiter( - max_rate=self._group_max_rate, - time_period=self._group_time_period, - ) - return self._group_limiters[group_id] - - async def _run_request( - self, - chat: bool, - group: Union[str, int, bool], - callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, list[JSONDict]]]], - args: Any, - kwargs: dict[str, Any], - ) -> Union[bool, JSONDict, list[JSONDict]]: - base_context = self._base_limiter if (chat and self._base_limiter) else null_context() - group_context = ( - self._get_group_limiter(group) if group and self._group_max_rate else null_context() - ) - - async with group_context, base_context: - # In case a retry_after was hit, we wait with processing the request - await self._retry_after_event.wait() - - return await callback(*args, **kwargs) - - # mypy doesn't understand that the last run of the for loop raises an exception - async def process_request( - self, - callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, list[JSONDict]]]], - args: Any, - kwargs: dict[str, Any], - endpoint: str, # noqa: ARG002 - data: dict[str, Any], - rate_limit_args: Optional[int], - ) -> Union[bool, JSONDict, list[JSONDict]]: - """ - Processes a request by applying rate limiting. - - See :meth:`telegram.ext.BaseRateLimiter.process_request` for detailed information on the - arguments. - - Args: - rate_limit_args (:obj:`None` | :obj:`int`): If set, specifies the maximum number of - retries to be made in case of a :exc:`~telegram.error.RetryAfter` exception. - Defaults to :paramref:`AIORateLimiter.max_retries`. - """ - max_retries = rate_limit_args or self._max_retries - - group: Union[int, str, bool] = False - chat: bool = False - chat_id = data.get("chat_id") - if chat_id is not None: - chat = True - - # In case user passes integer chat id as string - with contextlib.suppress(ValueError, TypeError): - chat_id = int(chat_id) - - if (isinstance(chat_id, int) and chat_id < 0) or isinstance(chat_id, str): - # string chat_id only works for channels and supergroups - # We can't really tell channels from groups though ... - group = chat_id - - for i in range(max_retries + 1): - try: - return await self._run_request( - chat=chat, group=group, callback=callback, args=args, kwargs=kwargs - ) - except RetryAfter as exc: - if i == max_retries: - _LOGGER.exception( - "Rate limit hit after maximum of %d retries", max_retries, exc_info=exc - ) - raise - - sleep = exc.retry_after + 0.1 - _LOGGER.info("Rate limit hit. Retrying after %f seconds", sleep) - # Make sure we don't allow other requests to be processed - self._retry_after_event.clear() - await asyncio.sleep(sleep) - finally: - # Allow other requests to be processed - self._retry_after_event.set() - return None # type: ignore[return-value] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_application.py b/venv/lib/python3.11/site-packages/telegram/ext/_application.py deleted file mode 100755 index 5815b34..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_application.py +++ /dev/null @@ -1,1917 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the Application class.""" - -import asyncio -import contextlib -import inspect -import itertools -import platform -import signal -import sys -from collections import defaultdict -from collections.abc import Awaitable, Coroutine, Generator, Mapping, Sequence -from copy import deepcopy -from pathlib import Path -from types import MappingProxyType, TracebackType -from typing import TYPE_CHECKING, Any, Callable, Generic, NoReturn, Optional, TypeVar, Union - -from telegram._update import Update -from telegram._utils.defaultvalue import ( - DEFAULT_80, - DEFAULT_IP, - DEFAULT_NONE, - DEFAULT_TRUE, - DefaultValue, -) -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import SCT, DVType, ODVInput -from telegram._utils.warnings import warn -from telegram.error import TelegramError -from telegram.ext._basepersistence import BasePersistence -from telegram.ext._contexttypes import ContextTypes -from telegram.ext._extbot import ExtBot -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._updater import Updater -from telegram.ext._utils.stack import was_called_by -from telegram.ext._utils.trackingdict import TrackingDict -from telegram.ext._utils.types import BD, BT, CCT, CD, JQ, RT, UD, ConversationKey, HandlerCallback -from telegram.warnings import PTBDeprecationWarning - -if TYPE_CHECKING: - from socket import socket - - from telegram import Message - from telegram.ext import ConversationHandler, JobQueue - from telegram.ext._applicationbuilder import InitApplicationBuilder - from telegram.ext._baseupdateprocessor import BaseUpdateProcessor - from telegram.ext._jobqueue import Job - -DEFAULT_GROUP: int = 0 - -_AppType = TypeVar("_AppType", bound="Application") # pylint: disable=invalid-name -_STOP_SIGNAL = object() -_DEFAULT_0 = DefaultValue(0) - -# Since python 3.12, the coroutine passed to create_task should not be an (async) generator. Remove -# this check when we drop support for python 3.11. -if sys.version_info >= (3, 12): - _CoroType = Awaitable[RT] -else: - _CoroType = Union[Generator["asyncio.Future[object]", None, RT], Awaitable[RT]] - -_ErrorCoroType = Optional[_CoroType[RT]] - -_LOGGER = get_logger(__name__) - - -class ApplicationHandlerStop(Exception): - """ - Raise this in a handler or an error handler to prevent execution of any other handler (even in - different groups). - - In order to use this exception in a :class:`telegram.ext.ConversationHandler`, pass the - optional :paramref:`state` parameter instead of returning the next state: - - .. code-block:: python - - async def conversation_callback(update, context): - ... - raise ApplicationHandlerStop(next_state) - - Note: - Has no effect, if the handler or error handler is run in a non-blocking way. - - Args: - state (:obj:`object`, optional): The next state of the conversation. - - Attributes: - state (:obj:`object`): Optional. The next state of the conversation. - """ - - __slots__ = ("state",) - - def __init__(self, state: Optional[object] = None) -> None: - super().__init__() - self.state: Optional[object] = state - - -class Application( - Generic[BT, CCT, UD, CD, BD, JQ], - contextlib.AbstractAsyncContextManager["Application"], -): - """This class dispatches all kinds of updates to its registered handlers, and is the entry - point to a PTB application. - - Tip: - This class may not be initialized directly. Use :class:`telegram.ext.ApplicationBuilder` - or :meth:`builder` (for convenience). - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with application: - # code - - is roughly equivalent to - - .. code:: python - - try: - await application.initialize() - # code - finally: - await application.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - This class is a :class:`~typing.Generic` class and accepts six type variables: - - 1. The type of :attr:`bot`. Must be :class:`telegram.Bot` or a subclass of that class. - 2. The type of the argument ``context`` of callback functions for (error) handlers and jobs. - Must be :class:`telegram.ext.CallbackContext` or a subclass of that class. This must be - consistent with the following types. - 3. The type of the values of :attr:`user_data`. - 4. The type of the values of :attr:`chat_data`. - 5. The type of :attr:`bot_data`. - 6. The type of :attr:`job_queue`. Must either be :class:`telegram.ext.JobQueue` or a subclass - of that or :obj:`None`. - - Examples: - :any:`Echo Bot ` - - .. seealso:: :wiki:`Your First Bot `, - :wiki:`Architecture Overview ` - - .. versionchanged:: 20.0 - - * Initialization is now done through the :class:`telegram.ext.ApplicationBuilder`. - * Removed the attribute ``groups``. - - Attributes: - bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers. - update_queue (:class:`asyncio.Queue`): The synchronized queue that will contain the - updates. - updater (:class:`telegram.ext.Updater`): Optional. The updater used by this application. - chat_data (:obj:`types.MappingProxyType`): A dictionary handlers can use to store data for - the chat. For each integer chat id, the corresponding value of this mapping is - available as :attr:`telegram.ext.CallbackContext.chat_data` in handler callbacks for - updates from that chat. - - .. versionchanged:: 20.0 - :attr:`chat_data` is now read-only. Note that the values of the mapping are still - mutable, i.e. editing ``context.chat_data`` within a handler callback is possible - (and encouraged), but editing the mapping ``application.chat_data`` itself is not. - - .. tip:: - - * Manually modifying :attr:`chat_data` is almost never needed and unadvisable. - * Entries are never deleted automatically from this mapping. If you want to delete - the data associated with a specific chat, e.g. if the bot got removed from that - chat, please use :meth:`drop_chat_data`. - - user_data (:obj:`types.MappingProxyType`): A dictionary handlers can use to store data for - the user. For each integer user id, the corresponding value of this mapping is - available as :attr:`telegram.ext.CallbackContext.user_data` in handler callbacks for - updates from that user. - - .. versionchanged:: 20.0 - :attr:`user_data` is now read-only. Note that the values of the mapping are still - mutable, i.e. editing ``context.user_data`` within a handler callback is possible - (and encouraged), but editing the mapping ``application.user_data`` itself is not. - - .. tip:: - - * Manually modifying :attr:`user_data` is almost never needed and unadvisable. - * Entries are never deleted automatically from this mapping. If you want to delete - the data associated with a specific user, e.g. if that user blocked the bot, - please use :meth:`drop_user_data`. - - bot_data (:obj:`dict`): A dictionary handlers can use to store data for the bot. - persistence (:class:`telegram.ext.BasePersistence`): The persistence class to - store data that should be persistent over restarts. - handlers (dict[:obj:`int`, list[:class:`telegram.ext.BaseHandler`]]): A dictionary mapping - each handler group to the list of handlers registered to that group. - - .. seealso:: - :meth:`add_handler`, :meth:`add_handlers`. - error_handlers (dict[:term:`coroutine function`, :obj:`bool`]): A dictionary where the keys - are error handlers and the values indicate whether they are to be run blocking. - - .. seealso:: - :meth:`add_error_handler` - context_types (:class:`telegram.ext.ContextTypes`): Specifies the types used by this - dispatcher for the ``context`` argument of handler and job callbacks. - post_init (:term:`coroutine function`): Optional. A callback that will be executed by - :meth:`Application.run_polling` and :meth:`Application.run_webhook` after initializing - the application via :meth:`initialize`. - post_shutdown (:term:`coroutine function`): Optional. A callback that will be executed by - :meth:`Application.run_polling` and :meth:`Application.run_webhook` after shutting down - the application via :meth:`shutdown`. - post_stop (:term:`coroutine function`): Optional. A callback that will be executed by - :meth:`Application.run_polling` and :meth:`Application.run_webhook` after stopping - the application via :meth:`stop`. - - .. versionadded:: 20.1 - - """ - - __slots__ = ( - ( # noqa: RUF005 - "__create_task_tasks", - "__update_fetcher_task", - "__update_persistence_event", - "__update_persistence_lock", - "__update_persistence_task", - "__stop_running_marker", - "_chat_data", - "_chat_ids_to_be_deleted_in_persistence", - "_chat_ids_to_be_updated_in_persistence", - "_conversation_handler_conversations", - "_initialized", - "_job_queue", - "_running", - "_update_processor", - "_user_data", - "_user_ids_to_be_deleted_in_persistence", - "_user_ids_to_be_updated_in_persistence", - "bot", - "bot_data", - "chat_data", - "context_types", - "error_handlers", - "handlers", - "persistence", - "post_init", - "post_shutdown", - "post_stop", - "update_queue", - "updater", - "user_data", - ) - # Allowing '__weakref__' creation here since we need it for the JobQueue - # Currently the __weakref__ slot is already created - # in the AsyncContextManager base class for pythons < 3.13 - + ("__weakref__",) - if sys.version_info >= (3, 13) - else () - ) - - def __init__( - self: "Application[BT, CCT, UD, CD, BD, JQ]", - *, - bot: BT, - update_queue: "asyncio.Queue[object]", - updater: Optional[Updater], - job_queue: JQ, - update_processor: "BaseUpdateProcessor", - persistence: Optional[BasePersistence[UD, CD, BD]], - context_types: ContextTypes[CCT, UD, CD, BD], - post_init: Optional[ - Callable[["Application[BT, CCT, UD, CD, BD, JQ]"], Coroutine[Any, Any, None]] - ], - post_shutdown: Optional[ - Callable[["Application[BT, CCT, UD, CD, BD, JQ]"], Coroutine[Any, Any, None]] - ], - post_stop: Optional[ - Callable[["Application[BT, CCT, UD, CD, BD, JQ]"], Coroutine[Any, Any, None]] - ], - ): - if not was_called_by( - inspect.currentframe(), Path(__file__).parent.resolve() / "_applicationbuilder.py" - ): - warn( - "`Application` instances should be built via the `ApplicationBuilder`.", - stacklevel=2, - ) - - self.bot: BT = bot - self.update_queue: asyncio.Queue[object] = update_queue - self.context_types: ContextTypes[CCT, UD, CD, BD] = context_types - self.updater: Optional[Updater] = updater - self.handlers: dict[int, list[BaseHandler[Any, CCT, Any]]] = {} - self.error_handlers: dict[ - HandlerCallback[object, CCT, None], Union[bool, DefaultValue[bool]] - ] = {} - self.post_init: Optional[ - Callable[[Application[BT, CCT, UD, CD, BD, JQ]], Coroutine[Any, Any, None]] - ] = post_init - self.post_shutdown: Optional[ - Callable[[Application[BT, CCT, UD, CD, BD, JQ]], Coroutine[Any, Any, None]] - ] = post_shutdown - self.post_stop: Optional[ - Callable[[Application[BT, CCT, UD, CD, BD, JQ]], Coroutine[Any, Any, None]] - ] = post_stop - self._update_processor = update_processor - self.bot_data: BD = self.context_types.bot_data() - self._user_data: defaultdict[int, UD] = defaultdict(self.context_types.user_data) - self._chat_data: defaultdict[int, CD] = defaultdict(self.context_types.chat_data) - # Read only mapping - self.user_data: Mapping[int, UD] = MappingProxyType(self._user_data) - self.chat_data: Mapping[int, CD] = MappingProxyType(self._chat_data) - - self.persistence: Optional[BasePersistence[UD, CD, BD]] = None - if persistence and not isinstance(persistence, BasePersistence): - raise TypeError("persistence must be based on telegram.ext.BasePersistence") - self.persistence = persistence - - # Some bookkeeping for persistence logic - self._chat_ids_to_be_updated_in_persistence: set[int] = set() - self._user_ids_to_be_updated_in_persistence: set[int] = set() - self._chat_ids_to_be_deleted_in_persistence: set[int] = set() - self._user_ids_to_be_deleted_in_persistence: set[int] = set() - - # This attribute will hold references to the conversation dicts of all conversation - # handlers so that we can extract the changed states during `update_persistence` - self._conversation_handler_conversations: dict[ - str, TrackingDict[ConversationKey, object] - ] = {} - - # A number of low-level helpers for the internal logic - self._initialized = False - self._running = False - self._job_queue: JQ = job_queue - self.__update_fetcher_task: Optional[asyncio.Task] = None - self.__update_persistence_task: Optional[asyncio.Task] = None - self.__update_persistence_event = asyncio.Event() - self.__update_persistence_lock = asyncio.Lock() - self.__create_task_tasks: set[asyncio.Task] = set() # Used for awaiting tasks upon exit - self.__stop_running_marker = asyncio.Event() - - async def __aenter__(self: _AppType) -> _AppType: # noqa: PYI019 - """|async_context_manager| :meth:`initializes ` the App. - - Returns: - The initialized App instance. - - Raises: - :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. - """ - try: - await self.initialize() - except Exception: - await self.shutdown() - raise - return self - - async def __aexit__( - self, - exc_type: Optional[type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - """|async_context_manager| :meth:`shuts down ` the App.""" - # Make sure not to return `True` so that exceptions are not suppressed - # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ - await self.shutdown() - - def __repr__(self) -> str: - """Give a string representation of the application in the form ``Application[bot=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs(self, bot=self.bot) - - @property - def running(self) -> bool: - """:obj:`bool`: Indicates if this application is running. - - .. seealso:: - :meth:`start`, :meth:`stop` - """ - return self._running - - @property - def concurrent_updates(self) -> int: - """:obj:`int`: The number of concurrent updates that will be processed in parallel. A - value of ``0`` indicates updates are *not* being processed concurrently. - - .. versionchanged:: 20.4 - This is now just a shortcut to :attr:`update_processor.max_concurrent_updates - `. - - .. seealso:: :wiki:`Concurrency` - """ - return self._update_processor.max_concurrent_updates - - @property - def job_queue(self) -> Optional["JobQueue[CCT]"]: - """ - :class:`telegram.ext.JobQueue`: The :class:`JobQueue` used by the - :class:`telegram.ext.Application`. - - .. seealso:: :wiki:`Job Queue ` - """ - if self._job_queue is None: - warn( - "No `JobQueue` set up. To use `JobQueue`, you must install PTB via " - '`pip install "python-telegram-bot[job-queue]"`.', - stacklevel=2, - ) - return self._job_queue - - @property - def update_processor(self) -> "BaseUpdateProcessor": - """:class:`telegram.ext.BaseUpdateProcessor`: The update processor used by this - application. - - .. seealso:: :wiki:`Concurrency` - - .. versionadded:: 20.4 - """ - return self._update_processor - - @staticmethod - def _raise_system_exit() -> NoReturn: - raise SystemExit - - @staticmethod - def builder() -> "InitApplicationBuilder": - """Convenience method. Returns a new :class:`telegram.ext.ApplicationBuilder`. - - .. versionadded:: 20.0 - """ - # Unfortunately this needs to be here due to cyclical imports - from telegram.ext import ApplicationBuilder # pylint: disable=import-outside-toplevel - - return ApplicationBuilder() - - def _check_initialized(self) -> None: - if not self._initialized: - raise RuntimeError( - "This Application was not initialized via `Application.initialize`!" - ) - - async def initialize(self) -> None: - """Initializes the Application by initializing: - - * The :attr:`bot`, by calling :meth:`telegram.Bot.initialize`. - * The :attr:`updater`, by calling :meth:`telegram.ext.Updater.initialize`. - * The :attr:`persistence`, by loading persistent conversations and data. - * The :attr:`update_processor` by calling - :meth:`telegram.ext.BaseUpdateProcessor.initialize`. - - Does *not* call :attr:`post_init` - that is only done by :meth:`run_polling` and - :meth:`run_webhook`. - - .. seealso:: - :meth:`shutdown` - """ - if self._initialized: - _LOGGER.debug("This Application is already initialized.") - return - - await self.bot.initialize() - await self._update_processor.initialize() - - if self.updater: - await self.updater.initialize() - - if not self.persistence: - self._initialized = True - return - - await self._initialize_persistence() - - # Unfortunately due to circular imports this has to be here - # pylint: disable=import-outside-toplevel - from telegram.ext._handlers.conversationhandler import ConversationHandler - - # Initialize the persistent conversation handlers with the stored states - for handler in itertools.chain.from_iterable(self.handlers.values()): - if isinstance(handler, ConversationHandler) and handler.persistent and handler.name: - await self._add_ch_to_persistence(handler) - - self._initialized = True - self.__stop_running_marker.clear() - - async def _add_ch_to_persistence(self, handler: "ConversationHandler") -> None: - self._conversation_handler_conversations.update( - await handler._initialize_persistence(self) # pylint: disable=protected-access - ) - - async def shutdown(self) -> None: - """Shuts down the Application by shutting down: - - * :attr:`bot` by calling :meth:`telegram.Bot.shutdown` - * :attr:`updater` by calling :meth:`telegram.ext.Updater.shutdown` - * :attr:`persistence` by calling :meth:`update_persistence` and - :meth:`BasePersistence.flush` - * :attr:`update_processor` by calling :meth:`telegram.ext.BaseUpdateProcessor.shutdown` - - Does *not* call :attr:`post_shutdown` - that is only done by :meth:`run_polling` and - :meth:`run_webhook`. - - .. seealso:: - :meth:`initialize` - - Raises: - :exc:`RuntimeError`: If the application is still :attr:`running`. - """ - if self.running: - raise RuntimeError("This Application is still running!") - - if not self._initialized: - _LOGGER.debug("This Application is already shut down. Returning.") - return - - await self.bot.shutdown() - await self._update_processor.shutdown() - - if self.updater: - await self.updater.shutdown() - - if self.persistence: - _LOGGER.debug("Updating & flushing persistence before shutdown") - await self.update_persistence() - await self.persistence.flush() - _LOGGER.debug("Updated and flushed persistence") - - self._initialized = False - - async def _initialize_persistence(self) -> None: - """This method basically just loads all the data by awaiting the BP methods""" - if not self.persistence: - return - - if self.persistence.store_data.user_data: - self._user_data.update(await self.persistence.get_user_data()) - if self.persistence.store_data.chat_data: - self._chat_data.update(await self.persistence.get_chat_data()) - if self.persistence.store_data.bot_data: - self.bot_data = await self.persistence.get_bot_data() - if not isinstance(self.bot_data, self.context_types.bot_data): - raise ValueError( - f"bot_data must be of type {self.context_types.bot_data.__name__}" - ) - - # Mypy doesn't know that persistence.set_bot (see above) already checks that - # self.bot is an instance of ExtBot if callback_data should be stored ... - if self.persistence.store_data.callback_data and ( - self.bot.callback_data_cache is not None # type: ignore[attr-defined] - ): - persistent_data = await self.persistence.get_callback_data() - if persistent_data is not None: - if not isinstance(persistent_data, tuple) or len(persistent_data) != 2: - raise ValueError("callback_data must be a tuple of length 2") - self.bot.callback_data_cache.load_persistence_data( # type: ignore[attr-defined] - persistent_data - ) - - async def start(self) -> None: - """Starts - - * a background task that fetches updates from :attr:`update_queue` and processes them via - :meth:`process_update`. - * :attr:`job_queue`, if set. - * a background task that calls :meth:`update_persistence` in regular intervals, if - :attr:`persistence` is set. - - Note: - This does *not* start fetching updates from Telegram. To fetch updates, you need to - either start :attr:`updater` manually or use one of :meth:`run_polling` or - :meth:`run_webhook`. - - Tip: - When using a custom logic for startup and shutdown of the application, eventual - cancellation of pending tasks should happen only `after` :meth:`stop` has been called - in order to ensure that the tasks mentioned above are not cancelled prematurely. - - .. seealso:: - :meth:`stop` - - Raises: - :exc:`RuntimeError`: If the application is already running or was not initialized. - """ - if self.running: - raise RuntimeError("This Application is already running!") - self._check_initialized() - - self._running = True - self.__update_persistence_event.clear() - - try: - if self.persistence: - self.__update_persistence_task = asyncio.create_task( - self._persistence_updater(), - name=f"Application:{self.bot.id}:persistence_updater", - ) - _LOGGER.debug("Loop for updating persistence started") - - if self._job_queue: - await self._job_queue.start() # type: ignore[union-attr] - _LOGGER.debug("JobQueue started") - - self.__update_fetcher_task = asyncio.create_task( - self._update_fetcher(), name=f"Application:{self.bot.id}:update_fetcher" - ) - _LOGGER.info("Application started") - - except Exception: - self._running = False - raise - - async def stop(self) -> None: - """Stops the process after processing any pending updates or tasks created by - :meth:`create_task`. Also stops :attr:`job_queue`, if set. - Finally, calls :meth:`update_persistence` and :meth:`BasePersistence.flush` on - :attr:`persistence`, if set. - - Warning: - Once this method is called, no more updates will be fetched from :attr:`update_queue`, - even if it's not empty. - - .. seealso:: - :meth:`start` - - Note: - * This does *not* stop :attr:`updater`. You need to either manually call - :meth:`telegram.ext.Updater.stop` or use one of :meth:`run_polling` or - :meth:`run_webhook`. - * Does *not* call :attr:`post_stop` - that is only done by - :meth:`run_polling` and :meth:`run_webhook`. - - Raises: - :exc:`RuntimeError`: If the application is not running. - """ - if not self.running: - raise RuntimeError("This Application is not running!") - - self._running = False - self.__stop_running_marker.clear() - _LOGGER.info("Application is stopping. This might take a moment.") - - # Stop listening for new updates and handle all pending ones - if self.__update_fetcher_task: - if self.__update_fetcher_task.done(): - try: - self.__update_fetcher_task.result() - except BaseException as exc: - _LOGGER.critical( - "Fetching updates was aborted due to %r. Suppressing " - "exception to ensure graceful shutdown.", - exc, - exc_info=True, - ) - else: - await self.update_queue.put(_STOP_SIGNAL) - _LOGGER.debug("Waiting for update_queue to join") - await self.update_queue.join() - await self.__update_fetcher_task - _LOGGER.debug("Application stopped fetching of updates.") - - if self._job_queue: - _LOGGER.debug("Waiting for running jobs to finish") - await self._job_queue.stop(wait=True) # type: ignore[union-attr] - _LOGGER.debug("JobQueue stopped") - - _LOGGER.debug("Waiting for `create_task` calls to be processed") - await asyncio.gather(*self.__create_task_tasks, return_exceptions=True) - - # Make sure that this is the *last* step of stopping the application! - if self.persistence and self.__update_persistence_task: - _LOGGER.debug("Waiting for persistence loop to finish") - self.__update_persistence_event.set() - await self.__update_persistence_task - self.__update_persistence_event.clear() - - _LOGGER.info("Application.stop() complete") - - def stop_running(self) -> None: - """This method can be used to stop the execution of :meth:`run_polling` or - :meth:`run_webhook` from within a handler, job or error callback. This allows a graceful - shutdown of the application, i.e. the methods listed in :attr:`run_polling` and - :attr:`run_webhook` will still be executed. - - This method can also be called within :meth:`post_init`. This allows for a graceful, - early shutdown of the application if some condition is met (e.g., a database connection - could not be established). - - Note: - If the application is not running and this method is not called within - :meth:`post_init`, this method does nothing. - - Warning: - This method is designed to for use in combination with :meth:`run_polling` or - :meth:`run_webhook`. Using this method in combination with a custom logic for starting - and stopping the application is not guaranteed to work as expected. Use at your own - risk. - - .. versionadded:: 20.5 - - .. versionchanged:: 21.2 - Added support for calling within :meth:`post_init`. - """ - if self.running: - # This works because `__run` is using `loop.run_forever()`. If that changes, this - # method needs to be adapted. - asyncio.get_running_loop().stop() - else: - self.__stop_running_marker.set() - if not self._initialized: - _LOGGER.debug( - "Application is not running and not initialized. `stop_running()` likely has " - "no effect." - ) - - def run_polling( - self, - poll_interval: float = 0.0, - timeout: int = 10, - bootstrap_retries: int = -1, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - allowed_updates: Optional[Sequence[str]] = None, - drop_pending_updates: Optional[bool] = None, - close_loop: bool = True, - stop_signals: ODVInput[Sequence[int]] = DEFAULT_NONE, - ) -> None: - """Convenience method that takes care of initializing and starting the app, - polling updates from Telegram using :meth:`telegram.ext.Updater.start_polling` and - a graceful shutdown of the app on exit. - - |app_run_shutdown| :paramref:`stop_signals`. - - The order of execution by :meth:`run_polling` is roughly as follows: - - - :meth:`initialize` - - :meth:`post_init` - - :meth:`telegram.ext.Updater.start_polling` - - :meth:`start` - - Run the application until the users stops it - - :meth:`telegram.ext.Updater.stop` - - :meth:`stop` - - :meth:`post_stop` - - :meth:`shutdown` - - :meth:`post_shutdown` - - A small wrapper is passed to :paramref:`telegram.ext.Updater.start_polling.error_callback` - which forwards errors occurring during polling to - :meth:`registered error handlers `. The update parameter of the callback - will be set to :obj:`None`. - - .. include:: inclusions/application_run_tip.rst - - Args: - poll_interval (:obj:`float`, optional): Time to wait between polling updates from - Telegram in seconds. Default is ``0.0``. - timeout (:obj:`int`, optional): Passed to - :paramref:`telegram.Bot.get_updates.timeout`. Default is ``10`` seconds. - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely (default) - * 0 - no retries - * > 0 - retry up to X times - - read_timeout (:obj:`float`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.read_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. versionchanged:: 20.7 - Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE` instead of - ``2``. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_read_timeout`. - write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.write_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_write_timeout`. - connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.connect_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_connect_timeout`. - pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.pool_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_pool_timeout`. - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - allowed_updates (Sequence[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.get_updates`. - - .. versionchanged:: 21.9 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - close_loop (:obj:`bool`, optional): If :obj:`True`, the current event loop will be - closed upon shutdown. Defaults to :obj:`True`. - - .. seealso:: - :meth:`asyncio.loop.close` - stop_signals (Sequence[:obj:`int`] | :obj:`None`, optional): Signals that will shut - down the app. Pass :obj:`None` to not use stop signals. - Defaults to :data:`signal.SIGINT`, :data:`signal.SIGTERM` and - :data:`signal.SIGABRT` on non Windows platforms. - - Caution: - Not every :class:`asyncio.AbstractEventLoop` implements - :meth:`asyncio.loop.add_signal_handler`. Most notably, the standard event loop - on Windows, :class:`asyncio.ProactorEventLoop`, does not implement this method. - If this method is not available, stop signals can not be set. - - Raises: - :exc:`RuntimeError`: If the Application does not have an :class:`telegram.ext.Updater`. - """ - if not self.updater: - raise RuntimeError( - "Application.run_polling is only available if the application has an Updater." - ) - - if (read_timeout, write_timeout, connect_timeout, pool_timeout) != ((DEFAULT_NONE,) * 4): - warn( - PTBDeprecationWarning( - "20.6", - "Setting timeouts via `Application.run_polling` is deprecated. " - "Please use `ApplicationBuilder.get_updates_*_timeout` instead.", - ), - stacklevel=2, - ) - - def error_callback(exc: TelegramError) -> None: - self.create_task(self.process_error(error=exc, update=None)) - - return self.__run( - updater_coroutine=self.updater.start_polling( - poll_interval=poll_interval, - timeout=timeout, - bootstrap_retries=bootstrap_retries, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - allowed_updates=allowed_updates, - drop_pending_updates=drop_pending_updates, - error_callback=error_callback, # if there is an error in fetching updates - ), - close_loop=close_loop, - stop_signals=stop_signals, - ) - - def run_webhook( - self, - listen: DVType[str] = DEFAULT_IP, - port: DVType[int] = DEFAULT_80, - url_path: str = "", - cert: Optional[Union[str, Path]] = None, - key: Optional[Union[str, Path]] = None, - bootstrap_retries: int = 0, - webhook_url: Optional[str] = None, - allowed_updates: Optional[Sequence[str]] = None, - drop_pending_updates: Optional[bool] = None, - ip_address: Optional[str] = None, - max_connections: int = 40, - close_loop: bool = True, - stop_signals: ODVInput[Sequence[int]] = DEFAULT_NONE, - secret_token: Optional[str] = None, - unix: Optional[Union[str, Path, "socket"]] = None, - ) -> None: - """Convenience method that takes care of initializing and starting the app, - listening for updates from Telegram using :meth:`telegram.ext.Updater.start_webhook` and - a graceful shutdown of the app on exit. - - |app_run_shutdown| :paramref:`stop_signals`. - - If :paramref:`cert` - and :paramref:`key` are not provided, the webhook will be started directly on - ``http://listen:port/url_path``, so SSL can be handled by another - application. Else, the webhook will be started on - ``https://listen:port/url_path``. Also calls :meth:`telegram.Bot.set_webhook` as - required. - - The order of execution by :meth:`run_webhook` is roughly as follows: - - - :meth:`initialize` - - :meth:`post_init` - - :meth:`telegram.ext.Updater.start_webhook` - - :meth:`start` - - Run the application until the users stops it - - :meth:`telegram.ext.Updater.stop` - - :meth:`stop` - - :meth:`post_stop` - - :meth:`shutdown` - - :meth:`post_shutdown` - - Important: - If you want to use this method, you must install PTB with the optional requirement - ``webhooks``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[webhooks]" - - .. include:: inclusions/application_run_tip.rst - - .. seealso:: - :wiki:`Webhooks` - - Args: - listen (:obj:`str`, optional): IP-Address to listen on. Defaults to - `127.0.0.1 `_. - port (:obj:`int`, optional): Port the bot should be listening on. Must be one of - :attr:`telegram.constants.SUPPORTED_WEBHOOK_PORTS` unless the bot is running - behind a proxy. Defaults to ``80``. - url_path (:obj:`str`, optional): Path inside url. Defaults to `` '' `` - cert (:class:`pathlib.Path` | :obj:`str`, optional): Path to the SSL certificate file. - key (:class:`pathlib.Path` | :obj:`str`, optional): Path to the SSL key file. - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely - * 0 - no retries (default) - * > 0 - retry up to X times - webhook_url (:obj:`str`, optional): Explicitly specify the webhook url. Useful behind - NAT, reverse proxy, etc. Default is derived from :paramref:`listen`, - :paramref:`port`, :paramref:`url_path`, :paramref:`cert`, and :paramref:`key`. - allowed_updates (Sequence[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.set_webhook`. - - .. versionchanged:: 21.9 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - ip_address (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`. - max_connections (:obj:`int`, optional): Passed to - :meth:`telegram.Bot.set_webhook`. Defaults to ``40``. - close_loop (:obj:`bool`, optional): If :obj:`True`, the current event loop will be - closed upon shutdown. Defaults to :obj:`True`. - - .. seealso:: - :meth:`asyncio.loop.close` - stop_signals (Sequence[:obj:`int`] | :obj:`None`, optional): Signals that will shut - down the app. Pass :obj:`None` to not use stop signals. - Defaults to :data:`signal.SIGINT`, :data:`signal.SIGTERM` and - :data:`signal.SIGABRT`. - - Caution: - Not every :class:`asyncio.AbstractEventLoop` implements - :meth:`asyncio.loop.add_signal_handler`. Most notably, the standard event loop - on Windows, :class:`asyncio.ProactorEventLoop`, does not implement this method. - If this method is not available, stop signals can not be set. - secret_token (:obj:`str`, optional): Secret token to ensure webhook requests originate - from Telegram. See :paramref:`telegram.Bot.set_webhook.secret_token` for more - details. - - When added, the web server started by this call will expect the token to be set in - the ``X-Telegram-Bot-Api-Secret-Token`` header of an incoming request and will - raise a :class:`http.HTTPStatus.FORBIDDEN ` error if either the - header isn't set or it is set to a wrong token. - - .. versionadded:: 20.0 - unix (:class:`pathlib.Path` | :obj:`str` | :class:`socket.socket`, optional): Can be - either: - - * the path to the unix socket file as :class:`pathlib.Path` or :obj:`str`. This - will be passed to `tornado.netutil.bind_unix_socket `_ to create the socket. - If the Path does not exist, the file will be created. - - * or the socket itself. This option allows you to e.g. restrict the permissions of - the socket for improved security. Note that you need to pass the correct family, - type and socket options yourself. - - Caution: - This parameter is a replacement for the default TCP bind. Therefore, it is - mutually exclusive with :paramref:`listen` and :paramref:`port`. When using - this param, you must also run a reverse proxy to the unix socket and set the - appropriate :paramref:`webhook_url`. - - .. versionadded:: 20.8 - .. versionchanged:: 21.1 - Added support to pass a socket instance itself. - """ - if not self.updater: - raise RuntimeError( - "Application.run_webhook is only available if the application has an Updater." - ) - - return self.__run( - updater_coroutine=self.updater.start_webhook( - listen=listen, - port=port, - url_path=url_path, - cert=cert, - key=key, - bootstrap_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url=webhook_url, - allowed_updates=allowed_updates, - ip_address=ip_address, - max_connections=max_connections, - secret_token=secret_token, - unix=unix, - ), - close_loop=close_loop, - stop_signals=stop_signals, - ) - - def __run( - self, - updater_coroutine: Coroutine, - stop_signals: ODVInput[Sequence[int]], - close_loop: bool = True, - ) -> None: - # Calling get_event_loop() should still be okay even in py3.10+ as long as there is a - # running event loop or we are in the main thread, which are the intended use cases. - # See the docs of get_event_loop() and get_running_loop() for more info - loop = asyncio.get_event_loop() - - if stop_signals is DEFAULT_NONE and platform.system() != "Windows": - stop_signals = (signal.SIGINT, signal.SIGTERM, signal.SIGABRT) - - try: - if not isinstance(stop_signals, DefaultValue): - for sig in stop_signals or []: - loop.add_signal_handler(sig, self._raise_system_exit) - except NotImplementedError as exc: - warn( - f"Could not add signal handlers for the stop signals {stop_signals} due to " - f"exception `{exc!r}`. If your event loop does not implement `add_signal_handler`," - " please pass `stop_signals=None`.", - stacklevel=3, - ) - - try: - loop.run_until_complete(self.initialize()) - if self.post_init: - loop.run_until_complete(self.post_init(self)) - if self.__stop_running_marker.is_set(): - _LOGGER.info("Application received stop signal via `stop_running`. Shutting down.") - return - loop.run_until_complete(updater_coroutine) # one of updater.start_webhook/polling - loop.run_until_complete(self.start()) - loop.run_forever() - except (KeyboardInterrupt, SystemExit): - _LOGGER.debug("Application received stop signal. Shutting down.") - finally: - # We arrive here either by catching the exceptions above or if the loop gets stopped - # In case the coroutine wasn't awaited, we don't need to bother the user with a warning - updater_coroutine.close() - - try: - # Mypy doesn't know that we already check if updater is None - if self.updater.running: # type: ignore[union-attr] - loop.run_until_complete(self.updater.stop()) # type: ignore[union-attr] - if self.running: - loop.run_until_complete(self.stop()) - # post_stop should be called only if stop was called! - if self.post_stop: - loop.run_until_complete(self.post_stop(self)) - loop.run_until_complete(self.shutdown()) - if self.post_shutdown: - loop.run_until_complete(self.post_shutdown(self)) - finally: - if close_loop: - loop.close() - - def create_task( - self, - coroutine: _CoroType[RT], - update: Optional[object] = None, - *, - name: Optional[str] = None, - ) -> "asyncio.Task[RT]": - """Thin wrapper around :func:`asyncio.create_task` that handles exceptions raised by - the :paramref:`coroutine` with :meth:`process_error`. - - Note: - * If :paramref:`coroutine` raises an exception, it will be set on the task created by - this method even though it's handled by :meth:`process_error`. - * If the application is currently running, tasks created by this method will be - awaited with :meth:`stop`. - - .. seealso:: :wiki:`Concurrency` - - Args: - coroutine (:term:`awaitable`): The awaitable to run as task. - - .. versionchanged:: 20.2 - Accepts :class:`asyncio.Future` and generator-based coroutine functions. - .. deprecated:: 20.4 - Since Python 3.12, generator-based coroutine functions are no longer accepted. - update (:obj:`object`, optional): If set, will be passed to :meth:`process_error` - as additional information for the error handlers. Moreover, the corresponding - :attr:`chat_data` and :attr:`user_data` entries will be updated in the next run of - :meth:`update_persistence` after the :paramref:`coroutine` is finished. - - Keyword Args: - name (:obj:`str`, optional): The name of the task. - - .. versionadded:: 20.4 - - Returns: - :class:`asyncio.Task`: The created task. - """ - return self.__create_task(coroutine=coroutine, update=update, name=name) - - def __create_task( - self, - coroutine: _CoroType[RT], - update: Optional[object] = None, - is_error_handler: bool = False, - name: Optional[str] = None, - ) -> "asyncio.Task[RT]": - # Unfortunately, we can't know if `coroutine` runs one of the error handler functions - # but by passing `is_error_handler=True` from `process_error`, we can make sure that we - # get at most one recursion of the user calls `create_task` manually with an error handler - # function - task: asyncio.Task[RT] = asyncio.create_task( - self.__create_task_callback( - coroutine=coroutine, update=update, is_error_handler=is_error_handler - ), - name=name, - ) - - if self.running: - self.__create_task_tasks.add(task) - task.add_done_callback(self.__create_task_done_callback) - else: - warn( - "Tasks created via `Application.create_task` while the application is not " - "running won't be automatically awaited!", - stacklevel=3, - ) - - return task - - def __create_task_done_callback(self, task: asyncio.Task) -> None: - self.__create_task_tasks.discard(task) # Discard from our set since we are done with it - # We just retrieve the eventual exception so that asyncio doesn't complain in case - # it's not retrieved somewhere else - with contextlib.suppress(asyncio.CancelledError, asyncio.InvalidStateError): - task.exception() - - async def __create_task_callback( - self, - coroutine: _CoroType[RT], - update: Optional[object] = None, - is_error_handler: bool = False, - ) -> RT: - try: - # Generator-based coroutines are not supported in Python 3.12+ - if sys.version_info < (3, 12) and isinstance(coroutine, Generator): - warn( - PTBDeprecationWarning( - "20.4", - "Generator-based coroutines are deprecated in create_task and will not" - " work in Python 3.12+", - ), - ) - return await asyncio.create_task(coroutine) - # If user uses generator in python 3.12+, Exception will happen and we cannot do - # anything about it. (hence the type ignore if mypy is run on python 3.12-) - return await coroutine # type: ignore[misc] - except Exception as exception: - if isinstance(exception, ApplicationHandlerStop): - warn( - "ApplicationHandlerStop is not supported with handlers running non-blocking.", - stacklevel=1, - ) - - # Avoid infinite recursion of error handlers. - elif is_error_handler: - _LOGGER.exception( - "An error was raised and an uncaught error was raised while " - "handling the error with an error_handler.", - exc_info=exception, - ) - - else: - # If we arrive here, an exception happened in the task and was neither - # ApplicationHandlerStop nor raised by an error handler. - # So we can and must handle it - await self.process_error(update=update, error=exception, coroutine=coroutine) - - # Raise exception so that it can be set on the task and retrieved by task.exception() - raise - finally: - self._mark_for_persistence_update(update=update) - - async def __update_fetcher(self) -> None: - # Continuously fetch updates from the queue. Exit only once the signal object is found. - while True: - update = await self.update_queue.get() - - if update is _STOP_SIGNAL: - # For the _STOP_SIGNAL - self.update_queue.task_done() - return - - _LOGGER.debug("Processing update %s", update) - - if self._update_processor.max_concurrent_updates > 1: - # We don't await the below because it has to be run concurrently - self.create_task( - self.__process_update_wrapper(update), - update=update, - name=f"Application:{self.bot.id}:process_concurrent_update", - ) - else: - await self.__process_update_wrapper(update) - - async def _update_fetcher(self) -> None: - try: - await self.__update_fetcher() - finally: - while not self.update_queue.empty(): - _LOGGER.debug("Dropping pending update: %s", self.update_queue.get_nowait()) - with contextlib.suppress(ValueError): - # Since we're shutting down here, it's not too bad if we call task_done - # on an empty queue - self.update_queue.task_done() - - async def __process_update_wrapper(self, update: object) -> None: - try: - await self._update_processor.process_update(update, self.process_update(update)) - finally: - self.update_queue.task_done() - - async def process_update(self, update: object) -> None: - """Processes a single update and marks the update to be updated by the persistence later. - Exceptions raised by handler callbacks will be processed by :meth:`process_error`. - - .. seealso:: :wiki:`Concurrency` - - .. versionchanged:: 20.0 - Persistence is now updated in an interval set by - :attr:`telegram.ext.BasePersistence.update_interval`. - - Args: - update (:class:`telegram.Update` | :obj:`object` | \ - :class:`telegram.error.TelegramError`): The update to process. - - Raises: - :exc:`RuntimeError`: If the application was not initialized. - """ - # Processing updates before initialize() is a problem e.g. if persistence is used - self._check_initialized() - - context = None - any_blocking = False # Flag which is set to True if any handler specifies block=True - - for handlers in self.handlers.values(): - try: - for handler in handlers: - check = handler.check_update(update) # Should the handler handle this update? - if check is None or check is False: - continue - - if not context: # build a context if not already built - try: - context = self.context_types.context.from_update(update, self) - except Exception as exc: - _LOGGER.critical( - ( - "Error while building CallbackContext for update %s. " - "Update will not be processed." - ), - update, - exc_info=exc, - ) - return - await context.refresh_data() - coroutine: Coroutine = handler.handle_update(update, self, check, context) - - if not handler.block or ( # if handler is running with block=False, - handler.block is DEFAULT_TRUE - and isinstance(self.bot, ExtBot) - and self.bot.defaults - and not self.bot.defaults.block - ): - self.create_task( - coroutine, - update=update, - name=( - f"Application:{self.bot.id}:process_update_non_blocking" - f":{handler}" - ), - ) - else: - any_blocking = True - await coroutine - break # Only a max of 1 handler per group is handled - - # Stop processing with any other handler. - except ApplicationHandlerStop: - _LOGGER.debug("Stopping further handlers due to ApplicationHandlerStop") - break - - # Dispatch any error. - except Exception as exc: - if await self.process_error(update=update, error=exc): - _LOGGER.debug("Error handler stopped further handlers.") - break - - if any_blocking: - # Only need to mark the update for persistence if there was at least one - # blocking handler - the non-blocking handlers mark the update again when finished - # (in __create_task_callback) - self._mark_for_persistence_update(update=update) - - def add_handler(self, handler: BaseHandler[Any, CCT, Any], group: int = DEFAULT_GROUP) -> None: - """Register a handler. - - TL;DR: Order and priority counts. 0 or 1 handlers per group will be used. End handling of - update with :class:`telegram.ext.ApplicationHandlerStop`. - - A handler must be an instance of a subclass of :class:`telegram.ext.BaseHandler`. All - handlers - are organized in groups with a numeric value. The default group is 0. All groups will be - evaluated for handling an update, but only 0 or 1 handler per group will be used. If - :class:`telegram.ext.ApplicationHandlerStop` is raised from one of the handlers, no further - handlers (regardless of the group) will be called. - - The priority/order of handlers is determined as follows: - - * Priority of the group (lower group number == higher priority) - * The first handler in a group which can handle an update (see - :attr:`telegram.ext.BaseHandler.check_update`) will be used. Other handlers from the - group will not be used. The order in which handlers were added to the group defines the - priority. - - Warning: - Adding persistent :class:`telegram.ext.ConversationHandler` after the application has - been initialized is discouraged. This is because the persisted conversation states need - to be loaded into memory while the application is already processing updates, which - might lead to race conditions and undesired behavior. In particular, current - conversation states may be overridden by the loaded data. - - Args: - handler (:class:`telegram.ext.BaseHandler`): A BaseHandler instance. - group (:obj:`int`, optional): The group identifier. Default is ``0``. - - """ - # Unfortunately due to circular imports this has to be here - # pylint: disable=import-outside-toplevel - from telegram.ext._handlers.conversationhandler import ConversationHandler - - if not isinstance(handler, BaseHandler): - raise TypeError(f"handler is not an instance of {BaseHandler.__name__}") - if not isinstance(group, int): - raise TypeError("group is not int") - if isinstance(handler, ConversationHandler) and handler.persistent and handler.name: - if not self.persistence: - raise ValueError( - f"ConversationHandler {handler.name} " - "can not be persistent if application has no persistence" - ) - if self._initialized: - self.create_task( - self._add_ch_to_persistence(handler), - name=f"Application:{self.bot.id}:add_handler:conversation_handler_after_init", - ) - warn( - "A persistent `ConversationHandler` was passed to `add_handler`, " - "after `Application.initialize` was called. This is discouraged." - "See the docs of `Application.add_handler` for details.", - stacklevel=2, - ) - - if group not in self.handlers: - self.handlers[group] = [] - self.handlers = dict(sorted(self.handlers.items())) # lower -> higher groups - - self.handlers[group].append(handler) - - def add_handlers( - self, - handlers: Union[ - Sequence[BaseHandler[Any, CCT, Any]], - dict[int, Sequence[BaseHandler[Any, CCT, Any]]], - ], - group: Union[int, DefaultValue[int]] = _DEFAULT_0, - ) -> None: - """Registers multiple handlers at once. The order of the handlers in the passed - sequence(s) matters. See :meth:`add_handler` for details. - - .. versionadded:: 20.0 - - Args: - handlers (Sequence[:class:`telegram.ext.BaseHandler`] | \ - dict[int, Sequence[:class:`telegram.ext.BaseHandler`]]): - Specify a sequence of handlers *or* a dictionary where the keys are groups and - values are handlers. - - .. versionchanged:: 21.7 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - or tuple. - - group (:obj:`int`, optional): Specify which group the sequence of :paramref:`handlers` - should be added to. Defaults to ``0``. - - Example:: - - app.add_handlers(handlers={ - -1: [MessageHandler(...)], - 1: [CallbackQueryHandler(...), CommandHandler(...)] - } - - Raises: - :exc:`TypeError`: If the combination of arguments is invalid. - """ - if isinstance(handlers, dict) and not isinstance(group, DefaultValue): - raise TypeError("The `group` argument can only be used with a sequence of handlers.") - - if isinstance(handlers, dict): - for handler_group, grp_handlers in handlers.items(): - if not isinstance(grp_handlers, Sequence): - raise TypeError( - f"Handlers for group {handler_group} must be a sequence of handlers." - ) - - for handler in grp_handlers: - self.add_handler(handler, handler_group) - - elif isinstance(handlers, Sequence): - for handler in handlers: - self.add_handler(handler, DefaultValue.get_value(group)) - - else: - raise TypeError( - "The `handlers` argument must be a sequence of handlers or a " - "dictionary where the keys are groups and values are sequences of handlers." - ) - - def remove_handler( - self, handler: BaseHandler[Any, CCT, Any], group: int = DEFAULT_GROUP - ) -> None: - """Remove a handler from the specified group. - - Args: - handler (:class:`telegram.ext.BaseHandler`): A :class:`telegram.ext.BaseHandler` - instance. - group (:obj:`object`, optional): The group identifier. Default is ``0``. - - """ - if handler in self.handlers[group]: - self.handlers[group].remove(handler) - if not self.handlers[group]: - del self.handlers[group] - - def drop_chat_data(self, chat_id: int) -> None: - """Drops the corresponding entry from the :attr:`chat_data`. Will also be deleted from - the persistence on the next run of :meth:`update_persistence`, if applicable. - - Warning: - When using :attr:`concurrent_updates` or the :attr:`job_queue`, - :meth:`process_update` or :meth:`telegram.ext.Job.run` may re-create this entry due to - the asynchronous nature of these features. Please make sure that your program can - avoid or handle such situations. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`): The chat id to delete. The entry will be deleted even if it is - not empty. - """ - self._chat_data.pop(chat_id, None) - self._chat_ids_to_be_deleted_in_persistence.add(chat_id) - - def drop_user_data(self, user_id: int) -> None: - """Drops the corresponding entry from the :attr:`user_data`. Will also be deleted from - the persistence on the next run of :meth:`update_persistence`, if applicable. - - Warning: - When using :attr:`concurrent_updates` or the :attr:`job_queue`, - :meth:`process_update` or :meth:`telegram.ext.Job.run` may re-create this entry due to - the asynchronous nature of these features. Please make sure that your program can - avoid or handle such situations. - - .. versionadded:: 20.0 - - Args: - user_id (:obj:`int`): The user id to delete. The entry will be deleted even if it is - not empty. - """ - self._user_data.pop(user_id, None) - self._user_ids_to_be_deleted_in_persistence.add(user_id) - - def migrate_chat_data( - self, - message: Optional["Message"] = None, - old_chat_id: Optional[int] = None, - new_chat_id: Optional[int] = None, - ) -> None: - """Moves the contents of :attr:`chat_data` at key :paramref:`old_chat_id` to the key - :paramref:`new_chat_id`. Also marks the entries to be updated accordingly in the next run - of :meth:`update_persistence`. - - Warning: - * Any data stored in :attr:`chat_data` at key :paramref:`new_chat_id` will be - overridden - * The key :paramref:`old_chat_id` of :attr:`chat_data` will be deleted - * This does not update the :attr:`~telegram.ext.Job.chat_id` attribute of any scheduled - :class:`telegram.ext.Job`. - - When using :attr:`concurrent_updates` or the :attr:`job_queue`, - :meth:`process_update` or :meth:`telegram.ext.Job.run` may re-create the old entry due - to the asynchronous nature of these features. Please make sure that your program can - avoid or handle such situations. - - .. seealso:: :wiki:`Storing Bot, User and Chat Related Data\ - ` - - Args: - message (:class:`telegram.Message`, optional): A message with either - :attr:`~telegram.Message.migrate_from_chat_id` or - :attr:`~telegram.Message.migrate_to_chat_id`. - Mutually exclusive with passing :paramref:`old_chat_id` and - :paramref:`new_chat_id`. - - .. seealso:: - :attr:`telegram.ext.filters.StatusUpdate.MIGRATE` - - old_chat_id (:obj:`int`, optional): The old chat ID. - Mutually exclusive with passing :paramref:`message` - new_chat_id (:obj:`int`, optional): The new chat ID. - Mutually exclusive with passing :paramref:`message` - - Raises: - ValueError: Raised if the input is invalid. - """ - if message and (old_chat_id or new_chat_id): - raise ValueError("Message and chat_id pair are mutually exclusive") - if not any((message, old_chat_id, new_chat_id)): - raise ValueError("chat_id pair or message must be passed") - - if message: - if message.migrate_from_chat_id is None and message.migrate_to_chat_id is None: - raise ValueError( - "Invalid message instance. The message must have either " - "`Message.migrate_from_chat_id` or `Message.migrate_to_chat_id`." - ) - - old_chat_id = message.migrate_from_chat_id or message.chat.id - new_chat_id = message.migrate_to_chat_id or message.chat.id - - elif not (isinstance(old_chat_id, int) and isinstance(new_chat_id, int)): - raise ValueError("old_chat_id and new_chat_id must be integers") - - self._chat_data[new_chat_id] = self._chat_data[old_chat_id] - self.drop_chat_data(old_chat_id) - - self._chat_ids_to_be_updated_in_persistence.add(new_chat_id) - # old_chat_id is marked for deletion by drop_chat_data above - - def _mark_for_persistence_update( - self, *, update: Optional[object] = None, job: Optional["Job"] = None - ) -> None: - if isinstance(update, Update): - if update.effective_chat: - self._chat_ids_to_be_updated_in_persistence.add(update.effective_chat.id) - if update.effective_user: - self._user_ids_to_be_updated_in_persistence.add(update.effective_user.id) - - if job: - if job.chat_id: - self._chat_ids_to_be_updated_in_persistence.add(job.chat_id) - if job.user_id: - self._user_ids_to_be_updated_in_persistence.add(job.user_id) - - def mark_data_for_update_persistence( - self, chat_ids: Optional[SCT[int]] = None, user_ids: Optional[SCT[int]] = None - ) -> None: - """Mark entries of :attr:`chat_data` and :attr:`user_data` to be updated on the next - run of :meth:`update_persistence`. - - Tip: - Use this method sparingly. If you have to use this method, it likely means that you - access and modify ``context.application.chat/user_data[some_id]`` within a callback. - Note that for data which should be available globally in all handler callbacks - independent of the chat/user, it is recommended to use :attr:`bot_data` instead. - - .. versionadded:: 20.3 - - Args: - chat_ids (:obj:`int` | Collection[:obj:`int`], optional): Chat IDs to mark. - user_ids (:obj:`int` | Collection[:obj:`int`], optional): User IDs to mark. - - """ - if chat_ids: - if isinstance(chat_ids, int): - self._chat_ids_to_be_updated_in_persistence.add(chat_ids) - else: - self._chat_ids_to_be_updated_in_persistence.update(chat_ids) - if user_ids: - if isinstance(user_ids, int): - self._user_ids_to_be_updated_in_persistence.add(user_ids) - else: - self._user_ids_to_be_updated_in_persistence.update(user_ids) - - async def _persistence_updater(self) -> None: - # Update the persistence in regular intervals. Exit only when the stop event has been set - while not self.__update_persistence_event.is_set(): - if not self.persistence: - return - - # asyncio synchronization primitives don't accept a timeout argument, it is recommended - # to use wait_for instead - try: - await asyncio.wait_for( - self.__update_persistence_event.wait(), - timeout=self.persistence.update_interval, - ) - except asyncio.TimeoutError: - pass - else: - return - - # putting this *after* the wait_for so we don't immediately update on startup as - # that would make little sense - await self.update_persistence() - - async def update_persistence(self) -> None: - """Updates :attr:`user_data`, :attr:`chat_data`, :attr:`bot_data` in :attr:`persistence` - along with :attr:`~telegram.ext.ExtBot.callback_data_cache` and the conversation states of - any persistent :class:`~telegram.ext.ConversationHandler` registered for this application. - - For :attr:`user_data` and :attr:`chat_data`, only those entries are updated which either - were used or have been manually marked via :meth:`mark_data_for_update_persistence` since - the last run of this method. - - Tip: - This method will be called in regular intervals by the application. There is usually - no need to call it manually. - - Note: - Any data is deep copied with :func:`copy.deepcopy` before handing it over to the - persistence in order to avoid race conditions, so all persisted data must be copyable. - - .. seealso:: :attr:`telegram.ext.BasePersistence.update_interval`, - :meth:`mark_data_for_update_persistence` - """ - async with self.__update_persistence_lock: - await self.__update_persistence() - - async def __update_persistence(self) -> None: - if not self.persistence: - return - - _LOGGER.debug("Starting next run of updating the persistence.") - - coroutines: set[Coroutine] = set() - - # Mypy doesn't know that persistence.set_bot (see above) already checks that - # self.bot is an instance of ExtBot if callback_data should be stored ... - if self.persistence.store_data.callback_data and ( - self.bot.callback_data_cache is not None # type: ignore[attr-defined] - ): - coroutines.add( - self.persistence.update_callback_data( - deepcopy( - self.bot.callback_data_cache.persistence_data # type: ignore[attr-defined] - ) - ) - ) - - if self.persistence.store_data.bot_data: - coroutines.add(self.persistence.update_bot_data(deepcopy(self.bot_data))) - - if self.persistence.store_data.chat_data: - update_ids = self._chat_ids_to_be_updated_in_persistence - self._chat_ids_to_be_updated_in_persistence = set() - delete_ids = self._chat_ids_to_be_deleted_in_persistence - self._chat_ids_to_be_deleted_in_persistence = set() - - # We don't want to update any data that has been deleted! - update_ids -= delete_ids - - for chat_id in update_ids: - coroutines.add( - self.persistence.update_chat_data(chat_id, deepcopy(self.chat_data[chat_id])) - ) - for chat_id in delete_ids: - coroutines.add(self.persistence.drop_chat_data(chat_id)) - - if self.persistence.store_data.user_data: - update_ids = self._user_ids_to_be_updated_in_persistence - self._user_ids_to_be_updated_in_persistence = set() - delete_ids = self._user_ids_to_be_deleted_in_persistence - self._user_ids_to_be_deleted_in_persistence = set() - - # We don't want to update any data that has been deleted! - update_ids -= delete_ids - - for user_id in update_ids: - coroutines.add( - self.persistence.update_user_data(user_id, deepcopy(self.user_data[user_id])) - ) - for user_id in delete_ids: - coroutines.add(self.persistence.drop_user_data(user_id)) - - # Unfortunately due to circular imports this has to be here - # pylint: disable=import-outside-toplevel - from telegram.ext._handlers.conversationhandler import PendingState - - for name, (key, new_state) in itertools.chain.from_iterable( - zip(itertools.repeat(name), states_dict.pop_accessed_write_items()) - for name, states_dict in self._conversation_handler_conversations.items() - ): - if isinstance(new_state, PendingState): - # If the handler was running non-blocking, we check if the new state is already - # available. Otherwise, we update with the old state, which is the next best - # guess. - # Note that when updating the persistence one last time during self.stop(), - # *all* tasks will be done. - if not new_state.done(): - if self.running: - _LOGGER.debug( - "A ConversationHandlers state was not yet resolved. Updating the " - "persistence with the current state. Will check again on next run of " - "Application.update_persistence." - ) - else: - _LOGGER.warning( - "A ConversationHandlers state was not yet resolved. Updating the " - "persistence with the current state." - ) - result = new_state.old_state - # We need to check again on the next run if the state is done - self._conversation_handler_conversations[name].mark_as_accessed(key) - else: - result = new_state.resolve() - else: - result = new_state - - effective_new_state = None if result is TrackingDict.DELETED else result - coroutines.add( - self.persistence.update_conversation( - name=name, key=key, new_state=effective_new_state - ) - ) - - results = await asyncio.gather(*coroutines, return_exceptions=True) - _LOGGER.debug("Finished updating persistence.") - - # dispatch any errors - await asyncio.gather( - *( - self.process_error(error=result, update=None) - for result in results - if isinstance(result, Exception) - ) - ) - - def add_error_handler( - self, - callback: HandlerCallback[object, CCT, None], - block: DVType[bool] = DEFAULT_TRUE, - ) -> None: - """Registers an error handler in the Application. This handler will receive every error - which happens in your bot. See the docs of :meth:`process_error` for more details on how - errors are handled. - - Note: - Attempts to add the same callback multiple times will be ignored. - - Examples: - :any:`Errorhandler Bot ` - - .. seealso:: :wiki:`Exceptions, Warnings and Logging ` - - Args: - callback (:term:`coroutine function`): The callback function for this error handler. - Will be called when an error is raised. Callback signature:: - - async def callback(update: Optional[object], context: CallbackContext) - - The error that happened will be present in - :attr:`telegram.ext.CallbackContext.error`. - block (:obj:`bool`, optional): Determines whether the return value of the callback - should be awaited before processing the next error handler in - :meth:`process_error`. Defaults to :obj:`True`. - """ - if callback in self.error_handlers: - _LOGGER.warning("The callback is already registered as an error handler. Ignoring.") - return - - self.error_handlers[callback] = block - - def remove_error_handler(self, callback: HandlerCallback[object, CCT, None]) -> None: - """Removes an error handler. - - Args: - callback (:term:`coroutine function`): The error handler to remove. - - """ - self.error_handlers.pop(callback, None) - - async def process_error( - self, - update: Optional[object], - error: Exception, - job: Optional["Job[CCT]"] = None, - coroutine: Optional[_ErrorCoroType[RT]] = None, - ) -> bool: - """Processes an error by passing it to all error handlers registered with - :meth:`add_error_handler`. If one of the error handlers raises - :class:`telegram.ext.ApplicationHandlerStop`, the error will not be handled by other error - handlers. Raising :class:`telegram.ext.ApplicationHandlerStop` also stops processing of - the update when this method is called by :meth:`process_update`, i.e. no further handlers - (even in other groups) will handle the update. All other exceptions raised by an error - handler will just be logged. - - .. versionchanged:: 20.0 - - * ``dispatch_error`` was renamed to :meth:`process_error`. - * Exceptions raised by error handlers are now properly logged. - * :class:`telegram.ext.ApplicationHandlerStop` is no longer reraised but converted into - the return value. - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update that caused the error. - error (:obj:`Exception`): The error that was raised. - job (:class:`telegram.ext.Job`, optional): The job that caused the error. - - .. versionadded:: 20.0 - coroutine (:term:`coroutine function`, optional): The coroutine that caused the error. - - Returns: - :obj:`bool`: :obj:`True`, if one of the error handlers raised - :class:`telegram.ext.ApplicationHandlerStop`. :obj:`False`, otherwise. - """ - if self.error_handlers: - for ( - callback, - block, - ) in self.error_handlers.items(): - try: - context = self.context_types.context.from_error( - update=update, - error=error, - application=self, - job=job, - coroutine=coroutine, - ) - except Exception as exc: - _LOGGER.critical( - ( - "Error while building CallbackContext for exception %s. " - "Exception will not be processed by error handlers." - ), - error, - exc_info=exc, - ) - return False - - if not block or ( # If error handler has `block=False`, create a Task to run cb - block is DEFAULT_TRUE - and isinstance(self.bot, ExtBot) - and self.bot.defaults - and not self.bot.defaults.block - ): - self.__create_task( - callback(update, context), - update=update, - is_error_handler=True, - name=f"Application:{self.bot.id}:process_error:non_blocking", - ) - else: - try: - await callback(update, context) - except ApplicationHandlerStop: - return True - except Exception as exc: - _LOGGER.exception( - "An error was raised and an uncaught error was raised while " - "handling the error with an error_handler.", - exc_info=exc, - ) - return False - - _LOGGER.exception("No error handlers are registered, logging exception.", exc_info=error) - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_applicationbuilder.py b/venv/lib/python3.11/site-packages/telegram/ext/_applicationbuilder.py deleted file mode 100755 index d0ade04..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_applicationbuilder.py +++ /dev/null @@ -1,1394 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the Builder classes for the telegram.ext module.""" -from asyncio import Queue -from collections.abc import Collection, Coroutine -from pathlib import Path -from typing import TYPE_CHECKING, Any, Callable, Generic, Optional, TypeVar, Union - -import httpx - -from telegram._bot import Bot -from telegram._utils.defaultvalue import DEFAULT_FALSE, DEFAULT_NONE, DefaultValue -from telegram._utils.types import DVInput, DVType, FilePathInput, HTTPVersion, ODVInput, SocketOpt -from telegram._utils.warnings import warn -from telegram.ext._application import Application -from telegram.ext._baseupdateprocessor import BaseUpdateProcessor, SimpleUpdateProcessor -from telegram.ext._contexttypes import ContextTypes -from telegram.ext._extbot import ExtBot -from telegram.ext._jobqueue import JobQueue -from telegram.ext._updater import Updater -from telegram.ext._utils.types import BD, BT, CCT, CD, JQ, UD -from telegram.request import BaseRequest -from telegram.request._httpxrequest import HTTPXRequest -from telegram.warnings import PTBDeprecationWarning - -if TYPE_CHECKING: - from telegram import Update - from telegram.ext import BasePersistence, BaseRateLimiter, CallbackContext, Defaults - from telegram.ext._utils.types import RLARGS - -# Type hinting is a bit complicated here because we try to get to a sane level of -# leveraging generics and therefore need a number of type variables. -# 'In' stands for input - used in parameters of methods below -# pylint: disable=invalid-name -InBT = TypeVar("InBT", bound=Bot) -InJQ = TypeVar("InJQ", bound=Union[None, JobQueue]) -InCCT = TypeVar("InCCT", bound="CallbackContext") -InUD = TypeVar("InUD") -InCD = TypeVar("InCD") -InBD = TypeVar("InBD") -BuilderType = TypeVar("BuilderType", bound="ApplicationBuilder") - - -_BOT_CHECKS = [ - ("request", "request instance"), - ("get_updates_request", "get_updates_request instance"), - ("connection_pool_size", "connection_pool_size"), - ("proxy", "proxy"), - ("socket_options", "socket_options"), - ("pool_timeout", "pool_timeout"), - ("connect_timeout", "connect_timeout"), - ("read_timeout", "read_timeout"), - ("write_timeout", "write_timeout"), - ("media_write_timeout", "media_write_timeout"), - ("http_version", "http_version"), - ("get_updates_connection_pool_size", "get_updates_connection_pool_size"), - ("get_updates_proxy", "get_updates_proxy"), - ("get_updates_socket_options", "get_updates_socket_options"), - ("get_updates_pool_timeout", "get_updates_pool_timeout"), - ("get_updates_connect_timeout", "get_updates_connect_timeout"), - ("get_updates_read_timeout", "get_updates_read_timeout"), - ("get_updates_write_timeout", "get_updates_write_timeout"), - ("get_updates_http_version", "get_updates_http_version"), - ("base_file_url", "base_file_url"), - ("base_url", "base_url"), - ("token", "token"), - ("defaults", "defaults"), - ("arbitrary_callback_data", "arbitrary_callback_data"), - ("private_key", "private_key"), - ("rate_limiter", "rate_limiter instance"), - ("local_mode", "local_mode setting"), -] - -_TWO_ARGS_REQ = "The parameter `{}` may only be set, if no {} was set." - - -class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]): - """This class serves as initializer for :class:`telegram.ext.Application` via the so called - `builder pattern`_. To build a :class:`telegram.ext.Application`, one first initializes an - instance of this class. Arguments for the :class:`telegram.ext.Application` to build are then - added by subsequently calling the methods of the builder. Finally, the - :class:`telegram.ext.Application` is built by calling :meth:`build`. In the simplest case this - can look like the following example. - - Example: - .. code:: python - - application = ApplicationBuilder().token("TOKEN").build() - - Please see the description of the individual methods for information on which arguments can be - set and what the defaults are when not called. When no default is mentioned, the argument will - not be used by default. - - Note: - * Some arguments are mutually exclusive. E.g. after calling :meth:`token`, you can't set - a custom bot with :meth:`bot` and vice versa. - * Unless a custom :class:`telegram.Bot` instance is set via :meth:`bot`, :meth:`build` will - use :class:`telegram.ext.ExtBot` for the bot. - - .. seealso:: :wiki:`Your First Bot `, - :wiki:`Builder Pattern ` - - .. _`builder pattern`: https://en.wikipedia.org/wiki/Builder_pattern - """ - - __slots__ = ( - "_application_class", - "_application_kwargs", - "_arbitrary_callback_data", - "_base_file_url", - "_base_url", - "_bot", - "_connect_timeout", - "_connection_pool_size", - "_context_types", - "_defaults", - "_get_updates_connect_timeout", - "_get_updates_connection_pool_size", - "_get_updates_http_version", - "_get_updates_pool_timeout", - "_get_updates_proxy", - "_get_updates_read_timeout", - "_get_updates_request", - "_get_updates_socket_options", - "_get_updates_write_timeout", - "_http_version", - "_job_queue", - "_local_mode", - "_media_write_timeout", - "_persistence", - "_pool_timeout", - "_post_init", - "_post_shutdown", - "_post_stop", - "_private_key", - "_private_key_password", - "_proxy", - "_rate_limiter", - "_read_timeout", - "_request", - "_socket_options", - "_token", - "_update_processor", - "_update_queue", - "_updater", - "_write_timeout", - ) - - def __init__(self: "InitApplicationBuilder"): - self._token: DVType[str] = DefaultValue("") - self._base_url: DVType[str] = DefaultValue("https://api.telegram.org/bot") - self._base_file_url: DVType[str] = DefaultValue("https://api.telegram.org/file/bot") - self._connection_pool_size: DVInput[int] = DEFAULT_NONE - self._proxy: DVInput[Union[str, httpx.Proxy, httpx.URL]] = DEFAULT_NONE - self._socket_options: DVInput[Collection[SocketOpt]] = DEFAULT_NONE - self._connect_timeout: ODVInput[float] = DEFAULT_NONE - self._read_timeout: ODVInput[float] = DEFAULT_NONE - self._write_timeout: ODVInput[float] = DEFAULT_NONE - self._media_write_timeout: ODVInput[float] = DEFAULT_NONE - self._pool_timeout: ODVInput[float] = DEFAULT_NONE - self._request: DVInput[BaseRequest] = DEFAULT_NONE - self._get_updates_connection_pool_size: DVInput[int] = DEFAULT_NONE - self._get_updates_proxy: DVInput[Union[str, httpx.Proxy, httpx.URL]] = DEFAULT_NONE - self._get_updates_socket_options: DVInput[Collection[SocketOpt]] = DEFAULT_NONE - self._get_updates_connect_timeout: ODVInput[float] = DEFAULT_NONE - self._get_updates_read_timeout: ODVInput[float] = DEFAULT_NONE - self._get_updates_write_timeout: ODVInput[float] = DEFAULT_NONE - self._get_updates_pool_timeout: ODVInput[float] = DEFAULT_NONE - self._get_updates_request: DVInput[BaseRequest] = DEFAULT_NONE - self._get_updates_http_version: DVInput[str] = DefaultValue("1.1") - self._private_key: ODVInput[bytes] = DEFAULT_NONE - self._private_key_password: ODVInput[bytes] = DEFAULT_NONE - self._defaults: ODVInput[Defaults] = DEFAULT_NONE - self._arbitrary_callback_data: Union[DefaultValue[bool], int] = DEFAULT_FALSE - self._local_mode: DVType[bool] = DEFAULT_FALSE - self._bot: DVInput[Bot] = DEFAULT_NONE - self._update_queue: DVType[Queue[Union[Update, object]]] = DefaultValue(Queue()) - - try: - self._job_queue: ODVInput[JobQueue] = DefaultValue(JobQueue()) - except RuntimeError as exc: - if "PTB must be installed via" not in str(exc): - raise - self._job_queue = DEFAULT_NONE - - self._persistence: ODVInput[BasePersistence] = DEFAULT_NONE - self._context_types: DVType[ContextTypes] = DefaultValue(ContextTypes()) - self._application_class: DVType[type[Application]] = DefaultValue(Application) - self._application_kwargs: dict[str, object] = {} - self._update_processor: BaseUpdateProcessor = SimpleUpdateProcessor( - max_concurrent_updates=1 - ) - self._updater: ODVInput[Updater] = DEFAULT_NONE - self._post_init: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None - self._post_shutdown: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None - self._post_stop: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None - self._rate_limiter: ODVInput[BaseRateLimiter] = DEFAULT_NONE - self._http_version: DVInput[str] = DefaultValue("1.1") - - def _build_request(self, get_updates: bool) -> BaseRequest: - prefix = "_get_updates_" if get_updates else "_" - if not isinstance(getattr(self, f"{prefix}request"), DefaultValue): - return getattr(self, f"{prefix}request") - - proxy = DefaultValue.get_value(getattr(self, f"{prefix}proxy")) - socket_options = DefaultValue.get_value(getattr(self, f"{prefix}socket_options")) - if get_updates: - connection_pool_size = ( - DefaultValue.get_value(getattr(self, f"{prefix}connection_pool_size")) or 1 - ) - else: - connection_pool_size = ( - DefaultValue.get_value(getattr(self, f"{prefix}connection_pool_size")) or 256 - ) - - timeouts = { - "connect_timeout": getattr(self, f"{prefix}connect_timeout"), - "read_timeout": getattr(self, f"{prefix}read_timeout"), - "write_timeout": getattr(self, f"{prefix}write_timeout"), - "pool_timeout": getattr(self, f"{prefix}pool_timeout"), - } - - if not get_updates: - timeouts["media_write_timeout"] = self._media_write_timeout - - # Get timeouts that were actually set- - effective_timeouts = { - key: value for key, value in timeouts.items() if not isinstance(value, DefaultValue) - } - - http_version = DefaultValue.get_value(getattr(self, f"{prefix}http_version")) or "1.1" - - return HTTPXRequest( - connection_pool_size=connection_pool_size, - proxy=proxy, - http_version=http_version, # type: ignore[arg-type] - socket_options=socket_options, - **effective_timeouts, - ) - - def _build_ext_bot(self) -> ExtBot: - if isinstance(self._token, DefaultValue): - raise RuntimeError("No bot token was set.") - - return ExtBot( - token=self._token, - base_url=DefaultValue.get_value(self._base_url), - base_file_url=DefaultValue.get_value(self._base_file_url), - private_key=DefaultValue.get_value(self._private_key), - private_key_password=DefaultValue.get_value(self._private_key_password), - defaults=DefaultValue.get_value(self._defaults), - arbitrary_callback_data=DefaultValue.get_value(self._arbitrary_callback_data), - request=self._build_request(get_updates=False), - get_updates_request=self._build_request(get_updates=True), - rate_limiter=DefaultValue.get_value(self._rate_limiter), - local_mode=DefaultValue.get_value(self._local_mode), - ) - - def _bot_check(self, name: str) -> None: - if self._bot is not DEFAULT_NONE: - raise RuntimeError(_TWO_ARGS_REQ.format(name, "bot instance")) - - def _updater_check(self, name: str) -> None: - if self._updater not in (DEFAULT_NONE, None): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "updater")) - - def build( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - ) -> Application[BT, CCT, UD, CD, BD, JQ]: - """Builds a :class:`telegram.ext.Application` with the provided arguments. - - Calls :meth:`telegram.ext.JobQueue.set_application` and - :meth:`telegram.ext.BasePersistence.set_bot` if appropriate. - - Returns: - :class:`telegram.ext.Application` - """ - job_queue = DefaultValue.get_value(self._job_queue) - persistence = DefaultValue.get_value(self._persistence) - # If user didn't set updater - if isinstance(self._updater, DefaultValue) or self._updater is None: - if isinstance(self._bot, DefaultValue): # and didn't set a bot - bot: Bot = self._build_ext_bot() # build a bot - else: - bot = self._bot - # now also build an updater/update_queue for them - update_queue = DefaultValue.get_value(self._update_queue) - - if self._updater is None: - updater = None - else: - updater = Updater(bot=bot, update_queue=update_queue) - else: # if they set an updater, get all necessary attributes for Application from Updater: - updater = self._updater - bot = self._updater.bot - update_queue = self._updater.update_queue - - application: Application[BT, CCT, UD, CD, BD, JQ] = DefaultValue.get_value( - self._application_class - )( - bot=bot, - update_queue=update_queue, - updater=updater, - update_processor=self._update_processor, - job_queue=job_queue, - persistence=persistence, - context_types=DefaultValue.get_value(self._context_types), - post_init=self._post_init, - post_shutdown=self._post_shutdown, - post_stop=self._post_stop, - **self._application_kwargs, # For custom Application subclasses - ) - - if job_queue is not None: - job_queue.set_application(application) # type: ignore[arg-type] - - if persistence is not None: - # This raises an exception if persistence.store_data.callback_data is True - # but self.bot is not an instance of ExtBot - so no need to check that later on - persistence.set_bot(bot) - - return application - - def application_class( - self: BuilderType, - application_class: type[Application[Any, Any, Any, Any, Any, Any]], - kwargs: Optional[dict[str, object]] = None, - ) -> BuilderType: - """Sets a custom subclass instead of :class:`telegram.ext.Application`. The - subclass's ``__init__`` should look like this - - .. code:: python - - def __init__(self, custom_arg_1, custom_arg_2, ..., **kwargs): - super().__init__(**kwargs) - self.custom_arg_1 = custom_arg_1 - self.custom_arg_2 = custom_arg_2 - - Args: - application_class (:obj:`type`): A subclass of :class:`telegram.ext.Application` - kwargs (dict[:obj:`str`, :obj:`object`], optional): Keyword arguments for the - initialization. Defaults to an empty dict. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._application_class = application_class - self._application_kwargs = kwargs or {} - return self - - def token(self: BuilderType, token: str) -> BuilderType: - """Sets the token for :attr:`telegram.ext.Application.bot`. - - Args: - token (:obj:`str`): The token. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("token") - self._updater_check("token") - self._token = token - return self - - def base_url(self: BuilderType, base_url: str) -> BuilderType: - """Sets the base URL for :attr:`telegram.ext.Application.bot`. If not called, - will default to ``'https://api.telegram.org/bot'``. - - .. seealso:: :paramref:`telegram.Bot.base_url`, - :wiki:`Local Bot API Server `, :meth:`base_file_url` - - Args: - base_url (:obj:`str`): The URL. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("base_url") - self._updater_check("base_url") - self._base_url = base_url - return self - - def base_file_url(self: BuilderType, base_file_url: str) -> BuilderType: - """Sets the base file URL for :attr:`telegram.ext.Application.bot`. If not - called, will default to ``'https://api.telegram.org/file/bot'``. - - .. seealso:: :paramref:`telegram.Bot.base_file_url`, - :wiki:`Local Bot API Server `, :meth:`base_url` - - Args: - base_file_url (:obj:`str`): The URL. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("base_file_url") - self._updater_check("base_file_url") - self._base_file_url = base_file_url - return self - - def _request_check(self, get_updates: bool) -> None: - prefix = "get_updates_" if get_updates else "" - name = prefix + "request" - - timeouts = ["connect_timeout", "read_timeout", "write_timeout", "pool_timeout"] - if not get_updates: - timeouts.append("media_write_timeout") - - # Code below tests if it's okay to set a Request object. Only okay if no other request args - # or instances containing a Request were set previously - for attr in timeouts: - if not isinstance(getattr(self, f"_{prefix}{attr}"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, attr)) - - if not isinstance(getattr(self, f"_{prefix}connection_pool_size"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "connection_pool_size")) - - if not isinstance(getattr(self, f"_{prefix}proxy"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "proxy")) - - if not isinstance(getattr(self, f"_{prefix}socket_options"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "socket_options")) - - if not isinstance(getattr(self, f"_{prefix}http_version"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "http_version")) - - self._bot_check(name) - - if self._updater not in (DEFAULT_NONE, None): - raise RuntimeError(_TWO_ARGS_REQ.format(name, "updater instance")) - - def _request_param_check(self, name: str, get_updates: bool) -> None: - if get_updates and self._get_updates_request is not DEFAULT_NONE: - raise RuntimeError( # disallow request args for get_updates if Request for that is set - _TWO_ARGS_REQ.format(f"get_updates_{name}", "get_updates_request instance") - ) - if self._request is not DEFAULT_NONE: # disallow request args if request is set - raise RuntimeError(_TWO_ARGS_REQ.format(name, "request instance")) - - if self._bot is not DEFAULT_NONE: # disallow request args if bot is set (has Request) - raise RuntimeError( - _TWO_ARGS_REQ.format( - f"get_updates_{name}" if get_updates else name, "bot instance" - ) - ) - - if self._updater not in (DEFAULT_NONE, None): # disallow request args for updater(has bot) - raise RuntimeError( - _TWO_ARGS_REQ.format(f"get_updates_{name}" if get_updates else name, "updater") - ) - - def request(self: BuilderType, request: BaseRequest) -> BuilderType: - """Sets a :class:`telegram.request.BaseRequest` instance for the - :paramref:`telegram.Bot.request` parameter of :attr:`telegram.ext.Application.bot`. - - .. seealso:: :meth:`get_updates_request` - - Args: - request (:class:`telegram.request.BaseRequest`): The request instance. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_check(get_updates=False) - self._request = request - return self - - def connection_pool_size(self: BuilderType, connection_pool_size: int) -> BuilderType: - """Sets the size of the connection pool for the - :paramref:`~telegram.request.HTTPXRequest.connection_pool_size` parameter of - :attr:`telegram.Bot.request`. Defaults to ``256``. - - .. include:: inclusions/pool_size_tip.rst - - .. seealso:: :meth:`get_updates_connection_pool_size` - - Args: - connection_pool_size (:obj:`int`): The size of the connection pool. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="connection_pool_size", get_updates=False) - self._connection_pool_size = connection_pool_size - return self - - def proxy_url(self: BuilderType, proxy_url: str) -> BuilderType: - """Legacy name for :meth:`proxy`, kept for backward compatibility. - - .. seealso:: :meth:`get_updates_proxy` - - .. deprecated:: 20.7 - - Args: - proxy_url (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): See - :paramref:`telegram.ext.ApplicationBuilder.proxy.proxy`. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - warn( - PTBDeprecationWarning( - "20.7", - "`ApplicationBuilder.proxy_url` is deprecated. Use `ApplicationBuilder.proxy` " - "instead.", - ), - stacklevel=2, - ) - return self.proxy(proxy_url) - - def proxy(self: BuilderType, proxy: Union[str, httpx.Proxy, httpx.URL]) -> BuilderType: - """Sets the proxy for the :paramref:`~telegram.request.HTTPXRequest.proxy` - parameter of :attr:`telegram.Bot.request`. Defaults to :obj:`None`. - - .. seealso:: :meth:`get_updates_proxy` - - .. versionadded:: 20.7 - - Args: - proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): The URL to a proxy - server, a ``httpx.Proxy`` object or a ``httpx.URL`` object. See - :paramref:`telegram.request.HTTPXRequest.proxy` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="proxy", get_updates=False) - self._proxy = proxy - return self - - def socket_options(self: BuilderType, socket_options: Collection[SocketOpt]) -> BuilderType: - """Sets the options for the :paramref:`~telegram.request.HTTPXRequest.socket_options` - parameter of :attr:`telegram.Bot.request`. Defaults to :obj:`None`. - - .. seealso:: :meth:`get_updates_socket_options` - - .. versionadded:: 20.7 - - Args: - socket_options (Collection[:obj:`tuple`], optional): Socket options. See - :paramref:`telegram.request.HTTPXRequest.socket_options` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="socket_options", get_updates=False) - self._socket_options = socket_options - return self - - def connect_timeout(self: BuilderType, connect_timeout: Optional[float]) -> BuilderType: - """Sets the connection attempt timeout for the - :paramref:`~telegram.request.HTTPXRequest.connect_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``5.0``. - - .. seealso:: :meth:`get_updates_connect_timeout` - - Args: - connect_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.connect_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="connect_timeout", get_updates=False) - self._connect_timeout = connect_timeout - return self - - def read_timeout(self: BuilderType, read_timeout: Optional[float]) -> BuilderType: - """Sets the waiting timeout for the - :paramref:`~telegram.request.HTTPXRequest.read_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``5.0``. - - .. seealso:: :meth:`get_updates_read_timeout` - - Args: - read_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.read_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="read_timeout", get_updates=False) - self._read_timeout = read_timeout - return self - - def write_timeout(self: BuilderType, write_timeout: Optional[float]) -> BuilderType: - """Sets the write operation timeout for the - :paramref:`~telegram.request.HTTPXRequest.write_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``5.0``. - - .. seealso:: :meth:`get_updates_write_timeout` - - Args: - write_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.write_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="write_timeout", get_updates=False) - self._write_timeout = write_timeout - return self - - def media_write_timeout( - self: BuilderType, media_write_timeout: Optional[float] - ) -> BuilderType: - """Sets the media write operation timeout for the - :paramref:`~telegram.request.HTTPXRequest.media_write_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``20``. - - .. versionadded:: 21.0 - - Args: - media_write_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.media_write_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="media_write_timeout", get_updates=False) - self._media_write_timeout = media_write_timeout - return self - - def pool_timeout(self: BuilderType, pool_timeout: Optional[float]) -> BuilderType: - """Sets the connection pool's connection freeing timeout for the - :paramref:`~telegram.request.HTTPXRequest.pool_timeout` parameter of - :attr:`telegram.Bot.request`. Defaults to ``1.0``. - - .. include:: inclusions/pool_size_tip.rst - - .. seealso:: :meth:`get_updates_pool_timeout` - - Args: - pool_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.pool_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="pool_timeout", get_updates=False) - self._pool_timeout = pool_timeout - return self - - def http_version(self: BuilderType, http_version: HTTPVersion) -> BuilderType: - """Sets the HTTP protocol version which is used for the - :paramref:`~telegram.request.HTTPXRequest.http_version` parameter of - :attr:`telegram.Bot.request`. By default, HTTP/1.1 is used. - - .. seealso:: :meth:`get_updates_http_version` - - Note: - Users have observed stability issues with HTTP/2, which happen due to how the `h2 - library handles `_ cancellations of - keepalive connections. See `#3556 `_ for a discussion. - - If you want to use HTTP/2, you must install PTB with the optional requirement - ``http2``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[http2]" - - Keep in mind that the HTTP/1.1 implementation may be considered the `"more - robust option at this time" `_. - - .. versionadded:: 20.1 - .. versionchanged:: 20.2 - Reset the default version to 1.1. - - Args: - http_version (:obj:`str`): Pass ``"2"`` or ``"2.0"`` if you'd like to use HTTP/2 for - making requests to Telegram. Defaults to ``"1.1"``, in which case HTTP/1.1 is used. - - .. versionchanged:: 20.5 - Accept ``"2"`` as a valid value. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="http_version", get_updates=False) - self._http_version = http_version - return self - - def get_updates_request(self: BuilderType, get_updates_request: BaseRequest) -> BuilderType: - """Sets a :class:`telegram.request.BaseRequest` instance for the - :paramref:`~telegram.Bot.get_updates_request` parameter of - :attr:`telegram.ext.Application.bot`. - - .. seealso:: :meth:`request` - - Args: - get_updates_request (:class:`telegram.request.BaseRequest`): The request instance. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_check(get_updates=True) - self._get_updates_request = get_updates_request - return self - - def get_updates_connection_pool_size( - self: BuilderType, get_updates_connection_pool_size: int - ) -> BuilderType: - """Sets the size of the connection pool for the - :paramref:`telegram.request.HTTPXRequest.connection_pool_size` parameter which is used - for the :meth:`telegram.Bot.get_updates` request. Defaults to ``1``. - - .. seealso:: :meth:`connection_pool_size` - - Args: - get_updates_connection_pool_size (:obj:`int`): The size of the connection pool. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="connection_pool_size", get_updates=True) - self._get_updates_connection_pool_size = get_updates_connection_pool_size - return self - - def get_updates_proxy_url(self: BuilderType, get_updates_proxy_url: str) -> BuilderType: - """Legacy name for :meth:`get_updates_proxy`, kept for backward compatibility. - - .. seealso:: :meth:`proxy` - - .. deprecated:: 20.7 - - Args: - get_updates_proxy_url (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): See - :paramref:`telegram.ext.ApplicationBuilder.get_updates_proxy.get_updates_proxy`. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - warn( - PTBDeprecationWarning( - "20.7", - "`ApplicationBuilder.get_updates_proxy_url` is deprecated. Use " - "`ApplicationBuilder.get_updates_proxy` instead.", - ), - stacklevel=2, - ) - return self.get_updates_proxy(get_updates_proxy_url) - - def get_updates_proxy( - self: BuilderType, get_updates_proxy: Union[str, httpx.Proxy, httpx.URL] - ) -> BuilderType: - """Sets the proxy for the :paramref:`telegram.request.HTTPXRequest.proxy` - parameter which is used for :meth:`telegram.Bot.get_updates`. Defaults to :obj:`None`. - - .. seealso:: :meth:`proxy` - - .. versionadded:: 20.7 - - Args: - proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``): The URL to a proxy server, - a ``httpx.Proxy`` object or a ``httpx.URL`` object. See - :paramref:`telegram.request.HTTPXRequest.proxy` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="proxy", get_updates=True) - self._get_updates_proxy = get_updates_proxy - return self - - def get_updates_socket_options( - self: BuilderType, get_updates_socket_options: Collection[SocketOpt] - ) -> BuilderType: - """Sets the options for the :paramref:`~telegram.request.HTTPXRequest.socket_options` - parameter of :paramref:`telegram.Bot.get_updates_request`. Defaults to :obj:`None`. - - .. seealso:: :meth:`socket_options` - - .. versionadded:: 20.7 - - Args: - get_updates_socket_options (Collection[:obj:`tuple`], optional): Socket options. See - :paramref:`telegram.request.HTTPXRequest.socket_options` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="socket_options", get_updates=True) - self._get_updates_socket_options = get_updates_socket_options - return self - - def get_updates_connect_timeout( - self: BuilderType, get_updates_connect_timeout: Optional[float] - ) -> BuilderType: - """Sets the connection attempt timeout for the - :paramref:`telegram.request.HTTPXRequest.connect_timeout` parameter which is used for - the :meth:`telegram.Bot.get_updates` request. Defaults to ``5.0``. - - .. seealso:: :meth:`connect_timeout` - - Args: - get_updates_connect_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.connect_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="connect_timeout", get_updates=True) - self._get_updates_connect_timeout = get_updates_connect_timeout - return self - - def get_updates_read_timeout( - self: BuilderType, get_updates_read_timeout: Optional[float] - ) -> BuilderType: - """Sets the waiting timeout for the - :paramref:`telegram.request.HTTPXRequest.read_timeout` parameter which is used for the - :meth:`telegram.Bot.get_updates` request. Defaults to ``5.0``. - - .. seealso:: :meth:`read_timeout` - - Args: - get_updates_read_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.read_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="read_timeout", get_updates=True) - self._get_updates_read_timeout = get_updates_read_timeout - return self - - def get_updates_write_timeout( - self: BuilderType, get_updates_write_timeout: Optional[float] - ) -> BuilderType: - """Sets the write operation timeout for the - :paramref:`telegram.request.HTTPXRequest.write_timeout` parameter which is used for - the :meth:`telegram.Bot.get_updates` request. Defaults to ``5.0``. - - .. seealso:: :meth:`write_timeout` - - Args: - get_updates_write_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.write_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="write_timeout", get_updates=True) - self._get_updates_write_timeout = get_updates_write_timeout - return self - - def get_updates_pool_timeout( - self: BuilderType, get_updates_pool_timeout: Optional[float] - ) -> BuilderType: - """Sets the connection pool's connection freeing timeout for the - :paramref:`~telegram.request.HTTPXRequest.pool_timeout` parameter which is used for the - :meth:`telegram.Bot.get_updates` request. Defaults to ``1.0``. - - .. seealso:: :meth:`pool_timeout` - - Args: - get_updates_pool_timeout (:obj:`float`): See - :paramref:`telegram.request.HTTPXRequest.pool_timeout` for more information. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="pool_timeout", get_updates=True) - self._get_updates_pool_timeout = get_updates_pool_timeout - return self - - def get_updates_http_version( - self: BuilderType, get_updates_http_version: HTTPVersion - ) -> BuilderType: - """Sets the HTTP protocol version which is used for the - :paramref:`~telegram.request.HTTPXRequest.http_version` parameter which is used in the - :meth:`telegram.Bot.get_updates` request. By default, HTTP/1.1 is used. - - .. seealso:: :meth:`http_version` - - Note: - Users have observed stability issues with HTTP/2, which happen due to how the `h2 - library handles `_ cancellations of - keepalive connections. See `#3556 `_ for a discussion. - - You will also need to install the http2 dependency. Keep in mind that the HTTP/1.1 - implementation may be considered the `"more robust option at this time" - `_. - - .. code-block:: bash - - pip install httpx[http2] - - .. versionadded:: 20.1 - .. versionchanged:: 20.2 - Reset the default version to 1.1. - - Args: - get_updates_http_version (:obj:`str`): Pass ``"2"`` or ``"2.0"`` if you'd like to use - HTTP/2 for making requests to Telegram. Defaults to ``"1.1"``, in which case - HTTP/1.1 is used. - - .. versionchanged:: 20.5 - Accept ``"2"`` as a valid value. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._request_param_check(name="http_version", get_updates=True) - self._get_updates_http_version = get_updates_http_version - return self - - def private_key( - self: BuilderType, - private_key: Union[bytes, FilePathInput], - password: Optional[Union[bytes, FilePathInput]] = None, - ) -> BuilderType: - """Sets the private key and corresponding password for decryption of telegram passport data - for :attr:`telegram.ext.Application.bot`. - - Examples: - :any:`Passport Bot ` - - .. seealso:: :wiki:`Telegram Passports ` - - Args: - private_key (:obj:`bytes` | :obj:`str` | :obj:`pathlib.Path`): The private key or the - file path of a file that contains the key. In the latter case, the file's content - will be read automatically. - password (:obj:`bytes` | :obj:`str` | :obj:`pathlib.Path`, optional): The corresponding - password or the file path of a file that contains the password. In the latter case, - the file's content will be read automatically. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("private_key") - self._updater_check("private_key") - - self._private_key = ( - private_key if isinstance(private_key, bytes) else Path(private_key).read_bytes() - ) - if password is None or isinstance(password, bytes): - self._private_key_password = password - else: - self._private_key_password = Path(password).read_bytes() - - return self - - def defaults(self: BuilderType, defaults: "Defaults") -> BuilderType: - """Sets the :class:`telegram.ext.Defaults` instance for - :attr:`telegram.ext.Application.bot`. - - .. seealso:: :wiki:`Adding Defaults to Your Bot ` - - Args: - defaults (:class:`telegram.ext.Defaults`): The defaults instance. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("defaults") - self._updater_check("defaults") - self._defaults = defaults - return self - - def arbitrary_callback_data( - self: BuilderType, arbitrary_callback_data: Union[bool, int] - ) -> BuilderType: - """Specifies whether :attr:`telegram.ext.Application.bot` should allow arbitrary objects as - callback data for :class:`telegram.InlineKeyboardButton` and how many keyboards should be - cached in memory. If not called, only strings can be used as callback data and no data will - be stored in memory. - - Important: - If you want to use this feature, you must install PTB with the optional requirement - ``callback-data``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[callback-data]" - - Examples: - :any:`Arbitrary callback_data Bot ` - - .. seealso:: :wiki:`Arbitrary callback_data ` - - Args: - arbitrary_callback_data (:obj:`bool` | :obj:`int`): If :obj:`True` is passed, the - default cache size of ``1024`` will be used. Pass an integer to specify a different - cache size. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("arbitrary_callback_data") - self._updater_check("arbitrary_callback_data") - self._arbitrary_callback_data = arbitrary_callback_data - return self - - def local_mode(self: BuilderType, local_mode: bool) -> BuilderType: - """Specifies the value for :paramref:`~telegram.Bot.local_mode` for the - :attr:`telegram.ext.Application.bot`. - If not called, will default to :obj:`False`. - - .. seealso:: :wiki:`Local Bot API Server ` - - Args: - local_mode (:obj:`bool`): Whether the bot should run in local mode. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("local_mode") - self._updater_check("local_mode") - self._local_mode = local_mode - return self - - def bot( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - bot: InBT, - ) -> "ApplicationBuilder[InBT, CCT, UD, CD, BD, JQ]": - """Sets a :class:`telegram.Bot` instance for - :attr:`telegram.ext.Application.bot`. Instances of subclasses like - :class:`telegram.ext.ExtBot` are also valid. - - Args: - bot (:class:`telegram.Bot`): The bot. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._updater_check("bot") - for attr, error in _BOT_CHECKS: - if not isinstance(getattr(self, f"_{attr}"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format("bot", error)) - self._bot = bot - return self # type: ignore[return-value] - - def update_queue(self: BuilderType, update_queue: "Queue[object]") -> BuilderType: - """Sets a :class:`asyncio.Queue` instance for - :attr:`telegram.ext.Application.update_queue`, i.e. the queue that the application will - fetch updates from. Will also be used for the :attr:`telegram.ext.Application.updater`. - If not called, a queue will be instantiated. - - .. seealso:: :attr:`telegram.ext.Updater.update_queue` - - Args: - update_queue (:class:`asyncio.Queue`): The queue. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - if self._updater not in (DEFAULT_NONE, None): - raise RuntimeError(_TWO_ARGS_REQ.format("update_queue", "updater instance")) - self._update_queue = update_queue - return self - - def concurrent_updates( - self: BuilderType, concurrent_updates: Union[bool, int, "BaseUpdateProcessor"] - ) -> BuilderType: - """Specifies if and how many updates may be processed concurrently instead of one by one. - If not called, updates will be processed one by one. - - Warning: - Processing updates concurrently is not recommended when stateful handlers like - :class:`telegram.ext.ConversationHandler` are used. Only use this if you are sure - that your bot does not (explicitly or implicitly) rely on updates being processed - sequentially. - - .. include:: inclusions/pool_size_tip.rst - - .. seealso:: :attr:`telegram.ext.Application.concurrent_updates` - - Args: - concurrent_updates (:obj:`bool` | :obj:`int` | :class:`BaseUpdateProcessor`): Passing - :obj:`True` will allow for ``256`` updates to be processed concurrently using - :class:`telegram.ext.SimpleUpdateProcessor`. Pass an integer to specify a different - number of updates that may be processed concurrently. Pass an instance of - :class:`telegram.ext.BaseUpdateProcessor` to use that instance for handling updates - concurrently. - - .. versionchanged:: 20.4 - Now accepts :class:`BaseUpdateProcessor` instances. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - # Check if concurrent updates is bool and convert to integer - if concurrent_updates is True: - concurrent_updates = 256 - elif concurrent_updates is False: - concurrent_updates = 1 - - # If `concurrent_updates` is an integer, create a `SimpleUpdateProcessor` - # instance with that integer value; otherwise, raise an error if the value - # is negative - if isinstance(concurrent_updates, int): - concurrent_updates = SimpleUpdateProcessor(concurrent_updates) - - # Assign default value of concurrent_updates if it is instance of - # `BaseUpdateProcessor` - self._update_processor: BaseUpdateProcessor = concurrent_updates # type: ignore[no-redef] - return self - - def job_queue( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - job_queue: InJQ, - ) -> "ApplicationBuilder[BT, CCT, UD, CD, BD, InJQ]": - """Sets a :class:`telegram.ext.JobQueue` instance for - :attr:`telegram.ext.Application.job_queue`. If not called, a job queue will be - instantiated if the requirements of :class:`telegram.ext.JobQueue` are installed. - - Examples: - :any:`Timer Bot ` - - .. seealso:: :wiki:`Job Queue ` - - Note: - * :meth:`telegram.ext.JobQueue.set_application` will be called automatically by - :meth:`build`. - * The job queue will be automatically started and stopped by - :meth:`telegram.ext.Application.start` and :meth:`telegram.ext.Application.stop`, - respectively. - * When passing :obj:`None` or when the requirements of :class:`telegram.ext.JobQueue` - are not installed, :attr:`telegram.ext.ConversationHandler.conversation_timeout` - can not be used, as this uses :attr:`telegram.ext.Application.job_queue` internally. - - Args: - job_queue (:class:`telegram.ext.JobQueue`): The job queue. Pass :obj:`None` if you - don't want to use a job queue. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._job_queue = job_queue - return self # type: ignore[return-value] - - def persistence( - self: BuilderType, persistence: "BasePersistence[Any, Any, Any]" - ) -> BuilderType: - """Sets a :class:`telegram.ext.BasePersistence` instance for - :attr:`telegram.ext.Application.persistence`. - - Note: - When using a persistence, note that all - data stored in :attr:`context.user_data `, - :attr:`context.chat_data `, - :attr:`context.bot_data ` and - in :attr:`telegram.ext.ExtBot.callback_data_cache` must be copyable with - :func:`copy.deepcopy`. This is due to the data being deep copied before handing it over - to the persistence in order to avoid race conditions. - - Examples: - :any:`Persistent Conversation Bot ` - - .. seealso:: :wiki:`Making Your Bot Persistent ` - - Warning: - If a :class:`telegram.ext.ContextTypes` instance is set via :meth:`context_types`, - the persistence instance must use the same types! - - Args: - persistence (:class:`telegram.ext.BasePersistence`): The persistence instance. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._persistence = persistence - return self - - def context_types( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - context_types: "ContextTypes[InCCT, InUD, InCD, InBD]", - ) -> "ApplicationBuilder[BT, InCCT, InUD, InCD, InBD, JQ]": - """Sets a :class:`telegram.ext.ContextTypes` instance for - :attr:`telegram.ext.Application.context_types`. - - Examples: - :any:`Context Types Bot ` - - Args: - context_types (:class:`telegram.ext.ContextTypes`): The context types. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._context_types = context_types - return self # type: ignore[return-value] - - def updater(self: BuilderType, updater: Optional[Updater]) -> BuilderType: - """Sets a :class:`telegram.ext.Updater` instance for - :attr:`telegram.ext.Application.updater`. The :attr:`telegram.ext.Updater.bot` and - :attr:`telegram.ext.Updater.update_queue` will be used for - :attr:`telegram.ext.Application.bot` and :attr:`telegram.ext.Application.update_queue`, - respectively. - - Args: - updater (:class:`telegram.ext.Updater` | :obj:`None`): The updater instance or - :obj:`None` if no updater should be used. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - if updater is None: - self._updater = updater - return self - - for attr, error in ( - (self._bot, "bot instance"), - (self._update_queue, "update_queue"), - ): - if not isinstance(attr, DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format("updater", error)) - - for attr_name, error in _BOT_CHECKS: - if not isinstance(getattr(self, f"_{attr_name}"), DefaultValue): - raise RuntimeError(_TWO_ARGS_REQ.format("updater", error)) - - self._updater = updater - return self - - def post_init( - self: BuilderType, post_init: Callable[[Application], Coroutine[Any, Any, None]] - ) -> BuilderType: - """ - Sets a callback to be executed by :meth:`Application.run_polling` and - :meth:`Application.run_webhook` *after* executing :meth:`Application.initialize` but - *before* executing :meth:`Updater.start_polling` or :meth:`Updater.start_webhook`, - respectively. - - Tip: - This can be used for custom startup logic that requires to await coroutines, e.g. - setting up the bots commands via :meth:`~telegram.Bot.set_my_commands`. - - Example: - .. code:: - - async def post_init(application: Application) -> None: - await application.bot.set_my_commands([('start', 'Starts the bot')]) - - application = Application.builder().token("TOKEN").post_init(post_init).build() - - Note: - |post_methods_note| - - .. seealso:: :meth:`post_stop`, :meth:`post_shutdown` - - Args: - post_init (:term:`coroutine function`): The custom callback. Must be a - :term:`coroutine function` and must accept exactly one positional argument, which - is the :class:`~telegram.ext.Application`:: - - async def post_init(application: Application) -> None: - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._post_init = post_init - return self - - def post_shutdown( - self: BuilderType, post_shutdown: Callable[[Application], Coroutine[Any, Any, None]] - ) -> BuilderType: - """ - Sets a callback to be executed by :meth:`Application.run_polling` and - :meth:`Application.run_webhook` *after* executing :meth:`Updater.shutdown` - and :meth:`Application.shutdown`. - - Tip: - This can be used for custom shutdown logic that requires to await coroutines, e.g. - closing a database connection - - Example: - .. code:: - - async def post_shutdown(application: Application) -> None: - await application.bot_data['database'].close() - - application = Application.builder() - .token("TOKEN") - .post_shutdown(post_shutdown) - .build() - - Note: - |post_methods_note| - - .. seealso:: :meth:`post_init`, :meth:`post_stop` - - Args: - post_shutdown (:term:`coroutine function`): The custom callback. Must be a - :term:`coroutine function` and must accept exactly one positional argument, which - is the :class:`~telegram.ext.Application`:: - - async def post_shutdown(application: Application) -> None: - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._post_shutdown = post_shutdown - return self - - def post_stop( - self: BuilderType, post_stop: Callable[[Application], Coroutine[Any, Any, None]] - ) -> BuilderType: - """ - Sets a callback to be executed by :meth:`Application.run_polling` and - :meth:`Application.run_webhook` *after* executing :meth:`Updater.stop` - and :meth:`Application.stop`. - - .. versionadded:: 20.1 - - Tip: - This can be used for custom stop logic that requires to await coroutines, e.g. - sending message to a chat before shutting down the bot. - - Hint: - The callback will be called only, if :meth:`Application.stop` was indeed called - successfully. For example, if the application is stopped early by calling - :meth:`Application.stop_running` within :meth:`post_init`, then the set callback will - *not* be called. - - Example: - .. code:: - - async def post_stop(application: Application) -> None: - await application.bot.send_message(123456, "Shutting down...") - - application = Application.builder() - .token("TOKEN") - .post_stop(post_stop) - .build() - - Note: - |post_methods_note| - - .. seealso:: :meth:`post_init`, :meth:`post_shutdown` - - Args: - post_stop (:term:`coroutine function`): The custom callback. Must be a - :term:`coroutine function` and must accept exactly one positional argument, which - is the :class:`~telegram.ext.Application`:: - - async def post_stop(application: Application) -> None: - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._post_stop = post_stop - return self - - def rate_limiter( - self: "ApplicationBuilder[BT, CCT, UD, CD, BD, JQ]", - rate_limiter: "BaseRateLimiter[RLARGS]", - ) -> "ApplicationBuilder[ExtBot[RLARGS], CCT, UD, CD, BD, JQ]": - """Sets a :class:`telegram.ext.BaseRateLimiter` instance for the - :paramref:`telegram.ext.ExtBot.rate_limiter` parameter of - :attr:`telegram.ext.Application.bot`. - - Args: - rate_limiter (:class:`telegram.ext.BaseRateLimiter`): The rate limiter. - - Returns: - :class:`ApplicationBuilder`: The same builder with the updated argument. - """ - self._bot_check("rate_limiter") - self._updater_check("rate_limiter") - self._rate_limiter = rate_limiter - return self # type: ignore[return-value] - - -InitApplicationBuilder = ( # This is defined all the way down here so that its type is inferred - ApplicationBuilder[ # by Pylance correctly. - ExtBot[None], - ContextTypes.DEFAULT_TYPE, - dict[Any, Any], - dict[Any, Any], - dict[Any, Any], - JobQueue[ContextTypes.DEFAULT_TYPE], - ] -) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_basepersistence.py b/venv/lib/python3.11/site-packages/telegram/ext/_basepersistence.py deleted file mode 100755 index 3571f6d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_basepersistence.py +++ /dev/null @@ -1,440 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the BasePersistence class.""" -from abc import ABC, abstractmethod -from typing import Generic, NamedTuple, NoReturn, Optional - -from telegram._bot import Bot -from telegram.ext._extbot import ExtBot -from telegram.ext._utils.types import BD, CD, UD, CDCData, ConversationDict, ConversationKey - - -class PersistenceInput(NamedTuple): - """Convenience wrapper to group boolean input for the :paramref:`~BasePersistence.store_data` - parameter for :class:`BasePersistence`. - - Args: - bot_data (:obj:`bool`, optional): Whether the setting should be applied for ``bot_data``. - Defaults to :obj:`True`. - chat_data (:obj:`bool`, optional): Whether the setting should be applied for ``chat_data``. - Defaults to :obj:`True`. - user_data (:obj:`bool`, optional): Whether the setting should be applied for ``user_data``. - Defaults to :obj:`True`. - callback_data (:obj:`bool`, optional): Whether the setting should be applied for - ``callback_data``. Defaults to :obj:`True`. - - Attributes: - bot_data (:obj:`bool`): Whether the setting should be applied for ``bot_data``. - chat_data (:obj:`bool`): Whether the setting should be applied for ``chat_data``. - user_data (:obj:`bool`): Whether the setting should be applied for ``user_data``. - callback_data (:obj:`bool`): Whether the setting should be applied for ``callback_data``. - - """ - - bot_data: bool = True - chat_data: bool = True - user_data: bool = True - callback_data: bool = True - - -class BasePersistence(Generic[UD, CD, BD], ABC): - """Interface class for adding persistence to your bot. - Subclass this object for different implementations of a persistent bot. - - Attention: - The interface provided by this class is intended to be accessed exclusively by - :class:`~telegram.ext.Application`. Calling any of the methods below manually might - interfere with the integration of persistence into :class:`~telegram.ext.Application`. - - All relevant methods must be overwritten. This includes: - - * :meth:`get_bot_data` - * :meth:`update_bot_data` - * :meth:`refresh_bot_data` - * :meth:`get_chat_data` - * :meth:`update_chat_data` - * :meth:`refresh_chat_data` - * :meth:`drop_chat_data` - * :meth:`get_user_data` - * :meth:`update_user_data` - * :meth:`refresh_user_data` - * :meth:`drop_user_data` - * :meth:`get_callback_data` - * :meth:`update_callback_data` - * :meth:`get_conversations` - * :meth:`update_conversation` - * :meth:`flush` - - If you don't actually need one of those methods, a simple :keyword:`pass` is enough. - For example, if you don't store ``bot_data``, you don't need :meth:`get_bot_data`, - :meth:`update_bot_data` or :meth:`refresh_bot_data`. - - Note: - You should avoid saving :class:`telegram.Bot` instances. This is because if you change e.g. - the bots token, this won't propagate to the serialized instances and may lead to exceptions. - - To prevent this, the implementation may use :attr:`bot` to replace bot instances with a - placeholder before serialization and insert :attr:`bot` back when loading the data. - Since :attr:`bot` will be set when the process starts, this will be the up-to-date bot - instance. - - If the persistence implementation does not take care of this, you should make sure not to - store any bot instances in the data that will be persisted. E.g. in case of - :class:`telegram.TelegramObject`, one may call :meth:`set_bot` to ensure that shortcuts like - :meth:`telegram.Message.reply_text` are available. - - This class is a :class:`~typing.Generic` class and accepts three type variables: - - 1. The type of the second argument of :meth:`update_user_data`, which must coincide with the - type of the second argument of :meth:`refresh_user_data` and the values in the dictionary - returned by :meth:`get_user_data`. - 2. The type of the second argument of :meth:`update_chat_data`, which must coincide with the - type of the second argument of :meth:`refresh_chat_data` and the values in the dictionary - returned by :meth:`get_chat_data`. - 3. The type of the argument of :meth:`update_bot_data`, which must coincide with the - type of the argument of :meth:`refresh_bot_data` and the return value of - :meth:`get_bot_data`. - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Making Your Bot Persistent ` - - .. versionchanged:: 20.0 - - * The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`. - * ``insert/replace_bot`` was dropped. Serialization of bot instances now needs to be - handled by the specific implementation - see above note. - - Args: - store_data (:class:`~telegram.ext.PersistenceInput`, optional): Specifies which kinds of - data will be saved by this persistence instance. By default, all available kinds of - data will be saved. - update_interval (:obj:`int` | :obj:`float`, optional): The - :class:`~telegram.ext.Application` will update - the persistence in regular intervals. This parameter specifies the time (in seconds) to - wait between two consecutive runs of updating the persistence. Defaults to ``60`` - seconds. - - .. versionadded:: 20.0 - Attributes: - store_data (:class:`~telegram.ext.PersistenceInput`): Specifies which kinds of data will - be saved by this persistence instance. - bot (:class:`telegram.Bot`): The bot associated with the persistence. - """ - - __slots__ = ( - "_update_interval", - "bot", - "store_data", - ) - - def __init__( - self, - store_data: Optional[PersistenceInput] = None, - update_interval: float = 60, - ): - self.store_data: PersistenceInput = store_data or PersistenceInput() - self._update_interval: float = update_interval - - self.bot: Bot = None # type: ignore[assignment] - - @property - def update_interval(self) -> float: - """:obj:`float`: Time (in seconds) that the :class:`~telegram.ext.Application` - will wait between two consecutive runs of updating the persistence. - - .. versionadded:: 20.0 - """ - return self._update_interval - - @update_interval.setter - def update_interval(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to update_interval after initialization." - ) - - def set_bot(self, bot: Bot) -> None: - """Set the Bot to be used by this persistence instance. - - Args: - bot (:class:`telegram.Bot`): The bot. - - Raises: - :exc:`TypeError`: If :attr:`PersistenceInput.callback_data` is :obj:`True` and the - :paramref:`bot` is not an instance of :class:`telegram.ext.ExtBot`. - """ - if self.store_data.callback_data and (not isinstance(bot, ExtBot)): - raise TypeError("callback_data can only be stored when using telegram.ext.ExtBot.") - - self.bot = bot - - @abstractmethod - async def get_user_data(self) -> dict[int, UD]: - """Will be called by :class:`telegram.ext.Application` upon creation with a - persistence object. It should return the ``user_data`` if stored, or an empty - :obj:`dict`. In the latter case, the dictionary should produce values - corresponding to one of the following: - - - :obj:`dict` - - The type from :attr:`telegram.ext.ContextTypes.user_data` - if :class:`telegram.ext.ContextTypes` is used. - - .. versionchanged:: 20.0 - This method may now return a :obj:`dict` instead of a :obj:`collections.defaultdict` - - Returns: - dict[:obj:`int`, :obj:`dict` | :attr:`telegram.ext.ContextTypes.user_data`]: - The restored user data. - """ - - @abstractmethod - async def get_chat_data(self) -> dict[int, CD]: - """Will be called by :class:`telegram.ext.Application` upon creation with a - persistence object. It should return the ``chat_data`` if stored, or an empty - :obj:`dict`. In the latter case, the dictionary should produce values - corresponding to one of the following: - - - :obj:`dict` - - The type from :attr:`telegram.ext.ContextTypes.chat_data` - if :class:`telegram.ext.ContextTypes` is used. - - .. versionchanged:: 20.0 - This method may now return a :obj:`dict` instead of a :obj:`collections.defaultdict` - - Returns: - dict[:obj:`int`, :obj:`dict` | :attr:`telegram.ext.ContextTypes.chat_data`]: - The restored chat data. - """ - - @abstractmethod - async def get_bot_data(self) -> BD: - """Will be called by :class:`telegram.ext.Application` upon creation with a - persistence object. It should return the ``bot_data`` if stored, or an empty - :obj:`dict`. In the latter case, the :obj:`dict` should produce values - corresponding to one of the following: - - - :obj:`dict` - - The type from :attr:`telegram.ext.ContextTypes.bot_data` - if :class:`telegram.ext.ContextTypes` are used. - - Returns: - dict[:obj:`int`, :obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`]: - The restored bot data. - """ - - @abstractmethod - async def get_callback_data(self) -> Optional[CDCData]: - """Will be called by :class:`telegram.ext.Application` upon creation with a - persistence object. If callback data was stored, it should be returned. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Returns: - tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], - dict[:obj:`str`, :obj:`str`]] | :obj:`None`: The restored metadata or :obj:`None`, - if no data was stored. - """ - - @abstractmethod - async def get_conversations(self, name: str) -> ConversationDict: - """Will be called by :class:`telegram.ext.Application` when a - :class:`telegram.ext.ConversationHandler` is added if - :attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`. - It should return the conversations for the handler with :paramref:`name` or an empty - :obj:`dict`. - - Args: - name (:obj:`str`): The handlers name. - - Returns: - :obj:`dict`: The restored conversations for the handler. - """ - - @abstractmethod - async def update_conversation( - self, name: str, key: ConversationKey, new_state: Optional[object] - ) -> None: - """Will be called when a :class:`telegram.ext.ConversationHandler` changes states. - This allows the storage of the new state in the persistence. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:class:`object`): The new state for the given key. - """ - - @abstractmethod - async def update_user_data(self, user_id: int, data: UD) -> None: - """Will be called by the :class:`telegram.ext.Application` after a handler has - handled an update. - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.user_data`): - The :attr:`telegram.ext.Application.user_data` ``[user_id]``. - """ - - @abstractmethod - async def update_chat_data(self, chat_id: int, data: CD) -> None: - """Will be called by the :class:`telegram.ext.Application` after a handler has - handled an update. - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.chat_data`): - The :attr:`telegram.ext.Application.chat_data` ``[chat_id]``. - """ - - @abstractmethod - async def update_bot_data(self, data: BD) -> None: - """Will be called by the :class:`telegram.ext.Application` after a handler has - handled an update. - - Args: - data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`): - The :attr:`telegram.ext.Application.bot_data`. - """ - - @abstractmethod - async def update_callback_data(self, data: CDCData) -> None: - """Will be called by the :class:`telegram.ext.Application` after a handler has - handled an update. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Args: - data (tuple[list[tuple[:obj:`str`, :obj:`float`, \ - dict[:obj:`str`, :obj:`Any`]]], dict[:obj:`str`, :obj:`str`]] | :obj:`None`): - The relevant data to restore :class:`telegram.ext.CallbackDataCache`. - """ - - @abstractmethod - async def drop_chat_data(self, chat_id: int) -> None: - """Will be called by the :class:`telegram.ext.Application`, when using - :meth:`~telegram.ext.Application.drop_chat_data`. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`): The chat id to delete from the persistence. - """ - - @abstractmethod - async def drop_user_data(self, user_id: int) -> None: - """Will be called by the :class:`telegram.ext.Application`, when using - :meth:`~telegram.ext.Application.drop_user_data`. - - .. versionadded:: 20.0 - - Args: - user_id (:obj:`int`): The user id to delete from the persistence. - """ - - @abstractmethod - async def refresh_user_data(self, user_id: int, user_data: UD) -> None: - """Will be called by the :class:`telegram.ext.Application` before passing the - :attr:`~telegram.ext.Application.user_data` to a callback. Can be used to update data - stored in :attr:`~telegram.ext.Application.user_data` from an external source. - - Tip: - This method is expected to edit the object :paramref:`user_data` in-place instead of - returning a new object. - - Warning: - When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method - may be called while a handler callback is still running. This might lead to race - conditions. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Args: - user_id (:obj:`int`): The user ID this :attr:`~telegram.ext.Application.user_data` is - associated with. - user_data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.user_data`): - The ``user_data`` of a single user. - """ - - @abstractmethod - async def refresh_chat_data(self, chat_id: int, chat_data: CD) -> None: - """Will be called by the :class:`telegram.ext.Application` before passing the - :attr:`~telegram.ext.Application.chat_data` to a callback. Can be used to update data - stored in :attr:`~telegram.ext.Application.chat_data` from an external source. - - Tip: - This method is expected to edit the object :paramref:`chat_data` in-place instead of - returning a new object. - - Warning: - When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method - may be called while a handler callback is still running. This might lead to race - conditions. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Args: - chat_id (:obj:`int`): The chat ID this :attr:`~telegram.ext.Application.chat_data` is - associated with. - chat_data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.chat_data`): - The ``chat_data`` of a single chat. - """ - - @abstractmethod - async def refresh_bot_data(self, bot_data: BD) -> None: - """Will be called by the :class:`telegram.ext.Application` before passing the - :attr:`~telegram.ext.Application.bot_data` to a callback. Can be used to update data stored - in :attr:`~telegram.ext.Application.bot_data` from an external source. - - Tip: - This method is expected to edit the object :paramref:`bot_data` in-place instead of - returning a new object. - - Warning: - When using :meth:`~telegram.ext.ApplicationBuilder.concurrent_updates`, this method - may be called while a handler callback is still running. This might lead to race - conditions. - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - - Args: - bot_data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`): - The ``bot_data``. - """ - - @abstractmethod - async def flush(self) -> None: - """Will be called by :meth:`telegram.ext.Application.stop`. Gives the - persistence a chance to finish up saving or close a database connection gracefully. - - .. versionchanged:: 20.0 - Changed this method into an :external:func:`~abc.abstractmethod`. - """ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_baseratelimiter.py b/venv/lib/python3.11/site-packages/telegram/ext/_baseratelimiter.py deleted file mode 100755 index ad11e44..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_baseratelimiter.py +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains a class that allows to rate limit requests to the Bot API.""" -from abc import ABC, abstractmethod -from collections.abc import Coroutine -from typing import Any, Callable, Generic, Optional, Union - -from telegram._utils.types import JSONDict -from telegram.ext._utils.types import RLARGS - - -class BaseRateLimiter(ABC, Generic[RLARGS]): - """ - Abstract interface class that allows to rate limit the requests that python-telegram-bot - sends to the Telegram Bot API. An implementation of this class - must implement all abstract methods and properties. - - This class is a :class:`~typing.Generic` class and accepts one type variable that specifies - the type of the argument :paramref:`~process_request.rate_limit_args` of - :meth:`process_request` and the methods of :class:`~telegram.ext.ExtBot`. - - Hint: - Requests to :meth:`~telegram.Bot.get_updates` are never rate limited. - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Avoiding Flood Limits ` - - .. versionadded:: 20.0 - """ - - __slots__ = () - - @abstractmethod - async def initialize(self) -> None: - """Initialize resources used by this class. Must be implemented by a subclass.""" - - @abstractmethod - async def shutdown(self) -> None: - """Stop & clear resources used by this class. Must be implemented by a subclass.""" - - @abstractmethod - async def process_request( - self, - callback: Callable[..., Coroutine[Any, Any, Union[bool, JSONDict, list[JSONDict]]]], - args: Any, - kwargs: dict[str, Any], - endpoint: str, - data: dict[str, Any], - rate_limit_args: Optional[RLARGS], - ) -> Union[bool, JSONDict, list[JSONDict]]: - """ - Process a request. Must be implemented by a subclass. - - This method must call :paramref:`callback` and return the result of the call. - `When` the callback is called is up to the implementation. - - Important: - This method must only return once the result of :paramref:`callback` is known! - - If a :exc:`~telegram.error.RetryAfter` error is raised, this method may try to make - a new request by calling the callback again. - - Warning: - This method *should not* handle any other exception raised by :paramref:`callback`! - - There are basically two different approaches how a rate limiter can be implemented: - - 1. React only if necessary. In this case, the :paramref:`callback` is called without any - precautions. If a :exc:`~telegram.error.RetryAfter` error is raised, processing requests - is halted for the :attr:`~telegram.error.RetryAfter.retry_after` and finally the - :paramref:`callback` is called again. This approach is often amendable for bots that - don't have a large user base and/or don't send more messages than they get updates. - 2. Throttle all outgoing requests. In this case the implementation makes sure that the - requests are spread out over a longer time interval in order to stay below the rate - limits. This approach is often amendable for bots that have a large user base and/or - send more messages than they get updates. - - An implementation can use the information provided by :paramref:`data`, - :paramref:`endpoint` and :paramref:`rate_limit_args` to handle each request differently. - - Examples: - * It is usually desirable to call :meth:`telegram.Bot.answer_inline_query` - as quickly as possible, while delaying :meth:`telegram.Bot.send_message` - is acceptable. - * There are `different `_ rate limits for group chats and - private chats. - * When sending broadcast messages to a large number of users, these requests can - typically be delayed for a longer time than messages that are direct replies to a - user input. - - Args: - callback (Callable[..., :term:`coroutine`]): The coroutine function that must be called - to make the request. - args (tuple[:obj:`object`]): The positional arguments for the :paramref:`callback` - function. - kwargs (dict[:obj:`str`, :obj:`object`]): The keyword arguments for the - :paramref:`callback` function. - endpoint (:obj:`str`): The endpoint that the request is made for, e.g. - ``"sendMessage"``. - data (dict[:obj:`str`, :obj:`object`]): The parameters that were passed to the method - of :class:`~telegram.ext.ExtBot`. Any ``api_kwargs`` are included in this and - any :paramref:`~telegram.ext.ExtBot.defaults` are already applied. - - Example: - - When calling:: - - await ext_bot.send_message( - chat_id=1, - text="Hello world!", - api_kwargs={"custom": "arg"} - ) - - then :paramref:`data` will be:: - - {"chat_id": 1, "text": "Hello world!", "custom": "arg"} - - rate_limit_args (:obj:`None` | :class:`object`): Custom arguments passed to the methods - of :class:`~telegram.ext.ExtBot`. Can e.g. be used to specify the priority of - the request. - - Returns: - :obj:`bool` | dict[:obj:`str`, :obj:`object`] | :obj:`None`: The result of the - callback function. - """ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_baseupdateprocessor.py b/venv/lib/python3.11/site-packages/telegram/ext/_baseupdateprocessor.py deleted file mode 100755 index 3d6ad37..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_baseupdateprocessor.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the BaseProcessor class.""" -from abc import ABC, abstractmethod -from asyncio import BoundedSemaphore -from contextlib import AbstractAsyncContextManager -from types import TracebackType -from typing import TYPE_CHECKING, Any, Optional, TypeVar, final - -if TYPE_CHECKING: - from collections.abc import Awaitable - -_BUPT = TypeVar("_BUPT", bound="BaseUpdateProcessor") - - -class BaseUpdateProcessor(AbstractAsyncContextManager["BaseUpdateProcessor"], ABC): - """An abstract base class for update processors. You can use this class to implement - your own update processor. - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with processor: - # code - - is roughly equivalent to - - .. code:: python - - try: - await processor.initialize() - # code - finally: - await processor.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - .. seealso:: :wiki:`Concurrency` - - .. versionadded:: 20.4 - - Args: - max_concurrent_updates (:obj:`int`): The maximum number of updates to be processed - concurrently. If this number is exceeded, new updates will be queued until the number - of currently processed updates decreases. - - Raises: - :exc:`ValueError`: If :paramref:`max_concurrent_updates` is a non-positive integer. - """ - - __slots__ = ("_max_concurrent_updates", "_semaphore") - - def __init__(self, max_concurrent_updates: int): - self._max_concurrent_updates = max_concurrent_updates - if self.max_concurrent_updates < 1: - raise ValueError("`max_concurrent_updates` must be a positive integer!") - self._semaphore = BoundedSemaphore(self.max_concurrent_updates) - - async def __aenter__(self: _BUPT) -> _BUPT: # noqa: PYI019 - """|async_context_manager| :meth:`initializes ` the Processor. - - Returns: - The initialized Processor instance. - - Raises: - :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. - """ - try: - await self.initialize() - except Exception: - await self.shutdown() - raise - return self - - async def __aexit__( - self, - exc_type: Optional[type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - """|async_context_manager| :meth:`shuts down ` the Processor.""" - await self.shutdown() - - @property - def max_concurrent_updates(self) -> int: - """:obj:`int`: The maximum number of updates that can be processed concurrently.""" - return self._max_concurrent_updates - - @abstractmethod - async def do_process_update( - self, - update: object, - coroutine: "Awaitable[Any]", - ) -> None: - """Custom implementation of how to process an update. Must be implemented by a subclass. - - Warning: - This method will be called by :meth:`process_update`. It should *not* be called - manually. - - Args: - update (:obj:`object`): The update to be processed. - coroutine (:term:`Awaitable`): The coroutine that will be awaited to process the - update. - """ - - @abstractmethod - async def initialize(self) -> None: - """Initializes the processor so resources can be allocated. Must be implemented by a - subclass. - - .. seealso:: - :meth:`shutdown` - """ - - @abstractmethod - async def shutdown(self) -> None: - """Shutdown the processor so resources can be freed. Must be implemented by a subclass. - - .. seealso:: - :meth:`initialize` - """ - - @final - async def process_update( - self, - update: object, - coroutine: "Awaitable[Any]", - ) -> None: - """Calls :meth:`do_process_update` with a semaphore to limit the number of concurrent - updates. - - Args: - update (:obj:`object`): The update to be processed. - coroutine (:term:`Awaitable`): The coroutine that will be awaited to process the - update. - """ - async with self._semaphore: - await self.do_process_update(update, coroutine) - - -class SimpleUpdateProcessor(BaseUpdateProcessor): - """Instance of :class:`telegram.ext.BaseUpdateProcessor` that immediately awaits the - coroutine, i.e. does not apply any additional processing. This is used by default when - :attr:`telegram.ext.ApplicationBuilder.concurrent_updates` is :obj:`int`. - - .. versionadded:: 20.4 - """ - - __slots__ = () - - async def do_process_update( - self, - update: object, # noqa: ARG002 - coroutine: "Awaitable[Any]", - ) -> None: - """Immediately awaits the coroutine, i.e. does not apply any additional processing. - - Args: - update (:obj:`object`): The update to be processed. - coroutine (:term:`Awaitable`): The coroutine that will be awaited to process the - update. - """ - await coroutine - - async def initialize(self) -> None: - """Does nothing.""" - - async def shutdown(self) -> None: - """Does nothing.""" diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_callbackcontext.py b/venv/lib/python3.11/site-packages/telegram/ext/_callbackcontext.py deleted file mode 100755 index d03250c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_callbackcontext.py +++ /dev/null @@ -1,429 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the CallbackContext class.""" - -from collections.abc import Awaitable, Generator -from re import Match -from typing import TYPE_CHECKING, Any, Generic, NoReturn, Optional, TypeVar, Union - -from telegram._callbackquery import CallbackQuery -from telegram._update import Update -from telegram._utils.warnings import warn -from telegram.ext._extbot import ExtBot -from telegram.ext._utils.types import BD, BT, CD, UD - -if TYPE_CHECKING: - from asyncio import Future, Queue - - from telegram.ext import Application, Job, JobQueue - from telegram.ext._utils.types import CCT - -_STORING_DATA_WIKI = ( - "https://github.com/python-telegram-bot/python-telegram-bot" - "/wiki/Storing-bot%2C-user-and-chat-related-data" -) - -# something like poor mans "typing.Self" for py<3.11 -ST = TypeVar("ST", bound="CallbackContext[Any, Any, Any, Any]") - - -class CallbackContext(Generic[BT, UD, CD, BD]): - """ - This is a context object passed to the callback called by :class:`telegram.ext.BaseHandler` - or by the :class:`telegram.ext.Application` in an error handler added by - :attr:`telegram.ext.Application.add_error_handler` or to the callback of a - :class:`telegram.ext.Job`. - - Note: - :class:`telegram.ext.Application` will create a single context for an entire update. This - means that if you got 2 handlers in different groups and they both get called, they will - receive the same :class:`CallbackContext` object (of course with proper attributes like - :attr:`matches` differing). This allows you to add custom attributes in a lower handler - group callback, and then subsequently access those attributes in a higher handler group - callback. Note that the attributes on :class:`CallbackContext` might change in the future, - so make sure to use a fairly unique name for the attributes. - - Warning: - Do not combine custom attributes with :paramref:`telegram.ext.BaseHandler.block` set to - :obj:`False` or :attr:`telegram.ext.Application.concurrent_updates` set to - :obj:`True`. Due to how those work, it will almost certainly execute the callbacks for an - update out of order, and the attributes that you think you added will not be present. - - This class is a :class:`~typing.Generic` class and accepts four type variables: - - 1. The type of :attr:`bot`. Must be :class:`telegram.Bot` or a subclass of that class. - 2. The type of :attr:`user_data` (if :attr:`user_data` is not :obj:`None`). - 3. The type of :attr:`chat_data` (if :attr:`chat_data` is not :obj:`None`). - 4. The type of :attr:`bot_data` (if :attr:`bot_data` is not :obj:`None`). - - Examples: - * :any:`Context Types Bot ` - * :any:`Custom Webhook Bot ` - - .. seealso:: :attr:`telegram.ext.ContextTypes.DEFAULT_TYPE`, - :wiki:`Job Queue ` - - Args: - application (:class:`telegram.ext.Application`): The application associated with this - context. - chat_id (:obj:`int`, optional): The ID of the chat associated with this object. Used - to provide :attr:`chat_data`. - - .. versionadded:: 20.0 - user_id (:obj:`int`, optional): The ID of the user associated with this object. Used - to provide :attr:`user_data`. - - .. versionadded:: 20.0 - Attributes: - coroutine (:term:`awaitable`): Optional. Only present in error handlers if the - error was caused by an awaitable run with :meth:`Application.create_task` or a handler - callback with :attr:`block=False `. - matches (list[:meth:`re.Match `]): Optional. If the associated update - originated from a :class:`filters.Regex`, this will contain a list of match objects for - every pattern where ``re.search(pattern, string)`` returned a match. Note that filters - short circuit, so combined regex filters will not always be evaluated. - args (list[:obj:`str`]): Optional. Arguments passed to a command if the associated update - is handled by :class:`telegram.ext.CommandHandler`, :class:`telegram.ext.PrefixHandler` - or :class:`telegram.ext.StringCommandHandler`. It contains a list of the words in the - text after the command, using any whitespace string as a delimiter. - error (:exc:`Exception`): Optional. The error that was raised. Only present when passed - to an error handler registered with :attr:`telegram.ext.Application.add_error_handler`. - job (:class:`telegram.ext.Job`): Optional. The job which originated this callback. - Only present when passed to the callback of :class:`telegram.ext.Job` or in error - handlers if the error is caused by a job. - - .. versionchanged:: 20.0 - :attr:`job` is now also present in error handlers if the error is caused by a job. - - """ - - __slots__ = ( - "__dict__", - "_application", - "_chat_id", - "_user_id", - "args", - "coroutine", - "error", - "job", - "matches", - ) - - def __init__( - self: ST, - application: "Application[BT, ST, UD, CD, BD, Any]", - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - ): - self._application: Application[BT, ST, UD, CD, BD, Any] = application - self._chat_id: Optional[int] = chat_id - self._user_id: Optional[int] = user_id - self.args: Optional[list[str]] = None - self.matches: Optional[list[Match[str]]] = None - self.error: Optional[Exception] = None - self.job: Optional[Job[Any]] = None - self.coroutine: Optional[ - Union[Generator[Optional[Future[object]], None, Any], Awaitable[Any]] - ] = None - - @property - def application(self) -> "Application[BT, ST, UD, CD, BD, Any]": - """:class:`telegram.ext.Application`: The application associated with this context.""" - return self._application - - @property - def bot_data(self) -> BD: - """:obj:`ContextTypes.bot_data`: Optional. An object that can be used to keep any data in. - For each update it will be the same :attr:`ContextTypes.bot_data`. Defaults to :obj:`dict`. - - .. seealso:: :wiki:`Storing Bot, User and Chat Related Data\ - ` - """ - return self.application.bot_data - - @bot_data.setter - def bot_data(self, _: object) -> NoReturn: - raise AttributeError( - f"You can not assign a new value to bot_data, see {_STORING_DATA_WIKI}" - ) - - @property - def chat_data(self) -> Optional[CD]: - """:obj:`ContextTypes.chat_data`: Optional. An object that can be used to keep any data in. - For each update from the same chat id it will be the same :obj:`ContextTypes.chat_data`. - Defaults to :obj:`dict`. - - Warning: - When a group chat migrates to a supergroup, its chat id will change and the - ``chat_data`` needs to be transferred. For details see our - :wiki:`wiki page `. - - .. seealso:: :wiki:`Storing Bot, User and Chat Related Data\ - ` - - .. versionchanged:: 20.0 - The chat data is now also present in error handlers if the error is caused by a job. - """ - if self._chat_id is not None: - return self._application.chat_data[self._chat_id] - return None - - @chat_data.setter - def chat_data(self, _: object) -> NoReturn: - raise AttributeError( - f"You can not assign a new value to chat_data, see {_STORING_DATA_WIKI}" - ) - - @property - def user_data(self) -> Optional[UD]: - """:obj:`ContextTypes.user_data`: Optional. An object that can be used to keep any data in. - For each update from the same user it will be the same :obj:`ContextTypes.user_data`. - Defaults to :obj:`dict`. - - .. seealso:: :wiki:`Storing Bot, User and Chat Related Data\ - ` - - .. versionchanged:: 20.0 - The user data is now also present in error handlers if the error is caused by a job. - """ - if self._user_id is not None: - return self._application.user_data[self._user_id] - return None - - @user_data.setter - def user_data(self, _: object) -> NoReturn: - raise AttributeError( - f"You can not assign a new value to user_data, see {_STORING_DATA_WIKI}" - ) - - async def refresh_data(self) -> None: - """If :attr:`application` uses persistence, calls - :meth:`telegram.ext.BasePersistence.refresh_bot_data` on :attr:`bot_data`, - :meth:`telegram.ext.BasePersistence.refresh_chat_data` on :attr:`chat_data` and - :meth:`telegram.ext.BasePersistence.refresh_user_data` on :attr:`user_data`, if - appropriate. - - Will be called by :meth:`telegram.ext.Application.process_update` and - :meth:`telegram.ext.Job.run`. - - .. versionadded:: 13.6 - """ - if self.application.persistence: - if self.application.persistence.store_data.bot_data: - await self.application.persistence.refresh_bot_data(self.bot_data) - if self.application.persistence.store_data.chat_data and self._chat_id is not None: - await self.application.persistence.refresh_chat_data( - chat_id=self._chat_id, - chat_data=self.chat_data, # type: ignore[arg-type] - ) - if self.application.persistence.store_data.user_data and self._user_id is not None: - await self.application.persistence.refresh_user_data( - user_id=self._user_id, - user_data=self.user_data, # type: ignore[arg-type] - ) - - def drop_callback_data(self, callback_query: CallbackQuery) -> None: - """ - Deletes the cached data for the specified callback query. - - .. versionadded:: 13.6 - - Note: - Will *not* raise exceptions in case the data is not found in the cache. - *Will* raise :exc:`KeyError` in case the callback query can not be found in the cache. - - .. seealso:: :wiki:`Arbitrary callback_data ` - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - Raises: - KeyError | RuntimeError: :exc:`KeyError`, if the callback query can not be found in - the cache and :exc:`RuntimeError`, if the bot doesn't allow for arbitrary - callback data. - """ - if isinstance(self.bot, ExtBot): - if self.bot.callback_data_cache is None: - raise RuntimeError( - "This telegram.ext.ExtBot instance does not use arbitrary callback data." - ) - self.bot.callback_data_cache.drop_data(callback_query) - else: - raise RuntimeError( # noqa: TRY004 - "telegram.Bot does not allow for arbitrary callback data." - ) - - @classmethod - def from_error( - cls: type["CCT"], - update: object, - error: Exception, - application: "Application[BT, CCT, UD, CD, BD, Any]", - job: Optional["Job[Any]"] = None, - coroutine: Optional[ - Union[Generator[Optional["Future[object]"], None, Any], Awaitable[Any]] - ] = None, - ) -> "CCT": - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the error - handlers. - - .. seealso:: :meth:`telegram.ext.Application.add_error_handler` - - .. versionchanged:: 20.0 - Removed arguments ``async_args`` and ``async_kwargs``. - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update associated with the - error. May be :obj:`None`, e.g. for errors in job callbacks. - error (:obj:`Exception`): The error. - application (:class:`telegram.ext.Application`): The application associated with this - context. - job (:class:`telegram.ext.Job`, optional): The job associated with the error. - - .. versionadded:: 20.0 - coroutine (:term:`awaitable`, optional): The awaitable associated - with this error if the error was caused by a coroutine run with - :meth:`Application.create_task` or a handler callback with - :attr:`block=False `. - - .. versionadded:: 20.0 - - .. versionchanged:: 20.2 - Accepts :class:`asyncio.Future` and generator-based coroutine functions. - Returns: - :class:`telegram.ext.CallbackContext` - """ - # update and job will never be present at the same time - if update is not None: - self = cls.from_update(update, application) - elif job is not None: - self = cls.from_job(job, application) - else: - self = cls(application) # type: ignore - - self.error = error - self.coroutine = coroutine - return self - - @classmethod - def from_update( - cls: type["CCT"], - update: object, - application: "Application[Any, CCT, Any, Any, Any, Any]", - ) -> "CCT": - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the - handlers. - - .. seealso:: :meth:`telegram.ext.Application.add_handler` - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update. - application (:class:`telegram.ext.Application`): The application associated with this - context. - - Returns: - :class:`telegram.ext.CallbackContext` - """ - if isinstance(update, Update): - chat = update.effective_chat - user = update.effective_user - - chat_id = chat.id if chat else None - user_id = user.id if user else None - - return cls(application, chat_id=chat_id, user_id=user_id) # type: ignore - return cls(application) # type: ignore - - @classmethod - def from_job( - cls: type["CCT"], - job: "Job[CCT]", - application: "Application[Any, CCT, Any, Any, Any, Any]", - ) -> "CCT": - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to a - job callback. - - .. seealso:: :meth:`telegram.ext.JobQueue` - - Args: - job (:class:`telegram.ext.Job`): The job. - application (:class:`telegram.ext.Application`): The application associated with this - context. - - Returns: - :class:`telegram.ext.CallbackContext` - """ - self = cls(application, chat_id=job.chat_id, user_id=job.user_id) # type: ignore - self.job = job - return self - - def update(self, data: dict[str, object]) -> None: - """Updates ``self.__slots__`` with the passed data. - - Args: - data (dict[:obj:`str`, :obj:`object`]): The data. - """ - for key, value in data.items(): - setattr(self, key, value) - - @property - def bot(self) -> BT: - """:class:`telegram.Bot`: The bot associated with this context.""" - return self._application.bot - - @property - def job_queue(self) -> Optional["JobQueue[ST]"]: - """ - :class:`telegram.ext.JobQueue`: The :class:`JobQueue` used by the - :class:`telegram.ext.Application`. - - .. seealso:: :wiki:`Job Queue ` - """ - if self._application._job_queue is None: # pylint: disable=protected-access - warn( - "No `JobQueue` set up. To use `JobQueue`, you must install PTB via " - '`pip install "python-telegram-bot[job-queue]"`.', - stacklevel=2, - ) - return self._application._job_queue # pylint: disable=protected-access - - @property - def update_queue(self) -> "Queue[object]": - """ - :class:`asyncio.Queue`: The :class:`asyncio.Queue` instance used by the - :class:`telegram.ext.Application` and (usually) the :class:`telegram.ext.Updater` - associated with this context. - - """ - return self._application.update_queue - - @property - def match(self) -> Optional[Match[str]]: - """ - :meth:`re.Match `: The first match from :attr:`matches`. - Useful if you are only filtering using a single regex filter. - Returns :obj:`None` if :attr:`matches` is empty. - """ - try: - return self.matches[0] # type: ignore[index] # pylint: disable=unsubscriptable-object - except (IndexError, TypeError): - return None diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_callbackdatacache.py b/venv/lib/python3.11/site-packages/telegram/ext/_callbackdatacache.py deleted file mode 100755 index 1052bd5..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_callbackdatacache.py +++ /dev/null @@ -1,469 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the CallbackDataCache class.""" -import datetime as dtm -import time -from collections.abc import MutableMapping -from typing import TYPE_CHECKING, Any, Optional, Union, cast -from uuid import uuid4 - -try: - from cachetools import LRUCache - - CACHE_TOOLS_AVAILABLE = True -except ImportError: - CACHE_TOOLS_AVAILABLE = False - - -import contextlib - -from telegram import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message, User -from telegram._utils.datetime import to_float_timestamp -from telegram.error import TelegramError -from telegram.ext._utils.types import CDCData - -if TYPE_CHECKING: - from telegram.ext import ExtBot - - -class InvalidCallbackData(TelegramError): - """ - Raised when the received callback data has been tampered with or deleted from cache. - - Examples: - :any:`Arbitrary Callback Data Bot ` - - .. seealso:: :wiki:`Arbitrary callback_data ` - - .. versionadded:: 13.6 - - Args: - callback_data (:obj:`int`, optional): The button data of which the callback data could not - be found. - - Attributes: - callback_data (:obj:`int`): Optional. The button data of which the callback data could not - be found. - """ - - __slots__ = ("callback_data",) - - def __init__(self, callback_data: Optional[str] = None) -> None: - super().__init__( - "The object belonging to this callback_data was deleted or the callback_data was " - "manipulated." - ) - self.callback_data: Optional[str] = callback_data - - def __reduce__(self) -> tuple[type, tuple[Optional[str]]]: # type: ignore[override] - """Defines how to serialize the exception for pickle. See - :py:meth:`object.__reduce__` for more info. - - Returns: - :obj:`tuple` - """ - return self.__class__, (self.callback_data,) - - -class _KeyboardData: - __slots__ = ("access_time", "button_data", "keyboard_uuid") - - def __init__( - self, - keyboard_uuid: str, - access_time: Optional[float] = None, - button_data: Optional[dict[str, object]] = None, - ): - self.keyboard_uuid = keyboard_uuid - self.button_data = button_data or {} - self.access_time = access_time or time.time() - - def update_access_time(self) -> None: - """Updates the access time with the current time.""" - self.access_time = time.time() - - def to_tuple(self) -> tuple[str, float, dict[str, object]]: - """Gives a tuple representation consisting of the keyboard uuid, the access time and the - button data. - """ - return self.keyboard_uuid, self.access_time, self.button_data - - -class CallbackDataCache: - """A custom cache for storing the callback data of a :class:`telegram.ext.ExtBot`. Internally, - it keeps two mappings with fixed maximum size: - - * One for mapping the data received in callback queries to the cached objects - * One for mapping the IDs of received callback queries to the cached objects - - The second mapping allows to manually drop data that has been cached for keyboards of messages - sent via inline mode. - If necessary, will drop the least recently used items. - - Important: - If you want to use this class, you must install PTB with the optional requirement - ``callback-data``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[callback-data]" - - Examples: - :any:`Arbitrary Callback Data Bot ` - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Arbitrary callback_data ` - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - To use this class, PTB must be installed via - ``pip install "python-telegram-bot[callback-data]"``. - - Args: - bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. - maxsize (:obj:`int`, optional): Maximum number of items in each of the internal mappings. - Defaults to ``1024``. - - persistent_data (tuple[list[tuple[:obj:`str`, :obj:`float`, \ - dict[:obj:`str`, :class:`object`]]], dict[:obj:`str`, :obj:`str`]], optional): \ - Data to initialize the cache with, as returned by \ - :meth:`telegram.ext.BasePersistence.get_callback_data`. - - Attributes: - bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. - - """ - - __slots__ = ("_callback_queries", "_keyboard_data", "_maxsize", "bot") - - def __init__( - self, - bot: "ExtBot[Any]", - maxsize: int = 1024, - persistent_data: Optional[CDCData] = None, - ): - if not CACHE_TOOLS_AVAILABLE: - raise RuntimeError( - "To use `CallbackDataCache`, PTB must be installed via `pip install " - '"python-telegram-bot[callback-data]"`.' - ) - - self.bot: ExtBot[Any] = bot - self._maxsize: int = maxsize - self._keyboard_data: MutableMapping[str, _KeyboardData] = LRUCache(maxsize=maxsize) - self._callback_queries: MutableMapping[str, str] = LRUCache(maxsize=maxsize) - - if persistent_data: - self.load_persistence_data(persistent_data) - - def load_persistence_data(self, persistent_data: CDCData) -> None: - """Loads data into the cache. - - Warning: - This method is not intended to be called by users directly. - - .. versionadded:: 20.0 - - Args: - persistent_data (tuple[list[tuple[:obj:`str`, :obj:`float`, \ - dict[:obj:`str`, :class:`object`]]], dict[:obj:`str`, :obj:`str`]], optional): \ - Data to load, as returned by \ - :meth:`telegram.ext.BasePersistence.get_callback_data`. - """ - keyboard_data, callback_queries = persistent_data - for key, value in callback_queries.items(): - self._callback_queries[key] = value - for uuid, access_time, data in keyboard_data: - self._keyboard_data[uuid] = _KeyboardData( - keyboard_uuid=uuid, access_time=access_time, button_data=data - ) - - @property - def maxsize(self) -> int: - """:obj:`int`: The maximum size of the cache. - - .. versionchanged:: 20.0 - This property is now read-only. - """ - return self._maxsize - - @property - def persistence_data(self) -> CDCData: - """tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], - dict[:obj:`str`, :obj:`str`]]: The data that needs to be persisted to allow - caching callback data across bot reboots. - """ - # While building a list/dict from the LRUCaches has linear runtime (in the number of - # entries), the runtime is bounded by maxsize and it has the big upside of not throwing a - # highly customized data structure at users trying to implement a custom persistence class - return [data.to_tuple() for data in self._keyboard_data.values()], dict( - self._callback_queries.items() - ) - - def process_keyboard(self, reply_markup: InlineKeyboardMarkup) -> InlineKeyboardMarkup: - """Registers the reply markup to the cache. If any of the buttons have - :attr:`~telegram.InlineKeyboardButton.callback_data`, stores that data and builds a new - keyboard with the correspondingly replaced buttons. Otherwise, does nothing and returns - the original reply markup. - - Args: - reply_markup (:class:`telegram.InlineKeyboardMarkup`): The keyboard. - - Returns: - :class:`telegram.InlineKeyboardMarkup`: The keyboard to be passed to Telegram. - - """ - keyboard_uuid = uuid4().hex - keyboard_data = _KeyboardData(keyboard_uuid) - - # Built a new nested list of buttons by replacing the callback data if needed - buttons = [ - [ - ( - # We create a new button instead of replacing callback_data in case the - # same object is used elsewhere - InlineKeyboardButton( - btn.text, - callback_data=self.__put_button(btn.callback_data, keyboard_data), - ) - if btn.callback_data - else btn - ) - for btn in column - ] - for column in reply_markup.inline_keyboard - ] - - if not keyboard_data.button_data: - # If we arrive here, no data had to be replaced and we can return the input - return reply_markup - - self._keyboard_data[keyboard_uuid] = keyboard_data - return InlineKeyboardMarkup(buttons) - - @staticmethod - def __put_button(callback_data: object, keyboard_data: _KeyboardData) -> str: - """Stores the data for a single button in :attr:`keyboard_data`. - Returns the string that should be passed instead of the callback_data, which is - ``keyboard_uuid + button_uuids``. - """ - uuid = uuid4().hex - keyboard_data.button_data[uuid] = callback_data - return f"{keyboard_data.keyboard_uuid}{uuid}" - - def __get_keyboard_uuid_and_button_data( - self, callback_data: str - ) -> Union[tuple[str, object], tuple[None, InvalidCallbackData]]: - keyboard, button = self.extract_uuids(callback_data) - try: - # we get the values before calling update() in case KeyErrors are raised - # we don't want to update in that case - keyboard_data = self._keyboard_data[keyboard] - button_data = keyboard_data.button_data[button] - # Update the timestamp for the LRU - keyboard_data.update_access_time() - except KeyError: - return None, InvalidCallbackData(callback_data) - return keyboard, button_data - - @staticmethod - def extract_uuids(callback_data: str) -> tuple[str, str]: - """Extracts the keyboard uuid and the button uuid from the given :paramref:`callback_data`. - - Args: - callback_data (:obj:`str`): The - :paramref:`~telegram.InlineKeyboardButton.callback_data` as present in the button. - - Returns: - (:obj:`str`, :obj:`str`): Tuple of keyboard and button uuid - - """ - # Extract the uuids as put in __put_button - return callback_data[:32], callback_data[32:] - - def process_message(self, message: Message) -> None: - """Replaces the data in the inline keyboard attached to the message with the cached - objects, if necessary. If the data could not be found, - :class:`telegram.ext.InvalidCallbackData` will be inserted. - - Note: - Checks :attr:`telegram.Message.via_bot` and :attr:`telegram.Message.from_user` to check - if the reply markup (if any) was actually sent by this cache's bot. If it was not, the - message will be returned unchanged. - - Note that this will fail for channel posts, as :attr:`telegram.Message.from_user` is - :obj:`None` for those! In the corresponding reply markups the callback data will be - replaced by :class:`telegram.ext.InvalidCallbackData`. - - Warning: - * Does *not* consider :attr:`telegram.Message.reply_to_message` and - :attr:`telegram.Message.pinned_message`. Pass them to this method separately. - * *In place*, i.e. the passed :class:`telegram.Message` will be changed! - - Args: - message (:class:`telegram.Message`): The message. - - """ - self.__process_message(message) - - def __process_message(self, message: Message) -> Optional[str]: - """As documented in process_message, but returns the uuid of the attached keyboard, if any, - which is relevant for process_callback_query. - - **IN PLACE** - """ - if not message.reply_markup: - return None - - if message.via_bot: - sender: Optional[User] = message.via_bot - elif message.from_user: - sender = message.from_user - else: - sender = None - - if sender is not None and sender != self.bot.bot: - return None - - keyboard_uuid = None - - for row in message.reply_markup.inline_keyboard: - for button in row: - if button.callback_data: - button_data = cast(str, button.callback_data) - keyboard_id, callback_data = self.__get_keyboard_uuid_and_button_data( - button_data - ) - # update_callback_data makes sure that the _id_attrs are updated - button.update_callback_data(callback_data) - - # This is lazy loaded. The firsts time we find a button - # we load the associated keyboard - afterwards, there is - if not keyboard_uuid and not isinstance(callback_data, InvalidCallbackData): - keyboard_uuid = keyboard_id - - return keyboard_uuid - - def process_callback_query(self, callback_query: CallbackQuery) -> None: - """Replaces the data in the callback query and the attached messages keyboard with the - cached objects, if necessary. If the data could not be found, - :class:`telegram.ext.InvalidCallbackData` will be inserted. - If :attr:`telegram.CallbackQuery.data` or :attr:`telegram.CallbackQuery.message` is - present, this also saves the callback queries ID in order to be able to resolve it to the - stored data. - - Note: - Also considers inserts data into the buttons of - :attr:`telegram.Message.reply_to_message` and :attr:`telegram.Message.pinned_message` - if necessary. - - Warning: - *In place*, i.e. the passed :class:`telegram.CallbackQuery` will be changed! - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - """ - mapped = False - - if callback_query.data: - data = callback_query.data - - # Get the cached callback data for the CallbackQuery - keyboard_uuid, button_data = self.__get_keyboard_uuid_and_button_data(data) - with callback_query._unfrozen(): - callback_query.data = button_data # type: ignore[assignment] - - # Map the callback queries ID to the keyboards UUID for later use - if not mapped and not isinstance(button_data, InvalidCallbackData): - self._callback_queries[callback_query.id] = keyboard_uuid # type: ignore - mapped = True - - # Get the cached callback data for the inline keyboard attached to the - # CallbackQuery. - if isinstance(callback_query.message, Message): - self.__process_message(callback_query.message) - for maybe_message in ( - callback_query.message.pinned_message, - callback_query.message.reply_to_message, - ): - if isinstance(maybe_message, Message): - self.__process_message(maybe_message) - - def drop_data(self, callback_query: CallbackQuery) -> None: - """Deletes the data for the specified callback query. - - Note: - Will *not* raise exceptions in case the callback data is not found in the cache. - *Will* raise :exc:`KeyError` in case the callback query can not be found in the - cache. - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - Raises: - KeyError: If the callback query can not be found in the cache - """ - try: - keyboard_uuid = self._callback_queries.pop(callback_query.id) - self.__drop_keyboard(keyboard_uuid) - except KeyError as exc: - raise KeyError("CallbackQuery was not found in cache.") from exc - - def __drop_keyboard(self, keyboard_uuid: str) -> None: - with contextlib.suppress(KeyError): - self._keyboard_data.pop(keyboard_uuid) - - def clear_callback_data( - self, time_cutoff: Optional[Union[float, dtm.datetime]] = None - ) -> None: - """Clears the stored callback data. - - Args: - time_cutoff (:obj:`float` | :obj:`datetime.datetime`, optional): Pass a UNIX timestamp - or a :obj:`datetime.datetime` to clear only entries which are older. - |tz-naive-dtms| - - """ - self.__clear(self._keyboard_data, time_cutoff=time_cutoff) - - def clear_callback_queries(self) -> None: - """Clears the stored callback query IDs.""" - self.__clear(self._callback_queries) - - def __clear( - self, mapping: MutableMapping, time_cutoff: Optional[Union[float, dtm.datetime]] = None - ) -> None: - if not time_cutoff: - mapping.clear() - return - - if isinstance(time_cutoff, dtm.datetime): - effective_cutoff = to_float_timestamp( - time_cutoff, tzinfo=self.bot.defaults.tzinfo if self.bot.defaults else None - ) - else: - effective_cutoff = time_cutoff - - # We need a list instead of a generator here, as the list doesn't change it's size - # during the iteration - to_drop = [key for key, data in mapping.items() if data.access_time < effective_cutoff] - for key in to_drop: - mapping.pop(key) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_contexttypes.py b/venv/lib/python3.11/site-packages/telegram/ext/_contexttypes.py deleted file mode 100755 index 2d3a8b3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_contexttypes.py +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the auxiliary class ContextTypes.""" -from typing import Any, Generic, overload - -from telegram.ext._callbackcontext import CallbackContext -from telegram.ext._extbot import ExtBot -from telegram.ext._utils.types import BD, CCT, CD, UD - -ADict = dict[Any, Any] - - -class ContextTypes(Generic[CCT, UD, CD, BD]): - """ - Convenience class to gather customizable types of the :class:`telegram.ext.CallbackContext` - interface. - - Examples: - :any:`ContextTypes Bot ` - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Storing Bot, User and Chat Related Data ` - - .. versionadded:: 13.6 - - Args: - context (:obj:`type`, optional): Determines the type of the ``context`` argument of all - (error-)handler callbacks and job callbacks. Must be a subclass of - :class:`telegram.ext.CallbackContext`. Defaults to - :class:`telegram.ext.CallbackContext`. - bot_data (:obj:`type`, optional): Determines the type of - :attr:`context.bot_data ` of all (error-)handler callbacks - and job callbacks. Defaults to :obj:`dict`. Must support instantiating without - arguments. - chat_data (:obj:`type`, optional): Determines the type of - :attr:`context.chat_data ` of all (error-)handler callbacks - and job callbacks. Defaults to :obj:`dict`. Must support instantiating without - arguments. - user_data (:obj:`type`, optional): Determines the type of - :attr:`context.user_data ` of all (error-)handler callbacks - and job callbacks. Defaults to :obj:`dict`. Must support instantiating without - arguments. - - """ - - DEFAULT_TYPE = CallbackContext[ExtBot[None], ADict, ADict, ADict] - """Shortcut for the type annotation for the ``context`` argument that's correct for the - default settings, i.e. if :class:`telegram.ext.ContextTypes` is not used. - - Example: - .. code:: python - - async def callback(update: Update, context: ContextTypes.DEFAULT_TYPE): - ... - - .. versionadded: 20.0 - """ - - __slots__ = ("_bot_data", "_chat_data", "_context", "_user_data") - - # overload signatures generated with - # https://gist.github.com/Bibo-Joshi/399382cda537fb01bd86b13c3d03a956 - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], ADict, ADict, ADict], ADict, ADict, ADict]", # pylint: disable=line-too-long # noqa: E501 - ): ... - - @overload - def __init__(self: "ContextTypes[CCT, ADict, ADict, ADict]", context: type[CCT]): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], UD, ADict, ADict], UD, ADict, ADict]", - user_data: type[UD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], ADict, CD, ADict], ADict, CD, ADict]", - chat_data: type[CD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], ADict, ADict, BD], ADict, ADict, BD]", - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, UD, ADict, ADict]", context: type[CCT], user_data: type[UD] - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, ADict, CD, ADict]", context: type[CCT], chat_data: type[CD] - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, ADict, ADict, BD]", context: type[CCT], bot_data: type[BD] - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], UD, CD, ADict], UD, CD, ADict]", - user_data: type[UD], - chat_data: type[CD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], UD, ADict, BD], UD, ADict, BD]", - user_data: type[UD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], ADict, CD, BD], ADict, CD, BD]", - chat_data: type[CD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, UD, CD, ADict]", - context: type[CCT], - user_data: type[UD], - chat_data: type[CD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, UD, ADict, BD]", - context: type[CCT], - user_data: type[UD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, ADict, CD, BD]", - context: type[CCT], - chat_data: type[CD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CallbackContext[ExtBot[Any], UD, CD, BD], UD, CD, BD]", - user_data: type[UD], - chat_data: type[CD], - bot_data: type[BD], - ): ... - - @overload - def __init__( - self: "ContextTypes[CCT, UD, CD, BD]", - context: type[CCT], - user_data: type[UD], - chat_data: type[CD], - bot_data: type[BD], - ): ... - - def __init__( # type: ignore[misc] - self, - context: "type[CallbackContext[ExtBot[Any], ADict, ADict, ADict]]" = CallbackContext, - bot_data: type[ADict] = dict, - chat_data: type[ADict] = dict, - user_data: type[ADict] = dict, - ): - if not issubclass(context, CallbackContext): - raise TypeError("context must be a subclass of CallbackContext.") - - # We make all those only accessible via properties because we don't currently support - # changing this at runtime, so overriding the attributes doesn't make sense - self._context = context - self._bot_data = bot_data - self._chat_data = chat_data - self._user_data = user_data - - @property - def context(self) -> type[CCT]: - """The type of the ``context`` argument of all (error-)handler callbacks and job - callbacks. - """ - return self._context # type: ignore[return-value] - - @property - def bot_data(self) -> type[BD]: - """The type of :attr:`context.bot_data ` of all (error-)handler - callbacks and job callbacks. - """ - return self._bot_data # type: ignore[return-value] - - @property - def chat_data(self) -> type[CD]: - """The type of :attr:`context.chat_data ` of all (error-)handler - callbacks and job callbacks. - """ - return self._chat_data # type: ignore[return-value] - - @property - def user_data(self) -> type[UD]: - """The type of :attr:`context.user_data ` of all (error-)handler - callbacks and job callbacks. - """ - return self._user_data # type: ignore[return-value] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_defaults.py b/venv/lib/python3.11/site-packages/telegram/ext/_defaults.py deleted file mode 100755 index 86fb59a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_defaults.py +++ /dev/null @@ -1,429 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the class Defaults, which allows passing default values to Application.""" -import datetime as dtm -from typing import Any, NoReturn, Optional, final - -from telegram import LinkPreviewOptions -from telegram._utils.datetime import UTC -from telegram._utils.types import ODVInput -from telegram._utils.warnings import warn -from telegram.warnings import PTBDeprecationWarning - - -@final -class Defaults: - """Convenience Class to gather all parameters with a (user defined) default value - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Adding Defaults to Your Bot ` - - .. versionchanged:: 20.0 - Removed the argument and attribute ``timeout``. Specify default timeout behavior for the - networking backend directly via :class:`telegram.ext.ApplicationBuilder` instead. - - Parameters: - parse_mode (:obj:`str`, optional): |parse_mode| - disable_notification (:obj:`bool`, optional): |disable_notification| - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this - message. Mutually exclusive with :paramref:`link_preview_options`. - - .. deprecated:: 20.8 - Use :paramref:`link_preview_options` instead. This parameter will be removed in - future versions. - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|. - Will be used for :attr:`telegram.ReplyParameters.allow_sending_without_reply`. - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - Use :paramref:`do_quote` instead. This parameter will be removed in future - versions. - tzinfo (:class:`datetime.tzinfo`, optional): A timezone to be used for all date(time) - inputs appearing throughout PTB, i.e. if a timezone naive date(time) object is passed - somewhere, it will be assumed to be in :paramref:`tzinfo`. Defaults to - :attr:`datetime.timezone.utc` otherwise. - - .. deprecated:: 21.10 - Support for ``pytz`` timezones is deprecated and will be removed in future - versions. - - block (:obj:`bool`, optional): Default setting for the :paramref:`BaseHandler.block` - parameter - of handlers and error handlers registered through :meth:`Application.add_handler` and - :meth:`Application.add_error_handler`. Defaults to :obj:`True`. - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 20.0 - link_preview_options (:class:`telegram.LinkPreviewOptions`, optional): - Link preview generation options for all outgoing messages. Mutually exclusive with - :paramref:`disable_web_page_preview`. - This object is used for the corresponding parameter of - :meth:`telegram.Bot.send_message`, :meth:`telegram.Bot.edit_message_text`, - and :class:`telegram.InputTextMessageContent` if not specified. If a value is specified - for the corresponding parameter, only those parameters of - :class:`telegram.LinkPreviewOptions` will be overridden that are not - explicitly set. - - Example: - - .. code-block:: python - - from telegram import LinkPreviewOptions - from telegram.ext import Defaults, ExtBot - - defaults = Defaults( - link_preview_options=LinkPreviewOptions(show_above_text=True) - ) - chat_id = 123 - - async def main(): - async with ExtBot("Token", defaults=defaults) as bot: - # The link preview will be shown above the text. - await bot.send_message(chat_id, "https://python-telegram-bot.org") - - # The link preview will be shown below the text. - await bot.send_message( - chat_id, - "https://python-telegram-bot.org", - link_preview_options=LinkPreviewOptions(show_above_text=False) - ) - - # The link preview will be shown above the text, but the preview will - # show Telegram. - await bot.send_message( - chat_id, - "https://python-telegram-bot.org", - link_preview_options=LinkPreviewOptions(url="https://telegram.org") - ) - - .. versionadded:: 20.8 - do_quote(:obj:`bool`, optional): |reply_quote| - - .. versionadded:: 20.8 - """ - - __slots__ = ( - "_allow_sending_without_reply", - "_api_defaults", - "_block", - "_disable_notification", - "_do_quote", - "_link_preview_options", - "_parse_mode", - "_protect_content", - "_tzinfo", - ) - - def __init__( - self, - parse_mode: Optional[str] = None, - disable_notification: Optional[bool] = None, - disable_web_page_preview: Optional[bool] = None, - quote: Optional[bool] = None, - tzinfo: dtm.tzinfo = UTC, - block: bool = True, - allow_sending_without_reply: Optional[bool] = None, - protect_content: Optional[bool] = None, - link_preview_options: Optional["LinkPreviewOptions"] = None, - do_quote: Optional[bool] = None, - ): - self._parse_mode: Optional[str] = parse_mode - self._disable_notification: Optional[bool] = disable_notification - self._allow_sending_without_reply: Optional[bool] = allow_sending_without_reply - self._tzinfo: dtm.tzinfo = tzinfo - self._block: bool = block - self._protect_content: Optional[bool] = protect_content - - if "pytz" in str(self._tzinfo.__class__): - # TODO: When dropping support, make sure to update _utils.datetime accordingly - warn( - message=PTBDeprecationWarning( - version="21.10", - message=( - "Support for pytz timezones is deprecated and will be removed in " - "future versions." - ), - ), - stacklevel=2, - ) - - if disable_web_page_preview is not None and link_preview_options is not None: - raise ValueError( - "`disable_web_page_preview` and `link_preview_options` are mutually exclusive." - ) - if quote is not None and do_quote is not None: - raise ValueError("`quote` and `do_quote` are mutually exclusive") - if disable_web_page_preview is not None: - warn( - PTBDeprecationWarning( - "20.8", - "`Defaults.disable_web_page_preview` is deprecated. Use " - "`Defaults.link_preview_options` instead.", - ), - stacklevel=2, - ) - self._link_preview_options: Optional[LinkPreviewOptions] = LinkPreviewOptions( - is_disabled=disable_web_page_preview - ) - else: - self._link_preview_options = link_preview_options - - if quote is not None: - warn( - PTBDeprecationWarning( - "20.8", "`Defaults.quote` is deprecated. Use `Defaults.do_quote` instead." - ), - stacklevel=2, - ) - self._do_quote: Optional[bool] = quote - else: - self._do_quote = do_quote - # Gather all defaults that actually have a default value - self._api_defaults = {} - for kwarg in ( - "allow_sending_without_reply", - "disable_notification", - "do_quote", - "explanation_parse_mode", - "link_preview_options", - "parse_mode", - "text_parse_mode", - "protect_content", - "question_parse_mode", - ): - value = getattr(self, kwarg) - if value is not None: - self._api_defaults[kwarg] = value - - def __hash__(self) -> int: - """Builds a hash value for this object such that the hash of two objects is equal if and - only if the objects are equal in terms of :meth:`__eq__`. - - Returns: - :obj:`int` The hash value of the object. - """ - return hash( - ( - self._parse_mode, - self._disable_notification, - self.disable_web_page_preview, - self._allow_sending_without_reply, - self.quote, - self._tzinfo, - self._block, - self._protect_content, - ) - ) - - def __eq__(self, other: object) -> bool: - """Defines equality condition for the :class:`Defaults` object. - Two objects of this class are considered to be equal if all their parameters - are identical. - - Returns: - :obj:`True` if both objects have all parameters identical. :obj:`False` otherwise. - """ - if isinstance(other, Defaults): - return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__) - return False - - @property - def api_defaults(self) -> dict[str, Any]: # skip-cq: PY-D0003 - return self._api_defaults - - @property - def parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or URLs in your bot's message. - """ - return self._parse_mode - - @parse_mode.setter - def parse_mode(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to parse_mode after initialization.") - - @property - def explanation_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :meth:`telegram.Bot.send_poll`. - """ - return self._parse_mode - - @explanation_parse_mode.setter - def explanation_parse_mode(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to explanation_parse_mode after initialization." - ) - - @property - def quote_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :meth:`telegram.ReplyParameters`. - """ - return self._parse_mode - - @quote_parse_mode.setter - def quote_parse_mode(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to quote_parse_mode after initialization." - ) - - @property - def text_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :class:`telegram.InputPollOption` and - :meth:`telegram.Bot.send_gift`. - - .. versionadded:: 21.2 - """ - return self._parse_mode - - @text_parse_mode.setter - def text_parse_mode(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to text_parse_mode after initialization." - ) - - @property - def question_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :meth:`telegram.Bot.send_poll`. - - .. versionadded:: 21.2 - """ - return self._parse_mode - - @question_parse_mode.setter - def question_parse_mode(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to question_parse_mode after initialization." - ) - - @property - def disable_notification(self) -> Optional[bool]: - """:obj:`bool`: Optional. Sends the message silently. Users will - receive a notification with no sound. - """ - return self._disable_notification - - @disable_notification.setter - def disable_notification(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to disable_notification after initialization." - ) - - @property - def disable_web_page_preview(self) -> ODVInput[bool]: - """:obj:`bool`: Optional. Disables link previews for links in all outgoing - messages. - - .. deprecated:: 20.8 - Use :attr:`link_preview_options` instead. This attribute will be removed in future - versions. - """ - return self._link_preview_options.is_disabled if self._link_preview_options else None - - @disable_web_page_preview.setter - def disable_web_page_preview(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to disable_web_page_preview after initialization." - ) - - @property - def allow_sending_without_reply(self) -> Optional[bool]: - """:obj:`bool`: Optional. Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - """ - return self._allow_sending_without_reply - - @allow_sending_without_reply.setter - def allow_sending_without_reply(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to allow_sending_without_reply after initialization." - ) - - @property - def quote(self) -> Optional[bool]: - """:obj:`bool`: Optional. |reply_quote| - - .. deprecated:: 20.8 - Use :attr:`do_quote` instead. This attribute will be removed in future - versions. - """ - return self._do_quote if self._do_quote is not None else None - - @quote.setter - def quote(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to quote after initialization.") - - @property - def tzinfo(self) -> dtm.tzinfo: - """:obj:`tzinfo`: A timezone to be used for all date(time) objects appearing - throughout PTB. - """ - return self._tzinfo - - @tzinfo.setter - def tzinfo(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to tzinfo after initialization.") - - @property - def block(self) -> bool: - """:obj:`bool`: Optional. Default setting for the :paramref:`BaseHandler.block` parameter - of handlers and error handlers registered through :meth:`Application.add_handler` and - :meth:`Application.add_error_handler`. - """ - return self._block - - @block.setter - def block(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to block after initialization.") - - @property - def protect_content(self) -> Optional[bool]: - """:obj:`bool`: Optional. Protects the contents of the sent message from forwarding and - saving. - - .. versionadded:: 20.0 - """ - return self._protect_content - - @protect_content.setter - def protect_content(self, _: object) -> NoReturn: - raise AttributeError( - "You can't assign a new value to protect_content after initialization." - ) - - @property - def link_preview_options(self) -> Optional["LinkPreviewOptions"]: - """:class:`telegram.LinkPreviewOptions`: Optional. Link preview generation options for all - outgoing messages. - - .. versionadded:: 20.8 - """ - return self._link_preview_options - - @property - def do_quote(self) -> Optional[bool]: - """:obj:`bool`: Optional. |reply_quote| - - .. versionadded:: 20.8 - """ - return self._do_quote diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_dictpersistence.py b/venv/lib/python3.11/site-packages/telegram/ext/_dictpersistence.py deleted file mode 100755 index da9749d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_dictpersistence.py +++ /dev/null @@ -1,481 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the DictPersistence class.""" -import json -from copy import deepcopy -from typing import TYPE_CHECKING, Any, Optional, cast - -from telegram.ext import BasePersistence, PersistenceInput -from telegram.ext._utils.types import CDCData, ConversationDict, ConversationKey - -if TYPE_CHECKING: - from telegram._utils.types import JSONDict - - -class DictPersistence(BasePersistence[dict[Any, Any], dict[Any, Any], dict[Any, Any]]): - """Using Python's :obj:`dict` and :mod:`json` for making your bot persistent. - - Attention: - The interface provided by this class is intended to be accessed exclusively by - :class:`~telegram.ext.Application`. Calling any of the methods below manually might - interfere with the integration of persistence into :class:`~telegram.ext.Application`. - - Note: - * Data managed by :class:`DictPersistence` is in-memory only and will be lost when the bot - shuts down. This is, because :class:`DictPersistence` is mainly intended as starting - point for custom persistence classes that need to JSON-serialize the stored data before - writing them to file/database. - - * This implementation of :class:`BasePersistence` does not handle data that cannot be - serialized by :func:`json.dumps`. - - .. seealso:: :wiki:`Making Your Bot Persistent ` - - .. versionchanged:: 20.0 - The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`. - - Args: - store_data (:class:`~telegram.ext.PersistenceInput`, optional): Specifies which kinds of - data will be saved by this persistence instance. By default, all available kinds of - data will be saved. - user_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - user_data on creating this persistence. Default is ``""``. - chat_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - chat_data on creating this persistence. Default is ``""``. - bot_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - bot_data on creating this persistence. Default is ``""``. - conversations_json (:obj:`str`, optional): JSON string that will be used to reconstruct - conversation on creating this persistence. Default is ``""``. - callback_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - callback_data on creating this persistence. Default is ``""``. - - .. versionadded:: 13.6 - update_interval (:obj:`int` | :obj:`float`, optional): The - :class:`~telegram.ext.Application` will update - the persistence in regular intervals. This parameter specifies the time (in seconds) to - wait between two consecutive runs of updating the persistence. Defaults to 60 seconds. - - .. versionadded:: 20.0 - Attributes: - store_data (:class:`~telegram.ext.PersistenceInput`): Specifies which kinds of data will - be saved by this persistence instance. - """ - - __slots__ = ( - "_bot_data", - "_bot_data_json", - "_callback_data", - "_callback_data_json", - "_chat_data", - "_chat_data_json", - "_conversations", - "_conversations_json", - "_user_data", - "_user_data_json", - ) - - def __init__( - self, - store_data: Optional[PersistenceInput] = None, - user_data_json: str = "", - chat_data_json: str = "", - bot_data_json: str = "", - conversations_json: str = "", - callback_data_json: str = "", - update_interval: float = 60, - ): - super().__init__(store_data=store_data, update_interval=update_interval) - self._user_data = None - self._chat_data = None - self._bot_data = None - self._callback_data = None - self._conversations = None - self._user_data_json: Optional[str] = None - self._chat_data_json: Optional[str] = None - self._bot_data_json: Optional[str] = None - self._callback_data_json: Optional[str] = None - self._conversations_json: Optional[str] = None - if user_data_json: - try: - self._user_data = self._decode_user_chat_data_from_json(user_data_json) - self._user_data_json = user_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize user_data_json. Not valid JSON") from exc - if chat_data_json: - try: - self._chat_data = self._decode_user_chat_data_from_json(chat_data_json) - self._chat_data_json = chat_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize chat_data_json. Not valid JSON") from exc - if bot_data_json: - try: - self._bot_data = json.loads(bot_data_json) - self._bot_data_json = bot_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize bot_data_json. Not valid JSON") from exc - if not isinstance(self._bot_data, dict): - raise TypeError("bot_data_json must be serialized dict") - if callback_data_json: - try: - data = json.loads(callback_data_json) - except (ValueError, AttributeError) as exc: - raise TypeError( - "Unable to deserialize callback_data_json. Not valid JSON" - ) from exc - # We are a bit more thorough with the checking of the format here, because it's - # more complicated than for the other things - try: - if data is None: - self._callback_data = None - else: - self._callback_data = cast( - CDCData, - ([(one, float(two), three) for one, two, three in data[0]], data[1]), - ) - self._callback_data_json = callback_data_json - except (ValueError, IndexError) as exc: - raise TypeError("callback_data_json is not in the required format") from exc - if self._callback_data is not None and ( - not all( - isinstance(entry[2], dict) and isinstance(entry[0], str) - for entry in self._callback_data[0] - ) - or not isinstance(self._callback_data[1], dict) - ): - raise TypeError("callback_data_json is not in the required format") - - if conversations_json: - try: - self._conversations = self._decode_conversations_from_json(conversations_json) - self._conversations_json = conversations_json - except (ValueError, AttributeError) as exc: - raise TypeError( - "Unable to deserialize conversations_json. Not valid JSON" - ) from exc - - @property - def user_data(self) -> Optional[dict[int, dict[Any, Any]]]: - """:obj:`dict`: The user_data as a dict.""" - return self._user_data - - @property - def user_data_json(self) -> str: - """:obj:`str`: The user_data serialized as a JSON-string.""" - if self._user_data_json: - return self._user_data_json - return json.dumps(self.user_data) - - @property - def chat_data(self) -> Optional[dict[int, dict[Any, Any]]]: - """:obj:`dict`: The chat_data as a dict.""" - return self._chat_data - - @property - def chat_data_json(self) -> str: - """:obj:`str`: The chat_data serialized as a JSON-string.""" - if self._chat_data_json: - return self._chat_data_json - return json.dumps(self.chat_data) - - @property - def bot_data(self) -> Optional[dict[Any, Any]]: - """:obj:`dict`: The bot_data as a dict.""" - return self._bot_data - - @property - def bot_data_json(self) -> str: - """:obj:`str`: The bot_data serialized as a JSON-string.""" - if self._bot_data_json: - return self._bot_data_json - return json.dumps(self.bot_data) - - @property - def callback_data(self) -> Optional[CDCData]: - """tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], \ - dict[:obj:`str`, :obj:`str`]]: The metadata on the stored callback data. - - .. versionadded:: 13.6 - """ - return self._callback_data - - @property - def callback_data_json(self) -> str: - """:obj:`str`: The metadata on the stored callback data as a JSON-string. - - .. versionadded:: 13.6 - """ - if self._callback_data_json: - return self._callback_data_json - return json.dumps(self.callback_data) - - @property - def conversations(self) -> Optional[dict[str, ConversationDict]]: - """:obj:`dict`: The conversations as a dict.""" - return self._conversations - - @property - def conversations_json(self) -> str: - """:obj:`str`: The conversations serialized as a JSON-string.""" - if self._conversations_json: - return self._conversations_json - if self.conversations: - return self._encode_conversations_to_json(self.conversations) - return json.dumps(self.conversations) - - async def get_user_data(self) -> dict[int, dict[object, object]]: - """Returns the user_data created from the ``user_data_json`` or an empty :obj:`dict`. - - Returns: - :obj:`dict`: The restored user data. - """ - if self.user_data is None: - self._user_data = {} - return deepcopy(self.user_data) # type: ignore[arg-type] - - async def get_chat_data(self) -> dict[int, dict[object, object]]: - """Returns the chat_data created from the ``chat_data_json`` or an empty :obj:`dict`. - - Returns: - :obj:`dict`: The restored chat data. - """ - if self.chat_data is None: - self._chat_data = {} - return deepcopy(self.chat_data) # type: ignore[arg-type] - - async def get_bot_data(self) -> dict[object, object]: - """Returns the bot_data created from the ``bot_data_json`` or an empty :obj:`dict`. - - Returns: - :obj:`dict`: The restored bot data. - """ - if self.bot_data is None: - self._bot_data = {} - return deepcopy(self.bot_data) # type: ignore[arg-type] - - async def get_callback_data(self) -> Optional[CDCData]: - """Returns the callback_data created from the ``callback_data_json`` or :obj:`None`. - - .. versionadded:: 13.6 - - Returns: - tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], \ - dict[:obj:`str`, :obj:`str`]]: The restored metadata or :obj:`None`, \ - if no data was stored. - """ - if self.callback_data is None: - self._callback_data = None - return None - return deepcopy(self.callback_data) - - async def get_conversations(self, name: str) -> ConversationDict: - """Returns the conversations created from the ``conversations_json`` or an empty - :obj:`dict`. - - Returns: - :obj:`dict`: The restored conversations data. - """ - if self.conversations is None: - self._conversations = {} - return self.conversations.get(name, {}).copy() # type: ignore[union-attr] - - async def update_conversation( - self, name: str, key: ConversationKey, new_state: Optional[object] - ) -> None: - """Will update the conversations for the given handler. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:obj:`tuple` | :class:`object`): The new state for the given key. - """ - if not self._conversations: - self._conversations = {} - if self._conversations.setdefault(name, {}).get(key) == new_state: - return - self._conversations[name][key] = new_state - self._conversations_json = None - - async def update_user_data(self, user_id: int, data: dict[Any, Any]) -> None: - """Will update the user_data (if changed). - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.Application.user_data` ``[user_id]``. - """ - if self._user_data is None: - self._user_data = {} - if self._user_data.get(user_id) == data: - return - self._user_data[user_id] = data - self._user_data_json = None - - async def update_chat_data(self, chat_id: int, data: dict[Any, Any]) -> None: - """Will update the chat_data (if changed). - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.Application.chat_data` ``[chat_id]``. - """ - if self._chat_data is None: - self._chat_data = {} - if self._chat_data.get(chat_id) == data: - return - self._chat_data[chat_id] = data - self._chat_data_json = None - - async def update_bot_data(self, data: dict[Any, Any]) -> None: - """Will update the bot_data (if changed). - - Args: - data (:obj:`dict`): The :attr:`telegram.ext.Application.bot_data`. - """ - if self._bot_data == data: - return - self._bot_data = data - self._bot_data_json = None - - async def update_callback_data(self, data: CDCData) -> None: - """Will update the callback_data (if changed). - - .. versionadded:: 13.6 - - Args: - data (tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], \ - dict[:obj:`str`, :obj:`str`]]): The relevant data to restore - :class:`telegram.ext.CallbackDataCache`. - """ - if self._callback_data == data: - return - self._callback_data = data - self._callback_data_json = None - - async def drop_chat_data(self, chat_id: int) -> None: - """Will delete the specified key from the :attr:`chat_data`. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`): The chat id to delete from the persistence. - """ - if self._chat_data is None: - return - self._chat_data.pop(chat_id, None) - self._chat_data_json = None - - async def drop_user_data(self, user_id: int) -> None: - """Will delete the specified key from the :attr:`user_data`. - - .. versionadded:: 20.0 - - Args: - user_id (:obj:`int`): The user id to delete from the persistence. - """ - if self._user_data is None: - return - self._user_data.pop(user_id, None) - self._user_data_json = None - - async def refresh_user_data(self, user_id: int, user_data: dict[Any, Any]) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data` - """ - - async def refresh_chat_data(self, chat_id: int, chat_data: dict[Any, Any]) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data` - """ - - async def refresh_bot_data(self, bot_data: dict[Any, Any]) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data` - """ - - async def flush(self) -> None: - """Does nothing. - - .. versionadded:: 20.0 - .. seealso:: :meth:`telegram.ext.BasePersistence.flush` - """ - - @staticmethod - def _encode_conversations_to_json(conversations: dict[str, ConversationDict]) -> str: - """Helper method to encode a conversations dict (that uses tuples as keys) to a - JSON-serializable way. Use :meth:`self._decode_conversations_from_json` to decode. - - Args: - conversations (:obj:`dict`): The conversations dict to transform to JSON. - - Returns: - :obj:`str`: The JSON-serialized conversations dict - """ - tmp: dict[str, JSONDict] = {} - for handler, states in conversations.items(): - tmp[handler] = {} - for key, state in states.items(): - tmp[handler][json.dumps(key)] = state - return json.dumps(tmp) - - @staticmethod - def _decode_conversations_from_json(json_string: str) -> dict[str, ConversationDict]: - """Helper method to decode a conversations dict (that uses tuples as keys) from a - JSON-string created with :meth:`self._encode_conversations_to_json`. - - Args: - json_string (:obj:`str`): The conversations dict as JSON string. - - Returns: - :obj:`dict`: The conversations dict after decoding - """ - tmp = json.loads(json_string) - conversations: dict[str, ConversationDict] = {} - for handler, states in tmp.items(): - conversations[handler] = {} - for key, state in states.items(): - conversations[handler][tuple(json.loads(key))] = state - return conversations - - @staticmethod - def _decode_user_chat_data_from_json(data: str) -> dict[int, dict[object, object]]: - """Helper method to decode chat or user data (that uses ints as keys) from a - JSON-string. - - Args: - data (:obj:`str`): The user/chat_data dict as JSON string. - - Returns: - :obj:`dict`: The user/chat_data defaultdict after decoding - """ - tmp: dict[int, dict[object, object]] = {} - decoded_data = json.loads(data) - for user, user_data in decoded_data.items(): - int_user_id = int(user) - tmp[int_user_id] = {} - for key, value in user_data.items(): - try: - _id = int(key) - except ValueError: - _id = key - tmp[int_user_id][_id] = value - return tmp diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_extbot.py b/venv/lib/python3.11/site-packages/telegram/ext/_extbot.py deleted file mode 100755 index d21b1f7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_extbot.py +++ /dev/null @@ -1,4709 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=too-many-arguments -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Bot with convenience extensions.""" -import datetime as dtm -from collections.abc import Sequence -from copy import copy -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Generic, - Optional, - TypeVar, - Union, - cast, - no_type_check, - overload, -) -from uuid import uuid4 - -from telegram import ( - Animation, - Audio, - Bot, - BotCommand, - BotCommandScope, - BotDescription, - BotName, - BotShortDescription, - BusinessConnection, - CallbackQuery, - ChatAdministratorRights, - ChatFullInfo, - ChatInviteLink, - ChatMember, - ChatPermissions, - ChatPhoto, - Contact, - Document, - File, - ForumTopic, - GameHighScore, - Gift, - Gifts, - InlineKeyboardMarkup, - InlineQueryResultsButton, - InputMedia, - InputPollOption, - LinkPreviewOptions, - Location, - MaskPosition, - MenuButton, - Message, - MessageId, - PhotoSize, - Poll, - PreparedInlineMessage, - ReactionType, - ReplyParameters, - SentWebAppMessage, - StarTransactions, - Sticker, - StickerSet, - TelegramObject, - Update, - User, - UserChatBoosts, - UserProfilePhotos, - Venue, - Video, - VideoNote, - Voice, - WebhookInfo, -) -from telegram._utils.datetime import to_timestamp -from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup -from telegram.ext._callbackdatacache import CallbackDataCache -from telegram.ext._utils.types import RLARGS -from telegram.request import BaseRequest -from telegram.warnings import PTBUserWarning - -if TYPE_CHECKING: - from telegram import ( - InlineQueryResult, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - InputPaidMedia, - InputSticker, - LabeledPrice, - MessageEntity, - PassportElementError, - ShippingOption, - ) - from telegram.ext import BaseRateLimiter, Defaults - -HandledTypes = TypeVar("HandledTypes", bound=Union[Message, CallbackQuery, ChatFullInfo]) -KT = TypeVar("KT", bound=ReplyMarkup) - - -class ExtBot(Bot, Generic[RLARGS]): - """This object represents a Telegram Bot with convenience extensions. - - Warning: - Not to be confused with :class:`telegram.Bot`. - - For the documentation of the arguments, methods and attributes, please see - :class:`telegram.Bot`. - - All API methods of this class have an additional keyword argument ``rate_limit_args``. - This can be used to pass additional information to the rate limiter, specifically to - :paramref:`telegram.ext.BaseRateLimiter.process_request.rate_limit_args`. - - This class is a :class:`~typing.Generic` class and accepts one type variable that specifies - the generic type of the :attr:`rate_limiter` used by the bot. Use :obj:`None` if no rate - limiter is used. - - Warning: - * The keyword argument ``rate_limit_args`` can `not` be used, if :attr:`rate_limiter` - is :obj:`None`. - * The method :meth:`~telegram.Bot.get_updates` is the only method that does not have the - additional argument, as this method will never be rate limited. - - Examples: - :any:`Arbitrary Callback Data Bot ` - - .. seealso:: :wiki:`Arbitrary callback_data ` - - .. versionadded:: 13.6 - - .. versionchanged:: 20.0 - Removed the attribute ``arbitrary_callback_data``. You can instead use - :attr:`bot.callback_data_cache.maxsize ` to - access the size of the cache. - - .. versionchanged:: 20.5 - Removed deprecated methods ``set_sticker_set_thumb`` and ``setStickerSetThumb``. - - Args: - defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to - be used if not set explicitly in the bot methods. - arbitrary_callback_data (:obj:`bool` | :obj:`int`, optional): Whether to - allow arbitrary objects as callback data for :class:`telegram.InlineKeyboardButton`. - Pass an integer to specify the maximum number of objects cached in memory. - Defaults to :obj:`False`. - - .. seealso:: :wiki:`Arbitrary callback_data ` - rate_limiter (:class:`telegram.ext.BaseRateLimiter`, optional): A rate limiter to use for - limiting the number of requests made by the bot per time interval. - - .. versionadded:: 20.0 - - """ - - __slots__ = ("_callback_data_cache", "_defaults", "_rate_limiter") - - _LOGGER = get_logger(__name__, class_name="ExtBot") - - # using object() would be a tiny bit safer, but a string plays better with the typing setup - __RL_KEY = uuid4().hex - - @overload - def __init__( - self: "ExtBot[None]", - token: str, - base_url: str = "https://api.telegram.org/bot", - base_file_url: str = "https://api.telegram.org/file/bot", - request: Optional[BaseRequest] = None, - get_updates_request: Optional[BaseRequest] = None, - private_key: Optional[bytes] = None, - private_key_password: Optional[bytes] = None, - defaults: Optional["Defaults"] = None, - arbitrary_callback_data: Union[bool, int] = False, - local_mode: bool = False, - ): ... - - @overload - def __init__( - self: "ExtBot[RLARGS]", - token: str, - base_url: str = "https://api.telegram.org/bot", - base_file_url: str = "https://api.telegram.org/file/bot", - request: Optional[BaseRequest] = None, - get_updates_request: Optional[BaseRequest] = None, - private_key: Optional[bytes] = None, - private_key_password: Optional[bytes] = None, - defaults: Optional["Defaults"] = None, - arbitrary_callback_data: Union[bool, int] = False, - local_mode: bool = False, - rate_limiter: Optional["BaseRateLimiter[RLARGS]"] = None, - ): ... - - def __init__( - self, - token: str, - base_url: str = "https://api.telegram.org/bot", - base_file_url: str = "https://api.telegram.org/file/bot", - request: Optional[BaseRequest] = None, - get_updates_request: Optional[BaseRequest] = None, - private_key: Optional[bytes] = None, - private_key_password: Optional[bytes] = None, - defaults: Optional["Defaults"] = None, - arbitrary_callback_data: Union[bool, int] = False, - local_mode: bool = False, - rate_limiter: Optional["BaseRateLimiter[RLARGS]"] = None, - ): - super().__init__( - token=token, - base_url=base_url, - base_file_url=base_file_url, - request=request, - get_updates_request=get_updates_request, - private_key=private_key, - private_key_password=private_key_password, - local_mode=local_mode, - ) - with self._unfrozen(): - self._defaults: Optional[Defaults] = defaults - self._rate_limiter: Optional[BaseRateLimiter] = rate_limiter - self._callback_data_cache: Optional[CallbackDataCache] = None - - # set up callback_data - if arbitrary_callback_data is False: - return - - if not isinstance(arbitrary_callback_data, bool): - maxsize = cast(int, arbitrary_callback_data) - else: - maxsize = 1024 - - self._callback_data_cache = CallbackDataCache(bot=self, maxsize=maxsize) - - def __repr__(self) -> str: - """Give a string representation of the bot in the form ``ExtBot[token=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs(self, token=self.token) - - @classmethod - def _warn( - cls, - message: Union[str, PTBUserWarning], - category: type[Warning] = PTBUserWarning, - stacklevel: int = 0, - ) -> None: - """We override this method to add one more level to the stacklevel, so that the warning - points to the user's code, not to the PTB code. - """ - super()._warn(message=message, category=category, stacklevel=stacklevel + 2) - - @property - def callback_data_cache(self) -> Optional[CallbackDataCache]: - """:class:`telegram.ext.CallbackDataCache`: Optional. The cache for - objects passed as callback data for :class:`telegram.InlineKeyboardButton`. - - Examples: - :any:`Arbitrary Callback Data Bot ` - - .. versionchanged:: 20.0 - * This property is now read-only. - * This property is now optional and can be :obj:`None` if - :paramref:`~telegram.ext.ExtBot.arbitrary_callback_data` is set to :obj:`False`. - """ - return self._callback_data_cache - - async def initialize(self) -> None: - """See :meth:`telegram.Bot.initialize`. Also initializes the - :paramref:`ExtBot.rate_limiter` (if set) - by calling :meth:`telegram.ext.BaseRateLimiter.initialize`. - """ - # Initialize before calling super, because super calls get_me - if self.rate_limiter: - await self.rate_limiter.initialize() - await super().initialize() - - async def shutdown(self) -> None: - """See :meth:`telegram.Bot.shutdown`. Also shuts down the - :paramref:`ExtBot.rate_limiter` (if set) by - calling :meth:`telegram.ext.BaseRateLimiter.shutdown`. - """ - # Shut down the rate limiter before shutting down the request objects! - if self.rate_limiter: - await self.rate_limiter.shutdown() - await super().shutdown() - - @classmethod - def _merge_api_rl_kwargs( - cls, api_kwargs: Optional[JSONDict], rate_limit_args: Optional[RLARGS] - ) -> Optional[JSONDict]: - """Inserts the `rate_limit_args` into `api_kwargs` with the special key `__RL_KEY` so - that we can extract them later without having to modify the `telegram.Bot` class. - """ - if not rate_limit_args: - return api_kwargs - if api_kwargs is None: - api_kwargs = {} - api_kwargs[cls.__RL_KEY] = rate_limit_args - return api_kwargs - - @classmethod - def _extract_rl_kwargs(cls, data: Optional[JSONDict]) -> Optional[RLARGS]: - """Extracts the `rate_limit_args` from `data` if it exists.""" - if not data: - return None - return data.pop(cls.__RL_KEY, None) - - async def _do_post( - self, - endpoint: str, - data: JSONDict, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - ) -> Union[bool, JSONDict, list[JSONDict]]: - """Order of method calls is: Bot.some_method -> Bot._post -> Bot._do_post. - So we can override Bot._do_post to add rate limiting. - """ - rate_limit_args = self._extract_rl_kwargs(data) - if not self.rate_limiter and rate_limit_args is not None: - raise ValueError( - "`rate_limit_args` can only be used if a `ExtBot.rate_limiter` is set." - ) - - # getting updates should not be rate limited! - if endpoint == "getUpdates" or not self.rate_limiter: - return await super()._do_post( - endpoint=endpoint, - data=data, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - read_timeout=read_timeout, - ) - - kwargs = { - "read_timeout": read_timeout, - "write_timeout": write_timeout, - "connect_timeout": connect_timeout, - "pool_timeout": pool_timeout, - } - self._LOGGER.debug( - "Passing request through rate limiter of type %s with rate_limit_args %s", - type(self.rate_limiter), - rate_limit_args, - ) - return await self.rate_limiter.process_request( - callback=super()._do_post, - args=(endpoint, data), - kwargs=kwargs, - endpoint=endpoint, - data=data, - rate_limit_args=rate_limit_args, - ) - - @property - def defaults(self) -> Optional["Defaults"]: - """The :class:`telegram.ext.Defaults` used by this bot, if any.""" - # This is a property because defaults shouldn't be changed at runtime - return self._defaults - - @property - def rate_limiter(self) -> Optional["BaseRateLimiter[RLARGS]"]: - """The :class:`telegram.ext.BaseRateLimiter` used by this bot, if any. - - .. versionadded:: 20.0 - """ - # This is a property because the rate limiter shouldn't be changed at runtime - return self._rate_limiter - - def _merge_lpo_defaults( - self, lpo: ODVInput[LinkPreviewOptions] - ) -> Optional[LinkPreviewOptions]: - # This is a standalone method because both _insert_defaults and - # _insert_defaults_for_ilq_results need this logic - # - # If Defaults.LPO is set, and LPO is passed in the bot method we should fuse - # them, giving precedence to passed values. - # Defaults.LPO(True, "google.com", True) & LPO=LPO(True, ..., False) -> - # LPO(True, "google.com", False) - if self.defaults is None or (defaults_lpo := self.defaults.link_preview_options) is None: - return DefaultValue.get_value(lpo) - return LinkPreviewOptions( - **{ - attr: ( - getattr(defaults_lpo, attr) - # only use the default value - # if the value was explicitly passed to the LPO object - if isinstance(orig_attr := getattr(lpo, attr), DefaultValue) - else orig_attr - ) - for attr in defaults_lpo.__slots__ - } - ) - - def _insert_defaults(self, data: dict[str, object]) -> None: - """Inserts the defaults values for optional kwargs for which tg.ext.Defaults provides - convenience functionality, i.e. the kwargs with a tg.utils.helpers.DefaultValue default - - data is edited in-place. As timeout is not passed via the kwargs, it needs to be passed - separately and gets returned. - - This can only work, if all kwargs that may have defaults are passed in data! - """ - if self.defaults is None: - # If we have no defaults to insert, the behavior is the same as in `tg.Bot` - super()._insert_defaults(data) - return - - # if we have Defaults, we - # 1) replace all DefaultValue instances with the relevant Defaults value. If there is none, - # we fall back to the default value of the bot method - # 2) convert all datetime.datetime objects to timestamps wrt the correct default timezone - # 3) set the correct parse_mode for all InputMedia objects - # 4) handle the LinkPreviewOptions case (see below) - # 5) handle the ReplyParameters case (see below) - # 6) handle text_parse_mode in InputPollOption - for key, val in data.items(): - # 1) - if isinstance(val, DefaultValue): - data[key] = self.defaults.api_defaults.get(key, val.value) - - # 2) - elif isinstance(val, dtm.datetime): - data[key] = to_timestamp(val, tzinfo=self.defaults.tzinfo) - - # 3) - elif isinstance(val, InputMedia) and val.parse_mode is DEFAULT_NONE: - # Copy object as not to edit it in-place - copied_val = copy(val) - with copied_val._unfrozen(): - copied_val.parse_mode = self.defaults.parse_mode - data[key] = copied_val - elif key == "media" and isinstance(val, Sequence): - # Copy objects as not to edit them in-place - copy_list = [copy(media) for media in val] - for media in copy_list: - if media.parse_mode is DEFAULT_NONE: - with media._unfrozen(): - media.parse_mode = self.defaults.parse_mode - - data[key] = copy_list - - # 4) LinkPreviewOptions: - elif isinstance(val, LinkPreviewOptions): - data[key] = self._merge_lpo_defaults(val) - - # 5) - # Similar to LinkPreviewOptions, but only two of the arguments of RPs have a default - elif isinstance(val, ReplyParameters) and ( - (defaults_aswr := self.defaults.allow_sending_without_reply) is not None - or self.defaults.quote_parse_mode is not None - ): - new_value = copy(val) - with new_value._unfrozen(): - new_value.allow_sending_without_reply = ( - defaults_aswr - if isinstance(val.allow_sending_without_reply, DefaultValue) - else val.allow_sending_without_reply - ) - new_value.quote_parse_mode = ( - self.defaults.quote_parse_mode - if isinstance(val.quote_parse_mode, DefaultValue) - else val.quote_parse_mode - ) - - data[key] = new_value - - # 6) - elif isinstance(val, Sequence) and all( - isinstance(obj, InputPollOption) for obj in val - ): - new_val = [] - for option in val: - if not isinstance(option.text_parse_mode, DefaultValue): - new_val.append(option) - else: - new_option = copy(option) - with new_option._unfrozen(): - new_option.text_parse_mode = self.defaults.text_parse_mode - new_val.append(new_option) - data[key] = new_val - - def _replace_keyboard(self, reply_markup: Optional[KT]) -> Optional[KT]: - # If the reply_markup is an inline keyboard and we allow arbitrary callback data, let the - # CallbackDataCache build a new keyboard with the data replaced. Otherwise return the input - if isinstance(reply_markup, InlineKeyboardMarkup) and self.callback_data_cache is not None: - # for some reason mypy doesn't understand that IKB is a subtype of Optional[KT] - return self.callback_data_cache.process_keyboard( # type: ignore[return-value] - reply_markup - ) - - return reply_markup - - def insert_callback_data(self, update: Update) -> None: - """If this bot allows for arbitrary callback data, this inserts the cached data into all - corresponding buttons within this update. - - Note: - Checks :attr:`telegram.Message.via_bot` and :attr:`telegram.Message.from_user` - to figure out if a) a reply markup exists and b) it was actually sent by this - bot. If not, the message will be returned unchanged. - - Note that this will fail for channel posts, as :attr:`telegram.Message.from_user` is - :obj:`None` for those! In the corresponding reply markups, the callback data will be - replaced by :class:`telegram.ext.InvalidCallbackData`. - - Warning: - *In place*, i.e. the passed :class:`telegram.Message` will be changed! - - Args: - update (:class:`telegram.Update`): The update. - - """ - # The only incoming updates that can directly contain a message sent by the bot itself are: - # * CallbackQueries - # * Messages where the pinned_message is sent by the bot - # * Messages where the reply_to_message is sent by the bot - # * Messages where via_bot is the bot - # Finally there is effective_chat.pinned message, but that's only returned in get_chat - if update.callback_query: - self._insert_callback_data(update.callback_query) - # elif instead of if, as effective_message includes callback_query.message - # and that has already been processed - elif update.effective_message: - self._insert_callback_data(update.effective_message) - - def _insert_callback_data(self, obj: HandledTypes) -> HandledTypes: - if self.callback_data_cache is None: - return obj - - if isinstance(obj, CallbackQuery): - self.callback_data_cache.process_callback_query(obj) - return obj # type: ignore[return-value] - - if isinstance(obj, Message): - if obj.reply_to_message: - # reply_to_message can't contain further reply_to_messages, so no need to check - self.callback_data_cache.process_message(obj.reply_to_message) - if isinstance(obj.reply_to_message.pinned_message, Message): - # pinned messages can't contain reply_to_message, no need to check - self.callback_data_cache.process_message(obj.reply_to_message.pinned_message) - if isinstance(obj.pinned_message, Message): - # pinned messages can't contain reply_to_message, no need to check - self.callback_data_cache.process_message(obj.pinned_message) - - # Finally, handle the message itself - self.callback_data_cache.process_message(message=obj) - return obj # type: ignore[return-value] - - if isinstance(obj, ChatFullInfo) and obj.pinned_message: - self.callback_data_cache.process_message(obj.pinned_message) - - return obj - - async def _send_message( - self, - endpoint: str, - data: JSONDict, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> Any: - # We override this method to call self._replace_keyboard and self._insert_callback_data. - # This covers most methods that have a reply_markup - result = await super()._send_message( - endpoint=endpoint, - data=data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=self._replace_keyboard(reply_markup), - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - link_preview_options=link_preview_options, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - if isinstance(result, Message): - self._insert_callback_data(result) - return result - - async def get_updates( - self, - offset: Optional[int] = None, - limit: Optional[int] = None, - timeout: Optional[int] = None, # noqa: ASYNC109 - allowed_updates: Optional[Sequence[str]] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - ) -> tuple[Update, ...]: - updates = await super().get_updates( - offset=offset, - limit=limit, - timeout=timeout, - allowed_updates=allowed_updates, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - for update in updates: - self.insert_callback_data(update) - - return updates - - def _effective_inline_results( - self, - results: Union[ - Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]] - ], - next_offset: Optional[str] = None, - current_offset: Optional[str] = None, - ) -> tuple[Sequence["InlineQueryResult"], Optional[str]]: - """This method is called by Bot.answer_inline_query to build the actual results list. - Overriding this to call self._replace_keyboard suffices - """ - effective_results, next_offset = super()._effective_inline_results( - results=results, next_offset=next_offset, current_offset=current_offset - ) - - # Process arbitrary callback - if self.callback_data_cache is None: - return effective_results, next_offset - results = [] - for result in effective_results: - # All currently existingInlineQueryResults have a reply_markup, but future ones - # might not have. Better be save than sorry - if not hasattr(result, "reply_markup"): - results.append(result) - else: - # We build a new result in case the user wants to use the same object in - # different places - new_result = copy(result) - with new_result._unfrozen(): - markup = self._replace_keyboard(result.reply_markup) - new_result.reply_markup = markup - - results.append(new_result) - - return results, next_offset - - @no_type_check # mypy doesn't play too well with hasattr - def _insert_defaults_for_ilq_results(self, res: "InlineQueryResult") -> "InlineQueryResult": - """This method is called by Bot.answer_inline_query to replace `DefaultValue(obj)` with - `obj`. - Overriding this to call insert the actual desired default values. - """ - if self.defaults is None: - # If we have no defaults to insert, the behavior is the same as in `tg.Bot` - return super()._insert_defaults_for_ilq_results(res) - - # Copy the objects that need modification to avoid modifying the original object - copied = False - if hasattr(res, "parse_mode") and res.parse_mode is DEFAULT_NONE: - res = copy(res) - with res._unfrozen(): - copied = True - res.parse_mode = self.defaults.parse_mode - if hasattr(res, "input_message_content") and res.input_message_content: - if ( - hasattr(res.input_message_content, "parse_mode") - and res.input_message_content.parse_mode is DEFAULT_NONE - ): - if not copied: - res = copy(res) - copied = True - with res.input_message_content._unfrozen(): - res.input_message_content.parse_mode = self.defaults.parse_mode - if hasattr(res.input_message_content, "link_preview_options"): - if not copied: - res = copy(res) - with res.input_message_content._unfrozen(): - if res.input_message_content.link_preview_options is DEFAULT_NONE: - res.input_message_content.link_preview_options = ( - self.defaults.link_preview_options - ) - else: - # merge the existing options with the defaults - res.input_message_content.link_preview_options = self._merge_lpo_defaults( - res.input_message_content.link_preview_options - ) - - return res - - async def do_api_request( - self, - endpoint: str, - api_kwargs: Optional[JSONDict] = None, - return_type: Optional[type[TelegramObject]] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - rate_limit_args: Optional[RLARGS] = None, - ) -> Any: - return await super().do_api_request( - endpoint=endpoint, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - return_type=return_type, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - - async def stop_poll( - self, - chat_id: Union[int, str], - message_id: int, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Poll: - # We override this method to call self._replace_keyboard - return await super().stop_poll( - chat_id=chat_id, - message_id=message_id, - reply_markup=self._replace_keyboard(reply_markup), - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def copy_message( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_id: int, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - show_caption_above_media: Optional[bool] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> MessageId: - # We override this method to call self._replace_keyboard - return await super().copy_message( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=self._replace_keyboard(reply_markup), - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - show_caption_above_media=show_caption_above_media, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def copy_messages( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - remove_caption: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple["MessageId", ...]: - # We override this method to call self._replace_keyboard - return await super().copy_messages( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - remove_caption=remove_caption, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatFullInfo: - # We override this method to call self._insert_callback_data - result = await super().get_chat( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - return self._insert_callback_data(result) - - async def add_sticker_to_set( - self, - user_id: int, - name: str, - sticker: "InputSticker", - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().add_sticker_to_set( - user_id=user_id, - name=name, - sticker=sticker, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_callback_query( - self, - callback_query_id: str, - text: Optional[str] = None, - show_alert: Optional[bool] = None, - url: Optional[str] = None, - cache_time: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().answer_callback_query( - callback_query_id=callback_query_id, - text=text, - show_alert=show_alert, - url=url, - cache_time=cache_time, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_inline_query( - self, - inline_query_id: str, - results: Union[ - Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]] - ], - cache_time: Optional[int] = None, - is_personal: Optional[bool] = None, - next_offset: Optional[str] = None, - button: Optional[InlineQueryResultsButton] = None, - *, - current_offset: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().answer_inline_query( - inline_query_id=inline_query_id, - results=results, - cache_time=cache_time, - is_personal=is_personal, - next_offset=next_offset, - current_offset=current_offset, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - button=button, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def save_prepared_inline_message( - self, - user_id: int, - result: "InlineQueryResult", - allow_user_chats: Optional[bool] = None, - allow_bot_chats: Optional[bool] = None, - allow_group_chats: Optional[bool] = None, - allow_channel_chats: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> PreparedInlineMessage: - return await super().save_prepared_inline_message( - user_id=user_id, - result=result, - allow_user_chats=allow_user_chats, - allow_bot_chats=allow_bot_chats, - allow_group_chats=allow_group_chats, - allow_channel_chats=allow_channel_chats, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_pre_checkout_query( - self, - pre_checkout_query_id: str, - ok: bool, - error_message: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().answer_pre_checkout_query( - pre_checkout_query_id=pre_checkout_query_id, - ok=ok, - error_message=error_message, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_shipping_query( - self, - shipping_query_id: str, - ok: bool, - shipping_options: Optional[Sequence["ShippingOption"]] = None, - error_message: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().answer_shipping_query( - shipping_query_id=shipping_query_id, - ok=ok, - shipping_options=shipping_options, - error_message=error_message, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def answer_web_app_query( - self, - web_app_query_id: str, - result: "InlineQueryResult", - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> SentWebAppMessage: - return await super().answer_web_app_query( - web_app_query_id=web_app_query_id, - result=result, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def approve_chat_join_request( - self, - chat_id: Union[str, int], - user_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().approve_chat_join_request( - chat_id=chat_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def ban_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - until_date: Optional[Union[int, dtm.datetime]] = None, - revoke_messages: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().ban_chat_member( - chat_id=chat_id, - user_id=user_id, - until_date=until_date, - revoke_messages=revoke_messages, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def ban_chat_sender_chat( - self, - chat_id: Union[str, int], - sender_chat_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().ban_chat_sender_chat( - chat_id=chat_id, - sender_chat_id=sender_chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def create_chat_invite_link( - self, - chat_id: Union[str, int], - expire_date: Optional[Union[int, dtm.datetime]] = None, - member_limit: Optional[int] = None, - name: Optional[str] = None, - creates_join_request: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().create_chat_invite_link( - chat_id=chat_id, - expire_date=expire_date, - member_limit=member_limit, - name=name, - creates_join_request=creates_join_request, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def create_invoice_link( - self, - title: str, - description: str, - payload: str, - provider_token: Optional[str], - currency: str, - prices: Sequence["LabeledPrice"], - max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[Sequence[int]] = None, - provider_data: Optional[Union[str, object]] = None, - photo_url: Optional[str] = None, - photo_size: Optional[int] = None, - photo_width: Optional[int] = None, - photo_height: Optional[int] = None, - need_name: Optional[bool] = None, - need_phone_number: Optional[bool] = None, - need_email: Optional[bool] = None, - need_shipping_address: Optional[bool] = None, - send_phone_number_to_provider: Optional[bool] = None, - send_email_to_provider: Optional[bool] = None, - is_flexible: Optional[bool] = None, - subscription_period: Optional[Union[int, dtm.timedelta]] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> str: - return await super().create_invoice_link( - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - provider_data=provider_data, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - is_flexible=is_flexible, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - subscription_period=subscription_period, - business_connection_id=business_connection_id, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def create_new_sticker_set( - self, - user_id: int, - name: str, - title: str, - stickers: Sequence["InputSticker"], - sticker_type: Optional[str] = None, - needs_repainting: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().create_new_sticker_set( - user_id=user_id, - name=name, - title=title, - stickers=stickers, - sticker_type=sticker_type, - needs_repainting=needs_repainting, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def decline_chat_join_request( - self, - chat_id: Union[str, int], - user_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().decline_chat_join_request( - chat_id=chat_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_chat_photo( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_chat_photo( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_chat_sticker_set( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_chat_sticker_set( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_forum_topic( - self, - chat_id: Union[str, int], - message_thread_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_forum_topic( - chat_id=chat_id, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_message( - self, - chat_id: Union[str, int], - message_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_message( - chat_id=chat_id, - message_id=message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_messages( - self, - chat_id: Union[str, int], - message_ids: Sequence[int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_messages( - chat_id=chat_id, - message_ids=message_ids, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_my_commands( - self, - scope: Optional[BotCommandScope] = None, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_my_commands( - scope=scope, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_sticker_from_set( - self, - sticker: Union[str, "Sticker"], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_sticker_from_set( - sticker=sticker, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_webhook( - self, - drop_pending_updates: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_webhook( - drop_pending_updates=drop_pending_updates, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_chat_invite_link( - self, - chat_id: Union[str, int], - invite_link: Union[str, "ChatInviteLink"], - expire_date: Optional[Union[int, dtm.datetime]] = None, - member_limit: Optional[int] = None, - name: Optional[str] = None, - creates_join_request: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().edit_chat_invite_link( - chat_id=chat_id, - invite_link=invite_link, - expire_date=expire_date, - member_limit=member_limit, - name=name, - creates_join_request=creates_join_request, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_forum_topic( - self, - chat_id: Union[str, int], - message_thread_id: int, - name: Optional[str] = None, - icon_custom_emoji_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().edit_forum_topic( - chat_id=chat_id, - message_thread_id=message_thread_id, - name=name, - icon_custom_emoji_id=icon_custom_emoji_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_general_forum_topic( - self, - chat_id: Union[str, int], - name: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().edit_general_forum_topic( - chat_id=chat_id, - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_message_caption( - self, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - show_caption_above_media: Optional[bool] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_caption( - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - caption=caption, - reply_markup=reply_markup, - parse_mode=parse_mode, - caption_entities=caption_entities, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - show_caption_above_media=show_caption_above_media, - ) - - async def edit_message_live_location( - self, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - latitude: Optional[float] = None, - longitude: Optional[float] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - horizontal_accuracy: Optional[float] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - live_period: Optional[int] = None, - business_connection_id: Optional[str] = None, - *, - location: Optional[Location] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_live_location( - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - latitude=latitude, - longitude=longitude, - reply_markup=reply_markup, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - live_period=live_period, - location=location, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_message_media( - self, - media: "InputMedia", - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_media( - media=media, - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_message_reply_markup( - self, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_reply_markup( - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_message_text( - self, - text: str, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - entities: Optional[Sequence["MessageEntity"]] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, - business_connection_id: Optional[str] = None, - *, - disable_web_page_preview: Optional[bool] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().edit_message_text( - text=text, - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - reply_markup=reply_markup, - entities=entities, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - link_preview_options=link_preview_options, - ) - - async def export_chat_invite_link( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> str: - return await super().export_chat_invite_link( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def forward_message( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().forward_message( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_id=message_id, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def forward_messages( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_ids: Sequence[int], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[MessageId, ...]: - return await super().forward_messages( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_ids=message_ids, - disable_notification=disable_notification, - protect_content=protect_content, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat_administrators( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[ChatMember, ...]: - return await super().get_chat_administrators( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatMember: - return await super().get_chat_member( - chat_id=chat_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat_member_count( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> int: - return await super().get_chat_member_count( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_chat_menu_button( - self, - chat_id: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> MenuButton: - return await super().get_chat_menu_button( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_file( - self, - file_id: Union[ - str, Animation, Audio, ChatPhoto, Document, PhotoSize, Sticker, Video, VideoNote, Voice - ], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> File: - return await super().get_file( - file_id=file_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_forum_topic_icon_stickers( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[Sticker, ...]: - return await super().get_forum_topic_icon_stickers( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_game_high_scores( - self, - user_id: int, - chat_id: Optional[int] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[GameHighScore, ...]: - return await super().get_game_high_scores( - user_id=user_id, - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_me( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> User: - return await super().get_me( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_commands( - self, - scope: Optional[BotCommandScope] = None, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[BotCommand, ...]: - return await super().get_my_commands( - scope=scope, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_default_administrator_rights( - self, - for_channels: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatAdministratorRights: - return await super().get_my_default_administrator_rights( - for_channels=for_channels, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_sticker_set( - self, - name: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> StickerSet: - return await super().get_sticker_set( - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_custom_emoji_stickers( - self, - custom_emoji_ids: Sequence[str], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> tuple[Sticker, ...]: - return await super().get_custom_emoji_stickers( - custom_emoji_ids=custom_emoji_ids, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_user_profile_photos( - self, - user_id: int, - offset: Optional[int] = None, - limit: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> UserProfilePhotos: - return await super().get_user_profile_photos( - user_id=user_id, - offset=offset, - limit=limit, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_webhook_info( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> WebhookInfo: - return await super().get_webhook_info( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def leave_chat( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().leave_chat( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def log_out( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().log_out( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def close( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().close( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def close_forum_topic( - self, - chat_id: Union[str, int], - message_thread_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().close_forum_topic( - chat_id=chat_id, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def close_general_forum_topic( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().close_general_forum_topic( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def create_forum_topic( - self, - chat_id: Union[str, int], - name: str, - icon_color: Optional[int] = None, - icon_custom_emoji_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ForumTopic: - return await super().create_forum_topic( - chat_id=chat_id, - name=name, - icon_color=icon_color, - icon_custom_emoji_id=icon_custom_emoji_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def reopen_general_forum_topic( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().reopen_general_forum_topic( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def hide_general_forum_topic( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().hide_general_forum_topic( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unhide_general_forum_topic( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unhide_general_forum_topic( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def pin_chat_message( - self, - chat_id: Union[str, int], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().pin_chat_message( - chat_id=chat_id, - message_id=message_id, - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - business_connection_id=business_connection_id, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def promote_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - can_change_info: Optional[bool] = None, - can_post_messages: Optional[bool] = None, - can_edit_messages: Optional[bool] = None, - can_delete_messages: Optional[bool] = None, - can_invite_users: Optional[bool] = None, - can_restrict_members: Optional[bool] = None, - can_pin_messages: Optional[bool] = None, - can_promote_members: Optional[bool] = None, - is_anonymous: Optional[bool] = None, - can_manage_chat: Optional[bool] = None, - can_manage_video_chats: Optional[bool] = None, - can_manage_topics: Optional[bool] = None, - can_post_stories: Optional[bool] = None, - can_edit_stories: Optional[bool] = None, - can_delete_stories: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().promote_chat_member( - chat_id=chat_id, - user_id=user_id, - can_change_info=can_change_info, - can_post_messages=can_post_messages, - can_edit_messages=can_edit_messages, - can_delete_messages=can_delete_messages, - can_invite_users=can_invite_users, - can_restrict_members=can_restrict_members, - can_pin_messages=can_pin_messages, - can_promote_members=can_promote_members, - is_anonymous=is_anonymous, - can_manage_chat=can_manage_chat, - can_manage_video_chats=can_manage_video_chats, - can_manage_topics=can_manage_topics, - can_post_stories=can_post_stories, - can_edit_stories=can_edit_stories, - can_delete_stories=can_delete_stories, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def reopen_forum_topic( - self, - chat_id: Union[str, int], - message_thread_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().reopen_forum_topic( - chat_id=chat_id, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def restrict_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - permissions: ChatPermissions, - until_date: Optional[Union[int, dtm.datetime]] = None, - use_independent_chat_permissions: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().restrict_chat_member( - chat_id=chat_id, - user_id=user_id, - permissions=permissions, - until_date=until_date, - use_independent_chat_permissions=use_independent_chat_permissions, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def revoke_chat_invite_link( - self, - chat_id: Union[str, int], - invite_link: Union[str, "ChatInviteLink"], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().revoke_chat_invite_link( - chat_id=chat_id, - invite_link=invite_link, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def send_animation( - self, - chat_id: Union[int, str], - animation: Union[FileInput, "Animation"], - duration: Optional[int] = None, - width: Optional[int] = None, - height: Optional[int] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_animation( - chat_id=chat_id, - animation=animation, - duration=duration, - width=width, - height=height, - caption=caption, - parse_mode=parse_mode, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - has_spoiler=has_spoiler, - thumbnail=thumbnail, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - business_connection_id=business_connection_id, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_audio( - self, - chat_id: Union[int, str], - audio: Union[FileInput, "Audio"], - duration: Optional[int] = None, - performer: Optional[str] = None, - title: Optional[str] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_audio( - chat_id=chat_id, - audio=audio, - duration=duration, - performer=performer, - business_connection_id=business_connection_id, - title=title, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - thumbnail=thumbnail, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_chat_action( - self, - chat_id: Union[str, int], - action: str, - message_thread_id: Optional[int] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().send_chat_action( - chat_id=chat_id, - business_connection_id=business_connection_id, - action=action, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def send_contact( - self, - chat_id: Union[int, str], - phone_number: Optional[str] = None, - first_name: Optional[str] = None, - last_name: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - vcard: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - contact: Optional[Contact] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_contact( - chat_id=chat_id, - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - vcard=vcard, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - contact=contact, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - business_connection_id=business_connection_id, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_dice( - self, - chat_id: Union[int, str], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - emoji: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_dice( - chat_id=chat_id, - disable_notification=disable_notification, - business_connection_id=business_connection_id, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - emoji=emoji, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_document( - self, - chat_id: Union[int, str], - document: Union[FileInput, "Document"], - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_content_type_detection: Optional[bool] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_document( - chat_id=chat_id, - document=document, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - parse_mode=parse_mode, - disable_content_type_detection=disable_content_type_detection, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - business_connection_id=business_connection_id, - message_thread_id=message_thread_id, - thumbnail=thumbnail, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_game( - self, - chat_id: int, - game_short_name: str, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_game( - chat_id=chat_id, - game_short_name=game_short_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_invoice( - self, - chat_id: Union[int, str], - title: str, - description: str, - payload: str, - provider_token: Optional[str], - currency: str, - prices: Sequence["LabeledPrice"], - start_parameter: Optional[str] = None, - photo_url: Optional[str] = None, - photo_size: Optional[int] = None, - photo_width: Optional[int] = None, - photo_height: Optional[int] = None, - need_name: Optional[bool] = None, - need_phone_number: Optional[bool] = None, - need_email: Optional[bool] = None, - need_shipping_address: Optional[bool] = None, - is_flexible: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - provider_data: Optional[Union[str, object]] = None, - send_phone_number_to_provider: Optional[bool] = None, - send_email_to_provider: Optional[bool] = None, - max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[Sequence[int]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_invoice( - chat_id=chat_id, - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - start_parameter=start_parameter, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - is_flexible=is_flexible, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - provider_data=provider_data, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - allow_sending_without_reply=allow_sending_without_reply, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_location( - self, - chat_id: Union[int, str], - latitude: Optional[float] = None, - longitude: Optional[float] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - live_period: Optional[int] = None, - horizontal_accuracy: Optional[float] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - location: Optional[Location] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_location( - chat_id=chat_id, - latitude=latitude, - longitude=longitude, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - live_period=live_period, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - location=location, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - business_connection_id=business_connection_id, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_media_group( - self, - chat_id: Union[int, str], - media: Sequence[ - Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] - ], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - ) -> tuple[Message, ...]: - return await super().send_media_group( - chat_id=chat_id, - media=media, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - caption=caption, - business_connection_id=business_connection_id, - parse_mode=parse_mode, - caption_entities=caption_entities, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_message( - self, - chat_id: Union[int, str], - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - entities: Optional[Sequence["MessageEntity"]] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - message_thread_id: Optional[int] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - disable_web_page_preview: Optional[bool] = None, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_message( - chat_id=chat_id, - text=text, - parse_mode=parse_mode, - entities=entities, - disable_web_page_preview=disable_web_page_preview, - disable_notification=disable_notification, - business_connection_id=business_connection_id, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - link_preview_options=link_preview_options, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_photo( - self, - chat_id: Union[int, str], - photo: Union[FileInput, "PhotoSize"], - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_photo( - chat_id=chat_id, - photo=photo, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - has_spoiler=has_spoiler, - reply_parameters=reply_parameters, - filename=filename, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_poll( - self, - chat_id: Union[int, str], - question: str, - options: Sequence[Union[str, "InputPollOption"]], - is_anonymous: Optional[bool] = None, - type: Optional[str] = None, # pylint: disable=redefined-builtin - allows_multiple_answers: Optional[bool] = None, - correct_option_id: Optional[CorrectOptionID] = None, - is_closed: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - explanation: Optional[str] = None, - explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, - open_period: Optional[int] = None, - close_date: Optional[Union[int, dtm.datetime]] = None, - explanation_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - question_parse_mode: ODVInput[str] = DEFAULT_NONE, - question_entities: Optional[Sequence["MessageEntity"]] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_poll( - chat_id=chat_id, - question=question, - options=options, - is_anonymous=is_anonymous, - type=type, - allows_multiple_answers=allows_multiple_answers, - correct_option_id=correct_option_id, - is_closed=is_closed, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - explanation=explanation, - explanation_parse_mode=explanation_parse_mode, - open_period=open_period, - close_date=close_date, - allow_sending_without_reply=allow_sending_without_reply, - explanation_entities=explanation_entities, - business_connection_id=business_connection_id, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - question_parse_mode=question_parse_mode, - question_entities=question_entities, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_sticker( - self, - chat_id: Union[int, str], - sticker: Union[FileInput, "Sticker"], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - emoji: Optional[str] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_sticker( - chat_id=chat_id, - sticker=sticker, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - emoji=emoji, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_venue( - self, - chat_id: Union[int, str], - latitude: Optional[float] = None, - longitude: Optional[float] = None, - title: Optional[str] = None, - address: Optional[str] = None, - foursquare_id: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - foursquare_type: Optional[str] = None, - google_place_id: Optional[str] = None, - google_place_type: Optional[str] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - venue: Optional[Venue] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_venue( - chat_id=chat_id, - latitude=latitude, - longitude=longitude, - title=title, - address=address, - foursquare_id=foursquare_id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - foursquare_type=foursquare_type, - google_place_id=google_place_id, - google_place_type=google_place_type, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - business_connection_id=business_connection_id, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - venue=venue, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_video( - self, - chat_id: Union[int, str], - video: Union[FileInput, "Video"], - duration: Optional[int] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - width: Optional[int] = None, - height: Optional[int] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - supports_streaming: Optional[bool] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_video( - chat_id=chat_id, - video=video, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - width=width, - height=height, - parse_mode=parse_mode, - supports_streaming=supports_streaming, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - has_spoiler=has_spoiler, - thumbnail=thumbnail, - filename=filename, - reply_parameters=reply_parameters, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - show_caption_above_media=show_caption_above_media, - ) - - async def send_video_note( - self, - chat_id: Union[int, str], - video_note: Union[FileInput, "VideoNote"], - duration: Optional[int] = None, - length: Optional[int] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_video_note( - chat_id=chat_id, - video_note=video_note, - duration=duration, - length=length, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - thumbnail=thumbnail, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def send_voice( - self, - chat_id: Union[int, str], - voice: Union[FileInput, "Voice"], - duration: Optional[int] = None, - caption: Optional[str] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: Optional[ReplyMarkup] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, - reply_parameters: Optional["ReplyParameters"] = None, - business_connection_id: Optional[str] = None, - message_effect_id: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: Optional[str] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_voice( - chat_id=chat_id, - voice=voice, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - parse_mode=parse_mode, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - protect_content=protect_content, - message_thread_id=message_thread_id, - reply_parameters=reply_parameters, - filename=filename, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def set_chat_administrator_custom_title( - self, - chat_id: Union[int, str], - user_id: int, - custom_title: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_administrator_custom_title( - chat_id=chat_id, - user_id=user_id, - custom_title=custom_title, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_description( - self, - chat_id: Union[str, int], - description: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_description( - chat_id=chat_id, - description=description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_user_emoji_status( - self, - user_id: int, - emoji_status_custom_emoji_id: Optional[str] = None, - emoji_status_expiration_date: Optional[Union[int, dtm.datetime]] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_user_emoji_status( - user_id=user_id, - emoji_status_custom_emoji_id=emoji_status_custom_emoji_id, - emoji_status_expiration_date=emoji_status_expiration_date, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_menu_button( - self, - chat_id: Optional[int] = None, - menu_button: Optional[MenuButton] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_menu_button( - chat_id=chat_id, - menu_button=menu_button, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_permissions( - self, - chat_id: Union[str, int], - permissions: ChatPermissions, - use_independent_chat_permissions: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_permissions( - chat_id=chat_id, - permissions=permissions, - use_independent_chat_permissions=use_independent_chat_permissions, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_photo( - self, - chat_id: Union[str, int], - photo: FileInput, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_photo( - chat_id=chat_id, - photo=photo, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_sticker_set( - self, - chat_id: Union[str, int], - sticker_set_name: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_sticker_set( - chat_id=chat_id, - sticker_set_name=sticker_set_name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_chat_title( - self, - chat_id: Union[str, int], - title: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_chat_title( - chat_id=chat_id, - title=title, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_game_score( - self, - user_id: int, - score: int, - chat_id: Optional[int] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - force: Optional[bool] = None, - disable_edit_message: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().set_game_score( - user_id=user_id, - score=score, - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - force=force, - disable_edit_message=disable_edit_message, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_commands( - self, - commands: Sequence[Union[BotCommand, tuple[str, str]]], - scope: Optional[BotCommandScope] = None, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_commands( - commands=commands, - scope=scope, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_default_administrator_rights( - self, - rights: Optional[ChatAdministratorRights] = None, - for_channels: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_default_administrator_rights( - rights=rights, - for_channels=for_channels, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_passport_data_errors( - self, - user_id: int, - errors: Sequence["PassportElementError"], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_passport_data_errors( - user_id=user_id, - errors=errors, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_position_in_set( - self, - sticker: Union[str, "Sticker"], - position: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_position_in_set( - sticker=sticker, - position=position, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_set_thumbnail( - self, - name: str, - user_id: int, - format: str, # pylint: disable=redefined-builtin - thumbnail: Optional[FileInput] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_set_thumbnail( - name=name, - user_id=user_id, - thumbnail=thumbnail, - format=format, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_webhook( - self, - url: str, - certificate: Optional[FileInput] = None, - max_connections: Optional[int] = None, - allowed_updates: Optional[Sequence[str]] = None, - ip_address: Optional[str] = None, - drop_pending_updates: Optional[bool] = None, - secret_token: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_webhook( - url=url, - certificate=certificate, - max_connections=max_connections, - allowed_updates=allowed_updates, - ip_address=ip_address, - drop_pending_updates=drop_pending_updates, - secret_token=secret_token, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def stop_message_live_location( - self, - chat_id: Optional[Union[str, int]] = None, - message_id: Optional[int] = None, - inline_message_id: Optional[str] = None, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Union[Message, bool]: - return await super().stop_message_live_location( - chat_id=chat_id, - message_id=message_id, - inline_message_id=inline_message_id, - reply_markup=reply_markup, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unban_chat_member( - self, - chat_id: Union[str, int], - user_id: int, - only_if_banned: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unban_chat_member( - chat_id=chat_id, - user_id=user_id, - only_if_banned=only_if_banned, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unban_chat_sender_chat( - self, - chat_id: Union[str, int], - sender_chat_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unban_chat_sender_chat( - chat_id=chat_id, - sender_chat_id=sender_chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unpin_all_chat_messages( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unpin_all_chat_messages( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unpin_chat_message( - self, - chat_id: Union[str, int], - message_id: Optional[int] = None, - business_connection_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unpin_chat_message( - chat_id=chat_id, - message_id=message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - business_connection_id=business_connection_id, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unpin_all_forum_topic_messages( - self, - chat_id: Union[str, int], - message_thread_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unpin_all_forum_topic_messages( - chat_id=chat_id, - message_thread_id=message_thread_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def unpin_all_general_forum_topic_messages( - self, - chat_id: Union[str, int], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().unpin_all_general_forum_topic_messages( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def upload_sticker_file( - self, - user_id: int, - sticker: FileInput, - sticker_format: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> File: - return await super().upload_sticker_file( - user_id=user_id, - sticker=sticker, - sticker_format=sticker_format, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_description( - self, - description: Optional[str] = None, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_description( - description=description, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_short_description( - self, - short_description: Optional[str] = None, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_short_description( - short_description=short_description, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_description( - self, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> BotDescription: - return await super().get_my_description( - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_short_description( - self, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> BotShortDescription: - return await super().get_my_short_description( - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_my_name( - self, - name: Optional[str] = None, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_my_name( - name=name, - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_my_name( - self, - language_code: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> BotName: - return await super().get_my_name( - language_code=language_code, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_custom_emoji_sticker_set_thumbnail( - self, - name: str, - custom_emoji_id: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_custom_emoji_sticker_set_thumbnail( - name=name, - custom_emoji_id=custom_emoji_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_set_title( - self, - name: str, - title: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_set_title( - name=name, - title=title, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def delete_sticker_set( - self, - name: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().delete_sticker_set( - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_emoji_list( - self, - sticker: Union[str, "Sticker"], - emoji_list: Sequence[str], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_emoji_list( - sticker=sticker, - emoji_list=emoji_list, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_keywords( - self, - sticker: Union[str, "Sticker"], - keywords: Optional[Sequence[str]] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_keywords( - sticker=sticker, - keywords=keywords, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_sticker_mask_position( - self, - sticker: Union[str, "Sticker"], - mask_position: Optional[MaskPosition] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_sticker_mask_position( - sticker=sticker, - mask_position=mask_position, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_user_chat_boosts( - self, - chat_id: Union[str, int], - user_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> UserChatBoosts: - return await super().get_user_chat_boosts( - chat_id=chat_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def set_message_reaction( - self, - chat_id: Union[str, int], - message_id: int, - reaction: Optional[Union[Sequence[Union[ReactionType, str]], ReactionType, str]] = None, - is_big: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().set_message_reaction( - chat_id=chat_id, - message_id=message_id, - reaction=reaction, - is_big=is_big, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_business_connection( - self, - business_connection_id: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> BusinessConnection: - return await super().get_business_connection( - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def replace_sticker_in_set( - self, - user_id: int, - name: str, - old_sticker: Union[str, "Sticker"], - sticker: "InputSticker", - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().replace_sticker_in_set( - user_id=user_id, - name=name, - old_sticker=old_sticker, - sticker=sticker, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def refund_star_payment( - self, - user_id: int, - telegram_payment_charge_id: str, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().refund_star_payment( - user_id=user_id, - telegram_payment_charge_id=telegram_payment_charge_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_star_transactions( - self, - offset: Optional[int] = None, - limit: Optional[int] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> StarTransactions: - return await super().get_star_transactions( - offset=offset, - limit=limit, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_user_star_subscription( - self, - user_id: int, - telegram_payment_charge_id: str, - is_canceled: bool, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().edit_user_star_subscription( - user_id=user_id, - telegram_payment_charge_id=telegram_payment_charge_id, - is_canceled=is_canceled, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def send_paid_media( - self, - chat_id: Union[str, int], - star_count: int, - media: Sequence["InputPaidMedia"], - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - show_caption_above_media: Optional[bool] = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - protect_content: ODVInput[bool] = DEFAULT_NONE, - reply_parameters: Optional["ReplyParameters"] = None, - reply_markup: Optional[ReplyMarkup] = None, - business_connection_id: Optional[str] = None, - payload: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Message: - return await super().send_paid_media( - chat_id=chat_id, - star_count=star_count, - media=media, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - show_caption_above_media=show_caption_above_media, - disable_notification=disable_notification, - protect_content=protect_content, - reply_parameters=reply_parameters, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - reply_to_message_id=reply_to_message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - business_connection_id=business_connection_id, - payload=payload, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def create_chat_subscription_invite_link( - self, - chat_id: Union[str, int], - subscription_period: int, - subscription_price: int, - name: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().create_chat_subscription_invite_link( - chat_id=chat_id, - subscription_period=subscription_period, - subscription_price=subscription_price, - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def edit_chat_subscription_invite_link( - self, - chat_id: Union[str, int], - invite_link: Union[str, "ChatInviteLink"], - name: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> ChatInviteLink: - return await super().edit_chat_subscription_invite_link( - chat_id=chat_id, - invite_link=invite_link, - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def get_available_gifts( - self, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> Gifts: - return await super().get_available_gifts( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def send_gift( - self, - user_id: int, - gift_id: Union[str, Gift], - text: Optional[str] = None, - text_parse_mode: ODVInput[str] = DEFAULT_NONE, - text_entities: Optional[Sequence["MessageEntity"]] = None, - pay_for_upgrade: Optional[bool] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().send_gift( - user_id=user_id, - gift_id=gift_id, - text=text, - text_parse_mode=text_parse_mode, - text_entities=text_entities, - pay_for_upgrade=pay_for_upgrade, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def verify_chat( - self, - chat_id: Union[int, str], - custom_description: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().verify_chat( - chat_id=chat_id, - custom_description=custom_description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def verify_user( - self, - user_id: int, - custom_description: Optional[str] = None, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().verify_user( - user_id=user_id, - custom_description=custom_description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def remove_chat_verification( - self, - chat_id: Union[int, str], - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().remove_chat_verification( - chat_id=chat_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - async def remove_user_verification( - self, - user_id: int, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: Optional[JSONDict] = None, - rate_limit_args: Optional[RLARGS] = None, - ) -> bool: - return await super().remove_user_verification( - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), - ) - - # updated camelCase aliases - getMe = get_me - sendMessage = send_message - deleteMessage = delete_message - deleteMessages = delete_messages - forwardMessage = forward_message - forwardMessages = forward_messages - sendPhoto = send_photo - sendAudio = send_audio - sendDocument = send_document - sendSticker = send_sticker - sendVideo = send_video - sendAnimation = send_animation - sendVoice = send_voice - sendVideoNote = send_video_note - sendMediaGroup = send_media_group - sendLocation = send_location - editMessageLiveLocation = edit_message_live_location - stopMessageLiveLocation = stop_message_live_location - sendVenue = send_venue - sendContact = send_contact - sendGame = send_game - sendChatAction = send_chat_action - answerInlineQuery = answer_inline_query - savePreparedInlineMessage = save_prepared_inline_message - getUserProfilePhotos = get_user_profile_photos - getFile = get_file - banChatMember = ban_chat_member - banChatSenderChat = ban_chat_sender_chat - unbanChatMember = unban_chat_member - unbanChatSenderChat = unban_chat_sender_chat - answerCallbackQuery = answer_callback_query - editMessageText = edit_message_text - editMessageCaption = edit_message_caption - editMessageMedia = edit_message_media - editMessageReplyMarkup = edit_message_reply_markup - getUpdates = get_updates - setWebhook = set_webhook - deleteWebhook = delete_webhook - leaveChat = leave_chat - getChat = get_chat - getChatAdministrators = get_chat_administrators - getChatMember = get_chat_member - setChatStickerSet = set_chat_sticker_set - deleteChatStickerSet = delete_chat_sticker_set - getChatMemberCount = get_chat_member_count - getWebhookInfo = get_webhook_info - setGameScore = set_game_score - getGameHighScores = get_game_high_scores - sendInvoice = send_invoice - answerShippingQuery = answer_shipping_query - answerPreCheckoutQuery = answer_pre_checkout_query - answerWebAppQuery = answer_web_app_query - restrictChatMember = restrict_chat_member - promoteChatMember = promote_chat_member - setChatPermissions = set_chat_permissions - setChatAdministratorCustomTitle = set_chat_administrator_custom_title - exportChatInviteLink = export_chat_invite_link - createChatInviteLink = create_chat_invite_link - editChatInviteLink = edit_chat_invite_link - revokeChatInviteLink = revoke_chat_invite_link - approveChatJoinRequest = approve_chat_join_request - declineChatJoinRequest = decline_chat_join_request - setChatPhoto = set_chat_photo - deleteChatPhoto = delete_chat_photo - setChatTitle = set_chat_title - setChatDescription = set_chat_description - setUserEmojiStatus = set_user_emoji_status - pinChatMessage = pin_chat_message - unpinChatMessage = unpin_chat_message - unpinAllChatMessages = unpin_all_chat_messages - getStickerSet = get_sticker_set - getCustomEmojiStickers = get_custom_emoji_stickers - uploadStickerFile = upload_sticker_file - createNewStickerSet = create_new_sticker_set - addStickerToSet = add_sticker_to_set - setStickerPositionInSet = set_sticker_position_in_set - deleteStickerFromSet = delete_sticker_from_set - setStickerSetThumbnail = set_sticker_set_thumbnail - setPassportDataErrors = set_passport_data_errors - sendPoll = send_poll - stopPoll = stop_poll - sendDice = send_dice - getMyCommands = get_my_commands - setMyCommands = set_my_commands - deleteMyCommands = delete_my_commands - logOut = log_out - copyMessage = copy_message - copyMessages = copy_messages - getChatMenuButton = get_chat_menu_button - setChatMenuButton = set_chat_menu_button - getMyDefaultAdministratorRights = get_my_default_administrator_rights - setMyDefaultAdministratorRights = set_my_default_administrator_rights - createInvoiceLink = create_invoice_link - getForumTopicIconStickers = get_forum_topic_icon_stickers - createForumTopic = create_forum_topic - editForumTopic = edit_forum_topic - closeForumTopic = close_forum_topic - reopenForumTopic = reopen_forum_topic - deleteForumTopic = delete_forum_topic - unpinAllForumTopicMessages = unpin_all_forum_topic_messages - editGeneralForumTopic = edit_general_forum_topic - closeGeneralForumTopic = close_general_forum_topic - reopenGeneralForumTopic = reopen_general_forum_topic - hideGeneralForumTopic = hide_general_forum_topic - unhideGeneralForumTopic = unhide_general_forum_topic - setMyDescription = set_my_description - getMyDescription = get_my_description - setMyShortDescription = set_my_short_description - getMyShortDescription = get_my_short_description - setCustomEmojiStickerSetThumbnail = set_custom_emoji_sticker_set_thumbnail - setStickerSetTitle = set_sticker_set_title - deleteStickerSet = delete_sticker_set - setStickerEmojiList = set_sticker_emoji_list - setStickerKeywords = set_sticker_keywords - setStickerMaskPosition = set_sticker_mask_position - setMyName = set_my_name - getMyName = get_my_name - unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages - getUserChatBoosts = get_user_chat_boosts - setMessageReaction = set_message_reaction - getBusinessConnection = get_business_connection - replaceStickerInSet = replace_sticker_in_set - refundStarPayment = refund_star_payment - getStarTransactions = get_star_transactions - editUserStarSubscription = edit_user_star_subscription - createChatSubscriptionInviteLink = create_chat_subscription_invite_link - editChatSubscriptionInviteLink = edit_chat_subscription_invite_link - sendPaidMedia = send_paid_media - getAvailableGifts = get_available_gifts - sendGift = send_gift - verifyChat = verify_chat - verifyUser = verify_user - removeChatVerification = remove_chat_verification - removeUserVerification = remove_user_verification diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__init__.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index fd201bf4c6c497bc7f3b328e53b3b1ebe6608446..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmZ3^%ge<81UIM5$^y}kK?DpiLK&agfQ;!3DGb33nv8xc8H$*I{LdiCUs3uQ`MIh3 zxrs%|`TAb@>G{U`i3J7vWvO{(`Z<|N`URCG8Tom}dWMGj#hE3kx&?{J*@@|?#rh?w zIjQMIiMjfz6(#!d8Hsr*IjKd(`tk9Zd6^~g@p=W7zc_4i^HWN5QtgUZfmVSWQ_K$} RJ}@&fGJary5k<^EF#z}fGnfDX diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/basehandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/basehandler.cpython-311.pyc deleted file mode 100755 index 8f3aee8c70f565509c16c63fd53f14f82ad2c153..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8010 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 PGhfJI|9!|{$;AHwBT_R; diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessconnectionhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessconnectionhandler.cpython-311.pyc deleted file mode 100755 index 01e33226bd109785274dcef06a390586bb3c852e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4313 zcmcgv%WoUU8K32w6e&ugWb5Gulh{_o)FvSrEmGESVoP!BqLl%gP5=h(a=AMcS6c2e zGfOEl1XKkKR0VwSAw`5DDTE$e1<4^OddQ)t{sW~80%aE{V4&@xHx_PzBBy>c`ygp6 zK~W$bE{F5@W@hL6{k{i(mC2+Kls~=q^UX*Wp}+8sUlLy9>93*jKGIMHX_6K)q-LlR zYKALeiTA@sq#3P5MLS}|n(<0pw4+9%nXDw6sY*)pW5!rBT}g{}+{iS?E91>9is8h|yDjpjLi3UnyVKGXn?NhQ_Qv(AcfMbi%eU^l0pj7?t7Rv)_9mBw z>9K1HBi_a^n`tSO5m{|0wybN;xZ72Duz*0)Ga4;tE_rA6F+IM z^YoX{_z56GP(=cCLYhtu2jhZ4&%<;7phxnL=hTM zJ+>{}5LnMW#^m;FSS%58o@*LP~5@DBx{E z8Anyqh*m1$mF2>+J9m|Cu#%ACN2(qIc&TI)+ALL7i&||Ph=c2GQ?RC*FX1xqDG>E1 zaNVN7G@ze*8Ct+^>4t%8B-q|Rf@pZBK}=j~61xG1G>Ez-w*|$ju$p0w@Z;fF4R%y) zteDuH#;jqr4GlKMEo!O2XAr6Fj+`+14nCF}TZc|b!xmV|J;}?bPnkpPy5AL<( z9$3Pzf-eYbBJbKI?C%J8*f5X}4(GfEnuGGJ+GeS$n|2lN0c?ih8r<81@w*qW<=GkN z^SW-peHo_Yoi<@M7_5Z>32O&irt$3MEJi?ky4t`B1z4!n6!y(pMAhp$sDr--zOlB% z@*e*DlD^IPFUM?p;>+>zulnVv*y!*ao&J8<3uB%E`Za- z+ltX9*s6=MfR-*%0&KVrfHcaEqT8G@1lSsINH;gcViVx>*^6~^WU|^-4hvXm^u#^58*eU#+T(FCVAX0_a z^AbG`3-U21%GxbLorEmwrf$nJ<%trV`R)d4B15_VN5mcYX!B*#r1Ig?*3{ zbK`{*bG?!pAP18HBYp>+Q9kTR_K@T#=Jdv%v>D9OYkO!jK$#_>$M+S5K_+w?cr%dR z3~=7$V2CojejCv*TN58z6P&UQjL|~Cn()29p5PKr4APKV@*r-3e;s57FEc;6@l9*k zEsmxnoJL;kUn&WHm8w29yyS-mGS|aG+=WofQ#vHQxJ+wA2|zjvjN zq|BM)bDtDNqj!4Yq20^QbhG(xw$RNke_H;{4?Edac-*PnTsL>In_KDTzWtf~+aGmu z>z(v^FFSqEreA|Y^V8fnaQ7+8;7euqUk0?(viwe4F}#_$ENhku!{85?Vc85k38x^< z@QSOD@_e3-^NRDCaa&djqSuqR;x8yAt60s)@-1P-}SgMWOU3#L5uIA=!% z-2=V6Nap_l`KyZ9!o!L)cape!xZsJPjUWq$_9NuppBvHViOVhruh3Va%SpicQ1!!- zB=r}O^t#kRul3Nm&PmS`w9pxSdgvRS(Wi$lc20VFsMHyKdguq8lb+`#-Gxu0>HW73 r%0Iq)|L%UMAA3!j>7(bXqp{=bpRRs3b$qjnFaLuJ{PP4Up^^Up`)ax* diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessmessagesdeletedhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/businessmessagesdeletedhandler.cpython-311.pyc deleted file mode 100755 index 451c32d3e527851f3f53eb527268fc9cbb33cbfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4360 zcmcgvTWlLy89w8?9Xn3qrp=|41HHw&U7I!wTUo0>nzYar+m%{(S8`R2$1}(Aq;v6} zGfp;D9)eVfAoZaSi?%`wig+kNyALa#`oIH1yyGHEn30ew0S~+x6(qDz{O8Oib{h&p zT8?LapUZ!4|Ns4$`B^TPK~Vni;g8n8mPhDMyb+X?UwQTmsCzgYaN4N)wUc(w-|O>1Yhbf-6D*=4X?6B*eWrIL$vQGmSzx&RYPH{^jE%I zG2*7)X*;@YDTbS@Znep~3N1=*;$~Y@90IlM>g6lTH@{nztJiN{2KMNUm8zRqeV6mX z@Yp4V5r1JA&9xQEh^)30N7glW+-r6ip_XD2K79qI=luyQieWSq^^P04URC|;iNCDh zc=l7Md>_<9P)!0AMKq}v)grZ+7S*C8-i&H7Ev_XfHKD26EBy!!r};x z$R9g4ZV82CFqDeoIJ8pNJWb&${I5~P3{{CuUzhkz#~&+sIx6{dV18Bm{j-_&-)Qc5d z1(1cT!2oXB6yOJ#^zKDV_&wb)aD#-)2U`#gZ?=eqD<*MTut|%kcjS(MTpeaJtN~uB z3EOJ0qT*o1!rm}uExTiAuqbX*TLqy2OJi$fhtV?xAj3>wvlOR8Nu}alou4Ks3fr<& z*tQwoYr)&Ff;};x6DCGJa4I-haRqD+I*Q@uKI}nwc4NI#*Da@xxABT?7(|Hf)wn&)P)Qn>vVt z9|K=qU0_9D|NN4H4F-o}4n6d6y#I?lTyT!j(=`lRy%QX*VcSN1L_Vtl92mz9xHt|p z0^$O7T6jY-It1HI(HFwf14^hHE&~9KvZ?6c3ZV*U4Kbu!Yhtnm>I~3}b!%j@kJZrn zfVH&TZX3F)aI+}+a13Bv!mFgIbPP|Kp5m*tLjs%R=ivoxlM$jA%m%ZpZ0dLPN*#cu zb|@v5x>XlvSO({yH#!da!b~;1>Wi8HeE#q9f8P54fASYMf{2q2q7id5a)3T|&5bc) zH1D2$x!=A8;p!Z|UcK$60${nxAiAZ3)!ev{nhHKXEHS9@nEmW0Kz=BFgq$$mBlHOR zK7rROdqX2ZA41#GcI;E>Q3N>Q^@@a?p*^-Eqj|(OlEW;)Ne6RarRWQM;VK$}@D;gM zl;|;-P)xXS)@c*!res;SbVrscPod}}Cu5vU2{u~b^&^~2b8?guz5<9_7WsuNvjnsS z#&@4D9o@He>}nb14Vr zRt9q`%YI;ClJ}FpPtE); zHS=(0f4ZBRd6FvkQsr){{Fm7?dz(*Y%e~q1ZtVW}ALkbKXP(Sm=*?Y#W_}lb&tM(o zCcNdyY#{L8Z%ZZK|)`wTatYr;~B5zl^3z!2jK#h4!F zY}w&V=GiY4Hem7(B(7W$?1H_fZ1%tSrCZQ4D`1Da)FzLN_=GX4nn`_rlRg zbDVH#Ql9zKaZWh2DaV}~g+$7YLSjPsN1GetY7zGBCOiex)4V_Ddmfb-hAe|en}=S; zee1V`bm;_C1;Kpaw?M$$gWn)BA5RSsCza@AV(02$0-b%e56_8L24k7{;s62ZkH0a9 z!vE8$uk4-KKeqX(C%*^tSJ_Lp3F?dr}w@wK=8M(iNF7X2wjL9UMo)1B3#f-I9qLiy(dj>xo#@3 z77xD1gJwyFJl|mOIU&*(kyHuoxYN(Gz?y^!-FO=LYRJHoqR>m18t`rCyJX7ak$ZBK z(c93^m}LH~$d4)l4v#hN>|yNQ<^m@IHUcbMwLeGR{kbK5o_f>6;1azEO%4J!05XV5 zk~BDjq{~tlt@hEW?qSbUG~XS4`snN3(Wj4I>mK&>QKdWj^wHbh!=4v8y@^lb*`4=x rtKYkQ@Agh)kocxFJwPv#y<49heO!3l`0UHQ)60M341Yg_OGxBjK2yu} diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/callbackqueryhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/callbackqueryhandler.cpython-311.pyc deleted file mode 100755 index 877a0b27a2c98505a24f76dc822227fb30b7a64f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9874 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 Mob>lsOqJI77e7vc4*&oF diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatmemberhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/chatmemberhandler.cpython-311.pyc deleted file mode 100755 index 9690b24c531cd788a7de8549227b4e8dd59e9bdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5455 zcmd5=-ESLN6~E)JICc`}vrW3I_O@Y5opkN(b_=ZORF+Dj0zI$3!HQ3!=5CI5JHIY z`1*dF`*qIm{O-B_e)(GlvBn~eYi3#@&m?5Jy*$zeA*bT zk5$I%HU5G~7wS&EIZiCTOnXeLkMAPrw%dQuy@ zPV&R|PnB16o7OF@X)vlP)`h8k zkwPXz;rUSErfx2mL_t)nFq7KMaiEr#z*tJ1vs$UTWLWC$Do$ClmTr}*i;7{h>Pfn4 zHL0qYrsYu1j8$rxRM9l-tTt`Os)qwBj>Gk(ro&)yFo-}}sp|L(FR*(~A+Y`efE3Er z0=>={)g7B^mTJ?Q#R0|~YRsDDum93LrQR@@-P=G(F;`1fR3G)QO)tRO&N5%HfU58` zv1B>ts-7AO1$u{Z8&R%lOe>Y>sndnGyteavxo>#YM<_i}au~0ds;b4UCTNS%TGLd~ zQL6b8ErWZ7qCtb$frH-YnT;3dhq__VB^GK4O@RHFM(?5}N_FO}z$7b7y)ApjtwL|m z2*c@NTFtYyV)}-q_KMXsG#HdNxTP}N29c%J$PCdn1Ztxzf|CMoV7C$tM)VDtkB)}A;SA<6=^e#rGHTTX9fkS=1vTv^XknGY ziooI;W%pFpaC`+aYB!jwD+VmZ#_o~L?GG)>L<1{mAK!_pg|Hi9LiRu*J3w1DSXZE2 zHyyyZE zr&%e`i>#(J4RB0!<$cxAQ?6i+K%q;PWkfZ4F#xiSh=*f|3o!gkfOrs(C;{NE+*Nc3 z!OnmwLi8gQ;bCV2G6TN@28nd`y)4{2lF|7_!_ZX$n1b&}fdlT^zd%ZvHyI!*GAyu) z%@`1+1%y(%tKZgvm@HFma?VV3wHgWwCF@$CBt#uuqYD=BfMAr5duY5Ff#afX01ept z@H@~Y?_*!YqK7OUG=%ff%NI}BdBC!<+Orjk?d8HZPZdu4To{sgk8ne`{jV@$R3~5L zli-O#Py&Ypl0i)eul;}anQ&u!{Q-9KpL@aX)8l{V1s)_Igc}UPIoloU;|q^UKl=wf z?nsm+c?`lbH`_;xpJABm=5{gSRX1TXqjvw$0wDHEf2jH~gpDWZwen3j9RQGz;}A)q zUw6RwDK!a|!IOXt2FNcTK=Kpm6XJxyH6c%+?iqZ&XREIzs3T-eT8sZ$dIGC|hC2|C zMAl+!L=MZ&K+pp6iD(E9a<~TZXapj?*wwtm4?#Jfbdz?o!MK~2W!=;rSr+@@S!m>A zD3RjRn8#SsYr=l~6-dAWvIwYT*-k+j-I%U_t`=9UIxE%{u3E+StYzzTQE4=acbIvn zXy{AD#;UVonWqb{sB>rxZ94~+i&}O~a{45r*0W=pbRFz^ zE0nMYp%h-D{C09Hv>SgF+Cx8L%S<{`K@Fm@x6UZeu9IDI;qG?J<>UANv=9008%{#(1BVA3`Tc>(m+c?|2>h`B z7>owb2usg|aMbO-0eC?Q9(>+u2gfR$ei%$&HdPBk-R0=j1qZt(!pOex94o!t^llkr3Tst?{O3(45u;TnQGMA~;nJl{*S@!;Lfc%gwe;I&qIwn?9-&m3`3TId5=J?jZFUyVJtq1{V<{Mwc&plWUbz(8=Fg}y9AT(O7XGO z`sHq#9Q)Gx)s0J=vyb0vC1&B>PRw=^a_8`o^>1xVZPk1L^cHzppRI2eFhPLJF z#BIzoCz{wj77AdD9v)4FCAbLshZ4s>^W52}pf{l(z{~g_6s{M~R(EDUNpD_(F9A0J zG6cr2h_`u*%Y6`#BBmyK;~W55ZM5C}_Pw_rk*ElNWSAtb4Z%o555boct+S$oZWZ0Fu3 z*xE?06sfMn2Rp%Ex@{pRiP`*1b|Bq^eT;Z7bTU%BP+)_u*Y*Q$PwB(PNM%IS)B0{>v@&XpRmLO|AuOe39!P|I0blQ_jI%gTz|L8Hk16*T*(|f0y7Q)DYC7Xo)fL+={1sQ4$w%Dy4-`jTaFg#Uj>EW_Pq+i+YwwHmG$ZQ!&&o&x*T~%;b z)jziQ8SopA{{oetfNB{5m6A$ClPXayQi-v+7Oh3Jm=@O(EWwg2#nQc^)RHX2vYVpS zQXuXDHpq6d!Oh-UWV60mtEE;+P14dI4OE7-3>((6Vs4fV??4{|mBuO~pj3bWOKOAK zE^P>Q%d*`&?WSdc|BN;a^F~+6ZK*N_svdFo?x<1a^CTgC+NF*~7lgWLndxkvD+X-} z^&mJDCxA+Z!czjp^HSCE2@9Sc3#tH+To(wExqwi$kP%a^D%`A_^Ci*1HLfl&liJL2 zpqG{!3T(((tyG=UE%jy<*(q6bi>2xtif*&&F}h?msj8T!Q7)9EH(Z(^L_G)qIJT!Ky;iU_dPIpb>iV<^_7SuIqG;g-1a7 z;5??$4^T`cgEiGPl&X zLq89JOsHL-Hx;MJS*hfy4!H>)#a=R1*tQm)>xjosiFzP7CV&D$Ezw{_U&{IZ)lfE^ z!9FIvrRYsYt(x#cp}asqO}hzFSfaoYs6(Udw#pigFF;1^22<;b4y@QXz3*__>)kSM zF>VVF;iDh$8JtZZ4>T%ZH)mNopw9Ar7%1~xAZr_y0uGZ4exG^XUZ1qS_dcK0^ zkL0>0oJ(jqv|gj3+4M28X+oZ%q5*-1dJR{^Qs_`rG_m>|gw(p(4`apdTXZXUF_BL8V^kPiaG^T;7PD~X}i`CDDKJS0!qryWxX(j)aZESUW|3BLZPZWZ>>cbaZ zcaXdkXdhxRq(EfZg4iwL@af=F<}u@P{J4TR#s^GrJLL){A-75TOwPD5o9VUX=bzle zcWCcJhIEY1mT$PJz?Hgjp)@`Q>5m%olOg=UI%bHEe*?uQ(mmpY*(M zLjI8>>A{~S?W4&Uk+H!lUoKz8breTZPYKSdq91FQ~f-FS@Cra$zt8%`c$Q51E$a^iXb5 z_A4!EF&yP5TVyf3obdb(KFDy|9UT%}3pUf%>$r>p1%P&x9_nNd zbxAxuxqi5F^t`BT?Am>&)g`fk$*(7${rQ_~<<&MV?Vw7PB#j*Zh}lq-gRK^s>7d0Cc)-KitlE@VuQ=!a=s^LdLQnp$Ea|cqSja3 z2u|qn3)}*B^O5DI zNH4;B14MoAqVDAf8l=xXxfHbU$`0ra0r2f|4MY|`Gx?Z@3jC*pBVTUP&qxBNc@#$u zV(}6d$Djz^rH_t%ss;BK)sgX%=KT*K`?^>@^%Sh^ILpLMPC>Ckx`3RaJ7>Bil0N?R z{sX^^ueBcTKh@cPYW1Cs125e-S1;VTv3{Um0=dHR;xo;>wx^}ut;Aef|%jQ?*-=6;J zdgr@ubqa5b&aK4@x%lx%!=v3e{DRdE@98G7mLlV4rEVIl8M0^c{<*b7>(S4SwkMBu z#*cTi*qQjJxKz@Y+tTr*WdVZ`m2%kOC5UVZ-VIWJCF*2{u{GQ BKtlik diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/commandhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/commandhandler.cpython-311.pyc deleted file mode 100755 index 7e247077dd90d6066a3f6f6ab8b19247d6e2e56f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11911 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/conversationhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/conversationhandler.cpython-311.pyc deleted file mode 100755 index 7abc6a0c0206132ce1832ce2704f09bbaff9c719..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45687 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/inlinequeryhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/inlinequeryhandler.cpython-311.pyc deleted file mode 100755 index 2485fe07d7a0830965d1d7e2174e3187781ff6e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6577 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 JUs6@b^WQQqJSqSH diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagehandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagehandler.cpython-311.pyc deleted file mode 100755 index ac530afe580921a09f2bdb8e7020c0a1d1480f52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5411 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 Qdg&ix(m%gosu10O0cB(Ie*gdg diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagereactionhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/messagereactionhandler.cpython-311.pyc deleted file mode 100755 index bc68c737a66658a5748acebe8052cfde7867b32f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8179 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/pollhandler.cpython-311.pyc deleted file mode 100755 index 280057dee4bf47a54c2dd4ffdf46746ea6550068..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2720 zcmb_e&yN&E6t14>of#Go0TV?esc2l806hT`4lV8i>n}W@fias*V!CU(Yi645>1wO0 zcNxNggMWYr5{M@*B8HfF@E`C$SP~A{SG{l>vwGp=d;M!?bm3%gZ*^67RlWDV?|rZ4 zhyD8(30%M3`R@9!(EA++<<%-W+b(qO5})*lZ}_#)7}t6=1N-%`J~n%1);Gh2aiiB5 zH+xNk)W|2qU-*Xj4Q}!pZ}8@zex%%&Jg5`$2>$b{*Yca!NV|3OM0XS@Iu?Esa_Wgl zvmjDbk2w88gyE+w@V3QpJ@)gy_cBc#iVvEt*@?j)7sUpS6Im& zW--`ag3evSNzZ_&YQE8{`?a3w*ZG2P^2Wdf-_2grZ-8ITbnlFL_U-~9bFNS==qU4z zc6rE$l8tGSIfcG6T}DFLB8AIlT1(rFAtHKS7YnRB3Jc#ZyVhbhbB)O;h=z7Hz@=*= z9#O@$hPTv?8Ca5hV7vWLcQ6w~#Je*JwQRe%&*h`ca z<7#7cDd;DfgU7H*hOq5c&hZ=CT4iC_XWsfM&;n!EqSrX5fmYNPo}vRGfj9|oqJb#< z|L6uA$01ic0oW{>*e;?;FM(6%c`+l4yD#*zn@4_84rf+*g=u=+)?AKl*Ar4C00O6j zB=U41BDZbRF62oywfvAdrZKH@iljx?0x;j_Rq%)`uH!!4M1buv*CQ}8;@-NG6Y0Wg z2$Z9FFze^MvZ&yhs*y-SA2y}26dqR!rt~Ls7Uq2@(WELEMocG?+jbs0dQ)CZO(GA> z4yw40=l<9<&zF-~ZUG%OEq5&VY0vM5*hmg`BD%rCgi|rdbXDO603|8`6ebir0wR6N zZ+JY`1%RBYn0o;W!4-we=YrckV??yUrDDiWAsEQ)GPW#dfzd2s`$B|}uOh~|ECez? zEU{Kd3X}ku`TNosauzBJXbBi$n=H`C2ZtQ32tpBHVTk~|GBqG~=N1=c4fj#IhT=J7HF7*M1^frdox%MY!_Jb5-EA)O-cz=lH8F` z#n%5KgeunmQt@H}Di=0UMKXy1G|FhU1!B6%CRQQ;A4%HC(=~16ym_^mT8yO_kAUrN zR*JQ;^X-O6Qn}6(*M!TvOP83wNfSlMV z74NCCSeH@HQaN9vklZ|2$mxIA&s?l7y;am_$a(H*tXY>MPe4T(7HbRSaI>qKT4$;t zzMN6Zj=tMwx)>-pDK(2cE)kE^L`9`09w%@Vnu>=5iRZjR94USNRc9o|yfbFf6P?e* zP@L_sIPPrlXrmJb{Z2g5BN3goPM_{5P|v9tDnA=?)hWf$0o`<*qNb`28Y&BHJW2P> z7SEe+V8JgcfHnK&1N7(}Xl|3gUn8%+d2i|arN;-_PY$%V4y^p-|9tM3_a9p;Ppp-# z*2*?aBUjq3wBJBv1x?vd8C1RY}BB!SfV!X9Qj?UgsiM=&{KP9KOcDtvIlg0&O eN_KC*J#lYv-+OrGo_KP|`ZJsK*9)d*aQy?@5FTd$ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/precheckoutqueryhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/precheckoutqueryhandler.cpython-311.pyc deleted file mode 100755 index 19e61bb564b8d8929d7f6ae175e9bf0adc9d7d2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4497 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 D9I<1} diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/shippingqueryhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/shippingqueryhandler.cpython-311.pyc deleted file mode 100755 index 763892a481ac2ddc09fc6cd335ab9f5d11355255..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2749 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 A-v9sr diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringregexhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/stringregexhandler.cpython-311.pyc deleted file mode 100755 index 8e57cd946e576f604c73541fecf9b56e05fd1d30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5296 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 H3cLLi!q?lJ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/typehandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/__pycache__/typehandler.cpython-311.pyc deleted file mode 100755 index 6303fbede59f851341d4baae9264c2b5c68cb827..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4198 zcmc&%-HRL76~8n3{@gFGvw^tWdP}m3*CRV_^DvaQt{vy2B?Vh+gNhlAX0BG_9nGls zj%>@-!xjwPz&`k)#Y^eKJ`~p>{R8@z=e#M!knKRgkf*$`f@8v?J-x z{l4e?&hMOi^v6o2NZ|SFZ+>^{l|@3nz()M!qsp^CL**ecNt2k8Dce#{Zpyt>GbLd= zWv6?YW+teo?QAdC%mwv~o$nQzg`l3bi@j2_)GIg35|If@nYl+2As@jne43S@H~(C3 zl`XL9%kd=AT$IV%#4Ow=W|0+Gm6ceflbVh{O2MA+i}qYHOV>!PeD6%7YYEzO&4JCR z;X0mfIf8m!MjOLEdq;Onn{jH`x)92jxV9$y`JeSY%XM_y&*7x&IIwbGAu5$^=6Qr4|=KE*SX%~tfRKtwrlLPa9`DJ-%?vw zbX&02CLOv1YUqyRdXzJJNL`2OriqKg(~^yK&*N5mfTG|gfd$o;$85F@XDIBhr^Mi2 z0<%NArO<1PQOgt5bPYi}E(c<8=y5u3B>zReEvCYwW^_Y^wTuHDl0%@oRa0pLSakd# zq7wtL3?`lX{lJOxhks$XEgx>*X7%Mcrj3TxZZy#Z&c8gdGyi631I9Rpwj@Wbc-_b1(dBDK+5@MilBk&FwE%6h}Nnk-8A_C5N_r-qSwu}HvCGw$|n@X&7 z7#jjS8+^b3?73|f1ws>p$m6OiRqt3kmf8Zg7z56kV+>p2?2AdH`TsS zf#MkAMRfa`==P1|i?Ij7B_{+noQd;Om0lzt9Q~hD?)fP8zoT5p6}bPiA)J01J@ty8 z7R>J4TWdfga`~TcH8v?E37hn4<0fB#yWh{pmgQA!W&%`>S?EM6(A}?Y*1K+x z)q6TO-1>X&wtJzj_xttR%(-2+t#-XX^t!HdK{MwL-iaB|m00MXz=-%R6#v{M|EQ8e^@H4g?z8;bU-D}QYmZmQ`L$2; z^(XoIIA1?ne{C`t{n)`6(Q% zL@s17+txI2$dk}3(9M4ofWRxb4vTdh_!tUccl?>i>zVw7VDX+rmezOQos`MisiSYb zJ}DJ4XD0-Tqw2;a1@EWTmk#9p-XwzqS+a8a@bsba_>IFePnMNQ4mX6rn>}NJztzGXKIIUP6)gno5AbfC<4d>joz;<^KXMfeimFD$i>lzIJ%ktN*oIm z4RT*wD3BLosuSdMA?mBoPr*1L0-XKR$rywZB?%=;8`8NblyLYXMEsZMCx&N*8wCao zOo>(uEsGJIqagzMKO~_pNY=0N-w$c?1AZ2oXh8896qA%BNt0KJ^v0N+e@ebHKJNRJ zd~ZDeJt7<9`R@@?$MfG8d%_7%Gv(bIdyQY+ynl07KALTS*(*yAmiOP;EljdMlxh?5 cV)5Y2LHlt1kRR+kS$_R*IN|Td%nB6$7cEMudjJ3c diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/basehandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/basehandler.py deleted file mode 100755 index b6353f2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/basehandler.py +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the base class for handlers as used by the Application.""" -from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union - -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import DVType -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") -UT = TypeVar("UT") - - -class BaseHandler(Generic[UT, CCT, RT], ABC): - """The base class for all update handlers. Create custom handlers by inheriting from it. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - This class is a :class:`~typing.Generic` class and accepts three type variables: - - 1. The type of the updates that this handler will handle. Must coincide with the type of the - first argument of :paramref:`callback`. :meth:`check_update` must only accept - updates of this type. - 2. The type of the second argument of :paramref:`callback`. Must coincide with the type of the - parameters :paramref:`handle_update.context` and - :paramref:`collect_additional_context.context` as well as the second argument of - :paramref:`callback`. Must be either :class:`~telegram.ext.CallbackContext` or a subclass - of that class. - - .. tip:: - For this type variable, one should usually provide a :class:`~typing.TypeVar` that is - also used for the mentioned method arguments. That way, a type checker can check whether - this handler fits the definition of the :class:`~Application`. - 3. The return type of the :paramref:`callback` function accepted by this handler. - - .. seealso:: :wiki:`Types of Handlers ` - - .. versionchanged:: 20.0 - - * The attribute ``run_async`` is now :paramref:`block`. - * This class was previously named ``Handler``. - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way. - - """ - - __slots__ = ( - "block", - "callback", - ) - - def __init__( - self: "BaseHandler[UT, CCT, RT]", - callback: HandlerCallback[UT, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - ): - self.callback: HandlerCallback[UT, CCT, RT] = callback - self.block: DVType[bool] = block - - def __repr__(self) -> str: - """Give a string representation of the handler in the form ``ClassName[callback=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - try: - callback_name = self.callback.__qualname__ - except AttributeError: - callback_name = repr(self.callback) - return build_repr_with_selected_attrs(self, callback=callback_name) - - @abstractmethod - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """ - This method is called to determine if an update should be handled by - this handler instance. It should always be overridden. - - Note: - Custom updates types can be handled by the application. Therefore, an implementation of - this method should always check the type of :paramref:`update`. - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update to be tested. - - Returns: - Either :obj:`None` or :obj:`False` if the update should not be handled. Otherwise an - object that will be passed to :meth:`handle_update` and - :meth:`collect_additional_context` when the update gets handled. - - """ - - async def handle_update( - self, - update: UT, - application: "Application[Any, CCT, Any, Any, Any, Any]", - check_result: object, - context: CCT, - ) -> RT: - """ - This method is called if it was determined that an update should indeed - be handled by this instance. Calls :attr:`callback` along with its respectful - arguments. To work with the :class:`telegram.ext.ConversationHandler`, this method - returns the value returned from :attr:`callback`. - Note that it can be overridden if needed by the subclassing handler. - - Args: - update (:obj:`str` | :class:`telegram.Update`): The update to be handled. - application (:class:`telegram.ext.Application`): The calling application. - check_result (:class:`object`): The result from :meth:`check_update`. - context (:class:`telegram.ext.CallbackContext`): The context as provided by - the application. - - """ - self.collect_additional_context(context, update, application, check_result) - return await self.callback(update, context) - - def collect_additional_context( - self, - context: CCT, - update: UT, - application: "Application[Any, CCT, Any, Any, Any, Any]", - check_result: Any, - ) -> None: - """Prepares additional arguments for the context. Override if needed. - - Args: - context (:class:`telegram.ext.CallbackContext`): The context object. - update (:class:`telegram.Update`): The update to gather chat/user id from. - application (:class:`telegram.ext.Application`): The calling application. - check_result: The result (return value) from :meth:`check_update`. - - """ diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessconnectionhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessconnectionhandler.py deleted file mode 100755 index 975bb47..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessconnectionhandler.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the BusinessConnectionHandler class.""" -from typing import Optional, TypeVar - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - - -class BusinessConnectionHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram - :attr:`Business Connections `. - - .. versionadded:: 21.1 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only - those which are from the specified user ID(s). - - username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only - those which are from the specified username(s). - - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - """ - - __slots__ = ( - "_user_ids", - "_usernames", - ) - - def __init__( - self: "BusinessConnectionHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - user_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - self._user_ids = parse_chat_id(user_id) - self._usernames = parse_username(username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.business_connection: - if not self._user_ids and not self._usernames: - return True - if update.business_connection.user.id in self._user_ids: - return True - return update.business_connection.user.username in self._usernames - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessmessagesdeletedhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessmessagesdeletedhandler.py deleted file mode 100755 index c2df450..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/businessmessagesdeletedhandler.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the BusinessMessagesDeletedHandler class.""" -from typing import Optional, TypeVar - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - - -class BusinessMessagesDeletedHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle - :attr:`deleted Telegram Business messages `. - - .. versionadded:: 21.1 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only - those which are from the specified chat ID(s). - - username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only - those which are from the specified username(s). - - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - """ - - __slots__ = ( - "_chat_ids", - "_usernames", - ) - - def __init__( - self: "BusinessMessagesDeletedHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - self._chat_ids = parse_chat_id(chat_id) - self._usernames = parse_username(username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.deleted_business_messages: - if not self._chat_ids and not self._usernames: - return True - if update.deleted_business_messages.chat.id in self._chat_ids: - return True - return update.deleted_business_messages.chat.username in self._usernames - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/callbackqueryhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/callbackqueryhandler.py deleted file mode 100755 index b09f824..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/callbackqueryhandler.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the CallbackQueryHandler class.""" -import asyncio -import re -from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union, cast - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class CallbackQueryHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram - :attr:`callback queries `. Optionally based on a regex. - - Read the documentation of the :mod:`re` module for more information. - - Note: - * If your bot allows arbitrary objects as - :paramref:`~telegram.InlineKeyboardButton.callback_data`, it may happen that the - original :attr:`~telegram.InlineKeyboardButton.callback_data` for the incoming - :class:`telegram.CallbackQuery` can not be found. This is the case when either a - malicious client tempered with the :attr:`telegram.CallbackQuery.data` or the data was - simply dropped from cache or not persisted. In these - cases, an instance of :class:`telegram.ext.InvalidCallbackData` will be set as - :attr:`telegram.CallbackQuery.data`. - - .. versionadded:: 13.6 - - * If neither :paramref:`pattern` nor :paramref:`game_pattern` is set, `any` - ``CallbackQuery`` will be handled. If only :paramref:`pattern` is set, queries with - :attr:`~telegram.CallbackQuery.game_short_name` will `not` be considered and vice versa. - If both patterns are set, queries with either :attr: - `~telegram.CallbackQuery.game_short_name` or :attr:`~telegram.CallbackQuery.data` - matching the defined pattern will be handled - - .. versionadded:: 21.5 - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pattern (:obj:`str` | :func:`re.Pattern ` | :obj:`callable` | :obj:`type`, \ - optional): - Pattern to test :attr:`telegram.CallbackQuery.data` against. If a string or a regex - pattern is passed, :func:`re.match` is used on :attr:`telegram.CallbackQuery.data` to - determine if an update should be handled by this handler. If your bot allows arbitrary - objects as :paramref:`~telegram.InlineKeyboardButton.callback_data`, non-strings will - be accepted. To filter arbitrary objects you may pass: - - - a callable, accepting exactly one argument, namely the - :attr:`telegram.CallbackQuery.data`. It must return :obj:`True` or - :obj:`False`/:obj:`None` to indicate, whether the update should be handled. - - a :obj:`type`. If :attr:`telegram.CallbackQuery.data` is an instance of that type - (or a subclass), the update will be handled. - - If :attr:`telegram.CallbackQuery.data` is :obj:`None`, the - :class:`telegram.CallbackQuery` update will not be handled. - - .. seealso:: :wiki:`Arbitrary callback_data ` - - .. versionchanged:: 13.6 - Added support for arbitrary callback data. - game_pattern (:obj:`str` | :func:`re.Pattern ` | optional) - Pattern to test :attr:`telegram.CallbackQuery.game_short_name` against. If a string or - a regex pattern is passed, :func:`re.match` is used on - :attr:`telegram.CallbackQuery.game_short_name` to determine if an update should be - handled by this handler. - - .. versionadded:: 21.5 - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - pattern (:func:`re.Pattern ` | :obj:`callable` | :obj:`type`): Optional. - Regex pattern, callback or type to test :attr:`telegram.CallbackQuery.data` against. - - .. versionchanged:: 13.6 - Added support for arbitrary callback data. - game_pattern (:func:`re.Pattern `): Optional. - Regex pattern to test :attr:`telegram.CallbackQuery.game_short_name` - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("game_pattern", "pattern") - - def __init__( - self: "CallbackQueryHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - pattern: Optional[ - Union[str, Pattern[str], type, Callable[[object], Optional[bool]]] - ] = None, - game_pattern: Optional[Union[str, Pattern[str]]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - if callable(pattern) and asyncio.iscoroutinefunction(pattern): - raise TypeError( - "The `pattern` must not be a coroutine function! Use an ordinary function instead." - ) - if isinstance(pattern, str): - pattern = re.compile(pattern) - - if isinstance(game_pattern, str): - game_pattern = re.compile(game_pattern) - self.pattern: Optional[ - Union[str, Pattern[str], type, Callable[[object], Optional[bool]]] - ] = pattern - self.game_pattern: Optional[Union[str, Pattern[str]]] = game_pattern - - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - # pylint: disable=too-many-return-statements - if not (isinstance(update, Update) and update.callback_query): - return None - - callback_data = update.callback_query.data - game_short_name = update.callback_query.game_short_name - - if not any([self.pattern, self.game_pattern]): - return True - - # we check for .data or .game_short_name from update to filter based on whats coming - # this gives xor-like behavior - if callback_data: - if not self.pattern: - return False - if isinstance(self.pattern, type): - return isinstance(callback_data, self.pattern) - if callable(self.pattern): - return self.pattern(callback_data) - if not isinstance(callback_data, str): - return False - if match := re.match(self.pattern, callback_data): - return match - - elif game_short_name: - if not self.game_pattern: - return False - if match := re.match(self.game_pattern, game_short_name): - return match - else: - return True - return False - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Union[bool, Match[str]], - ) -> None: - """Add the result of ``re.match(pattern, update.callback_query.data)`` to - :attr:`CallbackContext.matches` as list with one element. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatboosthandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatboosthandler.py deleted file mode 100755 index 2fce8c4..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatboosthandler.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ChatBoostHandler class.""" - -from typing import Final, Optional - -from telegram import Update -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, RT, HandlerCallback - - -class ChatBoostHandler(BaseHandler[Update, CCT, RT]): - """ - Handler class to handle Telegram updates that contain a chat boost. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - .. versionadded:: 20.8 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - chat_boost_types (:obj:`int`, optional): Pass one of - :attr:`CHAT_BOOST`, :attr:`REMOVED_CHAT_BOOST` or - :attr:`ANY_CHAT_BOOST` to specify if this handler should handle only updates with - :attr:`telegram.Update.chat_boost`, - :attr:`telegram.Update.removed_chat_boost` or both. Defaults to - :attr:`CHAT_BOOST`. - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters reactions to allow - only those which happen in the specified chat ID(s). - chat_username (:obj:`str` | Collection[:obj:`str`], optional): Filters reactions to allow - only those which happen in the specified username(s). - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - chat_boost_types (:obj:`int`): Optional. Specifies if this handler should handle only - updates with :attr:`telegram.Update.chat_boost`, - :attr:`telegram.Update.removed_chat_boost` or both. - block (:obj:`bool`): Determines whether the callback will run in a blocking way. - """ - - __slots__ = ( - "_chat_ids", - "_chat_usernames", - "chat_boost_types", - ) - - CHAT_BOOST: Final[int] = -1 - """ :obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_boost`.""" - REMOVED_CHAT_BOOST: Final[int] = 0 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.removed_chat_boost`.""" - ANY_CHAT_BOOST: Final[int] = 1 - """:obj:`int`: Used as a constant to handle both :attr:`telegram.Update.chat_boost` - and :attr:`telegram.Update.removed_chat_boost`.""" - - def __init__( - self: "ChatBoostHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_boost_types: int = CHAT_BOOST, - chat_id: Optional[int] = None, - chat_username: Optional[str] = None, - block: bool = True, - ): - super().__init__(callback, block=block) - self.chat_boost_types: int = chat_boost_types - self._chat_ids = parse_chat_id(chat_id) - self._chat_usernames = parse_username(chat_username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return False - - if not (update.chat_boost or update.removed_chat_boost): - return False - - if self.chat_boost_types == self.CHAT_BOOST and not update.chat_boost: - return False - - if self.chat_boost_types == self.REMOVED_CHAT_BOOST and not update.removed_chat_boost: - return False - - if not any((self._chat_ids, self._chat_usernames)): - return True - - # Extract chat and user IDs and usernames from the update for comparison - chat_id = chat.id if (chat := update.effective_chat) else None - chat_username = chat.username if chat else None - - return bool(self._chat_ids and (chat_id in self._chat_ids)) or bool( - self._chat_usernames and (chat_username in self._chat_usernames) - ) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatjoinrequesthandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatjoinrequesthandler.py deleted file mode 100755 index 849020f..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatjoinrequesthandler.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ChatJoinRequestHandler class.""" - -from typing import Optional - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import RT, SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, HandlerCallback - - -class ChatJoinRequestHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain - :attr:`telegram.Update.chat_join_request`. - - Note: - If neither of :paramref:`username` and the :paramref:`chat_id` are passed, this handler - accepts *any* join request. Otherwise, this handler accepts all requests to join chats - for which the chat ID is listed in :paramref:`chat_id` or the username is listed in - :paramref:`username`, or both. - - .. versionadded:: 20.0 - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - .. versionadded:: 13.8 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only - those which are asking to join the specified chat ID(s). - - .. versionadded:: 20.0 - username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only - those which are asking to join the specified username(s). - - .. versionadded:: 20.0 - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - - """ - - __slots__ = ( - "_chat_ids", - "_usernames", - ) - - def __init__( - self: "ChatJoinRequestHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - self._chat_ids = parse_chat_id(chat_id) - self._usernames = parse_username(username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.chat_join_request: - if not self._chat_ids and not self._usernames: - return True - if update.chat_join_request.chat.id in self._chat_ids: - return True - return update.chat_join_request.from_user.username in self._usernames - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatmemberhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatmemberhandler.py deleted file mode 100755 index a2b281c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/chatmemberhandler.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ChatMemberHandler class.""" -from typing import Final, Optional, TypeVar - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - - -class ChatMemberHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain a chat member update. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Chat Member Bot ` - - .. versionadded:: 13.4 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - chat_member_types (:obj:`int`, optional): Pass one of :attr:`MY_CHAT_MEMBER`, - :attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle - only updates with :attr:`telegram.Update.my_chat_member`, - :attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters chat member updates from - specified chat ID(s) only. - .. versionadded:: 21.3 - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - chat_member_types (:obj:`int`): Optional. Specifies if this handler should handle - only updates with :attr:`telegram.Update.my_chat_member`, - :attr:`telegram.Update.chat_member` or both. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ( - "_chat_ids", - "chat_member_types", - ) - MY_CHAT_MEMBER: Final[int] = -1 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`.""" - CHAT_MEMBER: Final[int] = 0 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_member`.""" - ANY_CHAT_MEMBER: Final[int] = 1 - """:obj:`int`: Used as a constant to handle both :attr:`telegram.Update.my_chat_member` - and :attr:`telegram.Update.chat_member`.""" - - def __init__( - self: "ChatMemberHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_member_types: int = MY_CHAT_MEMBER, - block: DVType[bool] = DEFAULT_TRUE, - chat_id: Optional[SCT[int]] = None, - ): - super().__init__(callback, block=block) - - self.chat_member_types: Optional[int] = chat_member_types - self._chat_ids = parse_chat_id(chat_id) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return False - if not (update.my_chat_member or update.chat_member): - return False - if ( - self._chat_ids - and update.effective_chat - and update.effective_chat.id not in self._chat_ids - ): - return False - if self.chat_member_types == self.ANY_CHAT_MEMBER: - return True - if self.chat_member_types == self.CHAT_MEMBER: - return bool(update.chat_member) - return bool(update.my_chat_member) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/choseninlineresulthandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/choseninlineresulthandler.py deleted file mode 100755 index 3bc80ed..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/choseninlineresulthandler.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ChosenInlineResultHandler class.""" -import re -from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union, cast - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - -if TYPE_CHECKING: - from telegram.ext import Application - - -class ChosenInlineResultHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain - :attr:`telegram.Update.chosen_inline_result`. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - pattern (:obj:`str` | :func:`re.Pattern `, optional): Regex pattern. If not - :obj:`None`, :func:`re.match` - is used on :attr:`telegram.ChosenInlineResult.result_id` to determine if an update - should be handled by this handler. This is accessible in the callback as - :attr:`telegram.ext.CallbackContext.matches`. - - .. versionadded:: 13.6 - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - pattern (`Pattern`): Optional. Regex pattern to test - :attr:`telegram.ChosenInlineResult.result_id` against. - - .. versionadded:: 13.6 - - """ - - __slots__ = ("pattern",) - - def __init__( - self: "ChosenInlineResultHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - pattern: Optional[Union[str, Pattern[str]]] = None, - ): - super().__init__(callback, block=block) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern: Optional[Union[str, Pattern[str]]] = pattern - - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` | :obj:`re.match` - - """ - if isinstance(update, Update) and update.chosen_inline_result: - if self.pattern: - if match := re.match(self.pattern, update.chosen_inline_result.result_id): - return match - else: - return True - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Union[bool, Match[str]], - ) -> None: - """This function adds the matched regex pattern result to - :attr:`telegram.ext.CallbackContext.matches`. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/commandhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/commandhandler.py deleted file mode 100755 index 27f7a42..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/commandhandler.py +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the CommandHandler class.""" -import re -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union - -from telegram import MessageEntity, Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext import filters as filters_module -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, FilterDataDict, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class CommandHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram commands. - - Commands are Telegram messages that start with a :attr:`telegram.MessageEntity.BOT_COMMAND` - (so with ``/``, optionally followed by an ``@`` and the bot's name and/or some additional - text). The handler will add a :obj:`list` to the :class:`CallbackContext` named - :attr:`CallbackContext.args`. It will contain a list of strings, which is the text following - the command split on single or consecutive whitespace characters. - - By default, the handler listens to messages as well as edited messages. To change this behavior - use :attr:`~filters.UpdateType.EDITED_MESSAGE ` - in the filter argument. - - Note: - :class:`CommandHandler` does *not* handle (edited) channel posts and does *not* handle - commands that are part of a caption. Please use :class:`~telegram.ext.MessageHandler` - with a suitable combination of filters (e.g. - :attr:`telegram.ext.filters.UpdateType.CHANNEL_POSTS`, - :attr:`telegram.ext.filters.CAPTION` and :class:`telegram.ext.filters.Regex`) to handle - those messages. - - Note: - If you want to support a different entity in the beginning, e.g. if a command message is - wrapped in a :attr:`telegram.MessageEntity.CODE`, use the - :class:`telegram.ext.PrefixHandler`. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - * :any:`Timer Bot ` - * :any:`Error Handler Bot ` - - .. versionchanged:: 20.0 - - * Renamed the attribute ``command`` to :attr:`commands`, which now is always a - :class:`frozenset` - * Updating the commands this handler listens to is no longer possible. - - Args: - command (:obj:`str` | Collection[:obj:`str`]): - The command or list of commands this handler should listen for. Case-insensitive. - Limitations are the same as for :attr:`telegram.BotCommand.command`. - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - filters (:class:`telegram.ext.filters.BaseFilter`, optional): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :mod:`telegram.ext.filters`. Filters can be combined using bitwise - operators (``&`` for :keyword:`and`, ``|`` for :keyword:`or`, ``~`` for :keyword:`not`) - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - has_args (:obj:`bool` | :obj:`int`, optional): - Determines whether the command handler should process the update or not. - If :obj:`True`, the handler will process any non-zero number of args. - If :obj:`False`, the handler will only process if there are no args. - if :obj:`int`, the handler will only process if there are exactly that many args. - Defaults to :obj:`None`, which means the handler will process any or no args. - - .. versionadded:: 20.5 - - Raises: - :exc:`ValueError`: When the command is too long or has illegal chars. - - Attributes: - commands (frozenset[:obj:`str`]): The set of commands this handler should listen for. - callback (:term:`coroutine function`): The callback function for this handler. - filters (:class:`telegram.ext.filters.BaseFilter`): Optional. Only allow updates with these - filters. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - has_args (:obj:`bool` | :obj:`int` | None): - Optional argument, otherwise all implementations of :class:`CommandHandler` will break. - Defaults to :obj:`None`, which means the handler will process any args or no args. - - .. versionadded:: 20.5 - """ - - __slots__ = ("commands", "filters", "has_args") - - def __init__( - self: "CommandHandler[CCT, RT]", - command: SCT[str], - callback: HandlerCallback[Update, CCT, RT], - filters: Optional[filters_module.BaseFilter] = None, - block: DVType[bool] = DEFAULT_TRUE, - has_args: Optional[Union[bool, int]] = None, - ): - super().__init__(callback, block=block) - - if isinstance(command, str): - commands = frozenset({command.lower()}) - else: - commands = frozenset(x.lower() for x in command) - for comm in commands: - if not re.match(r"^[\da-z_]{1,32}$", comm): - raise ValueError(f"Command `{comm}` is not a valid bot command") - self.commands: frozenset[str] = commands - - self.filters: filters_module.BaseFilter = ( - filters if filters is not None else filters_module.UpdateType.MESSAGES - ) - - self.has_args: Optional[Union[bool, int]] = has_args - - if (isinstance(self.has_args, int)) and (self.has_args < 0): - raise ValueError("CommandHandler argument has_args cannot be a negative integer") - - def _check_correct_args(self, args: list[str]) -> Optional[bool]: - """Determines whether the args are correct for this handler. Implemented in check_update(). - Args: - args (:obj:`list`): The args for the handler. - Returns: - :obj:`bool`: Whether the args are valid for this handler. - """ - return bool( - (self.has_args is None) - or (self.has_args is True and args) - or (self.has_args is False and not args) - or (isinstance(self.has_args, int) and len(args) == self.has_args) - ) - - def check_update( - self, update: object - ) -> Optional[Union[bool, tuple[list[str], Optional[Union[bool, FilterDataDict]]]]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`list`: The list of args for the handler. - - """ - if isinstance(update, Update) and update.effective_message: - message = update.effective_message - - if ( - message.entities - and message.entities[0].type == MessageEntity.BOT_COMMAND - and message.entities[0].offset == 0 - and message.text - and message.get_bot() - ): - command = message.text[1 : message.entities[0].length] - args = message.text.split()[1:] - command_parts = command.split("@") - command_parts.append(message.get_bot().username) - - if not ( - command_parts[0].lower() in self.commands - and command_parts[1].lower() == message.get_bot().username.lower() - ): - return None - - if not self._check_correct_args(args): - return None - - filter_result = self.filters.check_update(update) - if filter_result: - return args, filter_result - return False - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Union[bool, tuple[list[str], Optional[bool]]]], - ) -> None: - """Add text after the command to :attr:`CallbackContext.args` as list, split on single - whitespaces and add output of data filters to :attr:`CallbackContext` as well. - """ - if isinstance(check_result, tuple): - context.args = check_result[0] - if isinstance(check_result[1], dict): - context.update(check_result[1]) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/conversationhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/conversationhandler.py deleted file mode 100755 index 1bc5f03..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/conversationhandler.py +++ /dev/null @@ -1,958 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ConversationHandler.""" -import asyncio -import datetime as dtm -from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Final, Generic, NoReturn, Optional, Union, cast - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE, DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import DVType -from telegram._utils.warnings import warn -from telegram.ext._application import ApplicationHandlerStop -from telegram.ext._extbot import ExtBot -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._handlers.callbackqueryhandler import CallbackQueryHandler -from telegram.ext._handlers.choseninlineresulthandler import ChosenInlineResultHandler -from telegram.ext._handlers.inlinequeryhandler import InlineQueryHandler -from telegram.ext._handlers.stringcommandhandler import StringCommandHandler -from telegram.ext._handlers.stringregexhandler import StringRegexHandler -from telegram.ext._handlers.typehandler import TypeHandler -from telegram.ext._utils.trackingdict import TrackingDict -from telegram.ext._utils.types import CCT, ConversationDict, ConversationKey - -if TYPE_CHECKING: - from telegram.ext import Application, Job, JobQueue -_CheckUpdateType = tuple[object, ConversationKey, BaseHandler[Update, CCT, object], object] - -_LOGGER = get_logger(__name__, class_name="ConversationHandler") - - -@dataclass -class _ConversationTimeoutContext(Generic[CCT]): - """Used as a datastore for conversation timeouts. Passed in the - :paramref:`JobQueue.run_once.data` parameter. See :meth:`_trigger_timeout`. - """ - - __slots__ = ("application", "callback_context", "conversation_key", "update") - - conversation_key: ConversationKey - update: Update - application: "Application[Any, CCT, Any, Any, Any, JobQueue]" - callback_context: CCT - - -@dataclass -class PendingState: - """Thin wrapper around :class:`asyncio.Task` to handle block=False handlers. Note that this is - a public class of this module, since :meth:`Application.update_persistence` needs to access it. - It's still hidden from users, since this module itself is private. - """ - - __slots__ = ("old_state", "task") - - task: asyncio.Task - old_state: object - - def done(self) -> bool: - return self.task.done() - - def resolve(self) -> object: - """Returns the new state of the :class:`ConversationHandler` if available. If there was an - exception during the task execution, then return the old state. If both the new and old - state are :obj:`None`, return `CH.END`. If only the new state is :obj:`None`, return the - old state. - - Raises: - :exc:`RuntimeError`: If the current task has not yet finished. - """ - if not self.task.done(): - raise RuntimeError("New state is not yet available") - - exc = self.task.exception() - if exc: - _LOGGER.exception( - "Task function raised exception. Falling back to old state %s", - self.old_state, - ) - return self.old_state - - res = self.task.result() - if res is None and self.old_state is None: - res = ConversationHandler.END - elif res is None: - # returning None from a callback means that we want to stay in the old state - return self.old_state - - return res - - -class ConversationHandler(BaseHandler[Update, CCT, object]): - """ - A handler to hold a conversation with a single or multiple users through Telegram updates by - managing three collections of other handlers. - - Warning: - :class:`ConversationHandler` heavily relies on incoming updates being processed one by one. - When using this handler, :attr:`telegram.ext.ApplicationBuilder.concurrent_updates` should - be set to :obj:`False`. - - Note: - :class:`ConversationHandler` will only accept updates that are (subclass-)instances of - :class:`telegram.Update`. This is, because depending on the :attr:`per_user` and - :attr:`per_chat`, :class:`ConversationHandler` relies on - :attr:`telegram.Update.effective_user` and/or :attr:`telegram.Update.effective_chat` in - order to determine which conversation an update should belong to. For - :attr:`per_message=True `, :class:`ConversationHandler` uses - :attr:`update.callback_query.message.message_id ` when - :attr:`per_chat=True ` and - :attr:`update.callback_query.inline_message_id <.CallbackQuery.inline_message_id>` when - :attr:`per_chat=False `. For a more detailed explanation, please see our `FAQ`_. - - Finally, :class:`ConversationHandler`, does *not* handle (edited) channel posts. - - .. _`FAQ`: https://github.com/python-telegram-bot/python-telegram-bot/wiki\ - /Frequently-Asked-Questions#what-do-the-per_-settings-in-conversation handler-do - - The first collection, a :obj:`list` named :attr:`entry_points`, is used to initiate the - conversation, for example with a :class:`telegram.ext.CommandHandler` or - :class:`telegram.ext.MessageHandler`. - - The second collection, a :obj:`dict` named :attr:`states`, contains the different conversation - steps and one or more associated handlers that should be used if the user sends a message when - the conversation with them is currently in that state. Here you can also define a state for - :attr:`TIMEOUT` to define the behavior when :attr:`conversation_timeout` is exceeded, and a - state for :attr:`WAITING` to define behavior when a new update is received while the previous - :attr:`block=False ` handler is not finished. - - The third collection, a :obj:`list` named :attr:`fallbacks`, is used if the user is currently - in a conversation but the state has either no associated handler or the handler that is - associated to the state is inappropriate for the update, for example if the update contains a - command, but a regular text message is expected. You could use this for a ``/cancel`` command - or to let the user know their message was not recognized. - - To change the state of conversation, the callback function of a handler must return the new - state after responding to the user. If it does not return anything (returning :obj:`None` by - default), the state will not change. If an entry point callback function returns :obj:`None`, - the conversation ends immediately after the execution of this callback function. - To end the conversation, the callback function must return :attr:`END` or ``-1``. To - handle the conversation timeout, use handler :attr:`TIMEOUT` or ``-2``. - Finally, :class:`telegram.ext.ApplicationHandlerStop` can be used in conversations as described - in its documentation. - - Note: - In each of the described collections of handlers, a handler may in turn be a - :class:`ConversationHandler`. In that case, the child :class:`ConversationHandler` should - have the attribute :attr:`map_to_parent` which allows returning to the parent conversation - at specified states within the child conversation. - - Note that the keys in :attr:`map_to_parent` must not appear as keys in :attr:`states` - attribute or else the latter will be ignored. You may map :attr:`END` to one of the parents - states to continue the parent conversation after the child conversation has ended or even - map a state to :attr:`END` to end the *parent* conversation from within the child - conversation. For an example on nested :class:`ConversationHandler` s, see - :any:`examples.nestedconversationbot`. - - Examples: - * :any:`Conversation Bot ` - * :any:`Conversation Bot 2 ` - * :any:`Nested Conversation Bot ` - * :any:`Persistent Conversation Bot ` - - Args: - entry_points (list[:class:`telegram.ext.BaseHandler`]): A list of :obj:`BaseHandler` - objects that - can trigger the start of the conversation. The first handler whose :meth:`check_update` - method returns :obj:`True` will be used. If all return :obj:`False`, the update is not - handled. - states (dict[:obj:`object`, list[:class:`telegram.ext.BaseHandler`]]): A :obj:`dict` that - defines the different states of conversation a user can be in and one or more - associated :obj:`BaseHandler` objects that should be used in that state. The first - handler whose :meth:`check_update` method returns :obj:`True` will be used. - fallbacks (list[:class:`telegram.ext.BaseHandler`]): A list of handlers that might be used - if the user is in a conversation, but every handler for their current state returned - :obj:`False` on :meth:`check_update`. The first handler which :meth:`check_update` - method returns :obj:`True` will be used. If all return :obj:`False`, the update is not - handled. - allow_reentry (:obj:`bool`, optional): If set to :obj:`True`, a user that is currently in a - conversation can restart the conversation by triggering one of the entry points. - Default is :obj:`False`. - per_chat (:obj:`bool`, optional): If the conversation key should contain the Chat's ID. - Default is :obj:`True`. - per_user (:obj:`bool`, optional): If the conversation key should contain the User's ID. - Default is :obj:`True`. - per_message (:obj:`bool`, optional): If the conversation key should contain the Message's - ID. Default is :obj:`False`. - conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`, optional): When this - handler is inactive more than this timeout (in seconds), it will be automatically - ended. If this value is ``0`` or :obj:`None` (default), there will be no timeout. The - last received update and the corresponding :class:`context <.CallbackContext>` will be - handled by *ALL* the handler's whose :meth:`check_update` method returns :obj:`True` - that are in the state :attr:`ConversationHandler.TIMEOUT`. - - Caution: - * This feature relies on the :attr:`telegram.ext.Application.job_queue` being set - and hence requires that the dependencies that :class:`telegram.ext.JobQueue` - relies on are installed. - * Using :paramref:`conversation_timeout` with nested conversations is currently - not supported. You can still try to use it, but it will likely behave - differently from what you expect. - - name (:obj:`str`, optional): The name for this conversation handler. Required for - persistence. - persistent (:obj:`bool`, optional): If the conversation's dict for this handler should be - saved. :paramref:`name` is required and persistence has to be set in - :attr:`Application <.Application.persistence>`. - - .. versionchanged:: 20.0 - Was previously named as ``persistence``. - map_to_parent (dict[:obj:`object`, :obj:`object`], optional): A :obj:`dict` that can be - used to instruct a child conversation handler to transition into a mapped state on - its parent conversation handler in place of a specified nested state. - block (:obj:`bool`, optional): Pass :obj:`False` or :obj:`True` to set a default value for - the :attr:`BaseHandler.block` setting of all handlers (in :attr:`entry_points`, - :attr:`states` and :attr:`fallbacks`). The resolution order for checking if a handler - should be run non-blocking is: - - 1. :attr:`telegram.ext.BaseHandler.block` (if set) - 2. the value passed to this parameter (if any) - 3. :attr:`telegram.ext.Defaults.block` (if defaults are used) - - .. seealso:: :wiki:`Concurrency` - - .. versionchanged:: 20.0 - No longer overrides the handlers settings. Resolution order was changed. - - Raises: - :exc:`ValueError`: If :paramref:`persistent` is used but :paramref:`name` was not set, or - when :attr:`per_message`, :attr:`per_chat`, :attr:`per_user` are all :obj:`False`. - - Attributes: - block (:obj:`bool`): Determines whether the callback will run in a blocking way. Always - :obj:`True` since conversation handlers handle any non-blocking callbacks internally. - - """ - - __slots__ = ( - "_allow_reentry", - "_block", - "_child_conversations", - "_conversation_timeout", - "_conversations", - "_entry_points", - "_fallbacks", - "_map_to_parent", - "_name", - "_per_chat", - "_per_message", - "_per_user", - "_persistent", - "_states", - "_timeout_jobs_lock", - "timeout_jobs", - ) - - END: Final[int] = -1 - """:obj:`int`: Used as a constant to return when a conversation is ended.""" - TIMEOUT: Final[int] = -2 - """:obj:`int`: Used as a constant to handle state when a conversation is timed out - (exceeded :attr:`conversation_timeout`). - """ - WAITING: Final[int] = -3 - """:obj:`int`: Used as a constant to handle state when a conversation is still waiting on the - previous :attr:`block=False ` handler to finish.""" - - # pylint: disable=super-init-not-called - def __init__( - self: "ConversationHandler[CCT]", - entry_points: list[BaseHandler[Update, CCT, object]], - states: dict[object, list[BaseHandler[Update, CCT, object]]], - fallbacks: list[BaseHandler[Update, CCT, object]], - allow_reentry: bool = False, - per_chat: bool = True, - per_user: bool = True, - per_message: bool = False, - conversation_timeout: Optional[Union[float, dtm.timedelta]] = None, - name: Optional[str] = None, - persistent: bool = False, - map_to_parent: Optional[dict[object, object]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - # these imports need to be here because of circular import error otherwise - from telegram.ext import ( # pylint: disable=import-outside-toplevel - PollAnswerHandler, - PollHandler, - PreCheckoutQueryHandler, - ShippingQueryHandler, - ) - - # self.block is what the Application checks and we want it to always run CH in a blocking - # way so that CH can take care of any non-blocking logic internally - self.block: DVType[bool] = True - # Store the actual setting in a protected variable instead - self._block: DVType[bool] = block - - self._entry_points: list[BaseHandler[Update, CCT, object]] = entry_points - self._states: dict[object, list[BaseHandler[Update, CCT, object]]] = states - self._fallbacks: list[BaseHandler[Update, CCT, object]] = fallbacks - - self._allow_reentry: bool = allow_reentry - self._per_user: bool = per_user - self._per_chat: bool = per_chat - self._per_message: bool = per_message - self._conversation_timeout: Optional[Union[float, dtm.timedelta]] = conversation_timeout - self._name: Optional[str] = name - self._map_to_parent: Optional[dict[object, object]] = map_to_parent - - # if conversation_timeout is used, this dict is used to schedule a job which runs when the - # conv has timed out. - self.timeout_jobs: dict[ConversationKey, Job[Any]] = {} - self._timeout_jobs_lock = asyncio.Lock() - self._conversations: ConversationDict = {} - self._child_conversations: set[ConversationHandler] = set() - - if persistent and not self.name: - raise ValueError("Conversations can't be persistent when handler is unnamed.") - self._persistent: bool = persistent - - if not any((self.per_user, self.per_chat, self.per_message)): - raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'") - - if self.per_message and not self.per_chat: - warn( - "If 'per_message=True' is used, 'per_chat=True' should also be used, " - "since message IDs are not globally unique.", - stacklevel=2, - ) - - all_handlers: list[BaseHandler[Update, CCT, object]] = [] - all_handlers.extend(entry_points) - all_handlers.extend(fallbacks) - - for state_handlers in states.values(): - all_handlers.extend(state_handlers) - - self._child_conversations.update( - handler for handler in all_handlers if isinstance(handler, ConversationHandler) - ) - - # this link will be added to all warnings tied to per_* setting - per_faq_link = ( - " Read this FAQ entry to learn more about the per_* settings: " - "https://github.com/python-telegram-bot/python-telegram-bot/wiki" - "/Frequently-Asked-Questions#what-do-the-per_-settings-in-conversationhandler-do." - ) - - # this loop is going to warn the user about handlers which can work unexpectedly - # in conversations - for handler in all_handlers: - if isinstance(handler, (StringCommandHandler, StringRegexHandler)): - warn( - "The `ConversationHandler` only handles updates of type `telegram.Update`. " - f"{handler.__class__.__name__} handles updates of type `str`.", - stacklevel=2, - ) - elif isinstance(handler, TypeHandler) and not issubclass(handler.type, Update): - warn( - "The `ConversationHandler` only handles updates of type `telegram.Update`." - f" The TypeHandler is set to handle {handler.type.__name__}.", - stacklevel=2, - ) - elif isinstance(handler, PollHandler): - warn( - "PollHandler will never trigger in a conversation since it has no information " - "about the chat or the user who voted in it. Do you mean the " - "`PollAnswerHandler`?", - stacklevel=2, - ) - - elif self.per_chat and ( - isinstance( - handler, - ( - ShippingQueryHandler, - InlineQueryHandler, - ChosenInlineResultHandler, - PreCheckoutQueryHandler, - PollAnswerHandler, - ), - ) - ): - warn( - f"Updates handled by {handler.__class__.__name__} only have information about " - "the user, so this handler won't ever be triggered if `per_chat=True`." - f"{per_faq_link}", - stacklevel=2, - ) - - elif self.per_message and not isinstance(handler, CallbackQueryHandler): - warn( - "If 'per_message=True', all entry points, state handlers, and fallbacks" - " must be 'CallbackQueryHandler', since no other handlers " - f"have a message context.{per_faq_link}", - stacklevel=2, - ) - elif not self.per_message and isinstance(handler, CallbackQueryHandler): - warn( - "If 'per_message=False', 'CallbackQueryHandler' will not be " - f"tracked for every message.{per_faq_link}", - stacklevel=2, - ) - - if self.conversation_timeout and isinstance(handler, self.__class__): - warn( - "Using `conversation_timeout` with nested conversations is currently not " - "supported. You can still try to use it, but it will likely behave " - "differently from what you expect.", - stacklevel=2, - ) - - def __repr__(self) -> str: - """Give a string representation of the ConversationHandler in the form - ``ConversationHandler[name=..., states={...}]``. - - If there are more than 3 states, only the first 3 states are listed. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - truncation_threshold = 3 - states = dict(list(self.states.items())[:truncation_threshold]) - states_string = str(states) - if len(self.states) > truncation_threshold: - states_string = states_string[:-1] + ", ...}" - - return build_repr_with_selected_attrs( - self, - name=self.name, - states=states_string, - ) - - @property - def entry_points(self) -> list[BaseHandler[Update, CCT, object]]: - """list[:class:`telegram.ext.BaseHandler`]: A list of :obj:`BaseHandler` objects that can - trigger the start of the conversation. - """ - return self._entry_points - - @entry_points.setter - def entry_points(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to entry_points after initialization." - ) - - @property - def states(self) -> dict[object, list[BaseHandler[Update, CCT, object]]]: - """dict[:obj:`object`, list[:class:`telegram.ext.BaseHandler`]]: A :obj:`dict` that - defines the different states of conversation a user can be in and one or more - associated :obj:`BaseHandler` objects that should be used in that state. - """ - return self._states - - @states.setter - def states(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to states after initialization.") - - @property - def fallbacks(self) -> list[BaseHandler[Update, CCT, object]]: - """list[:class:`telegram.ext.BaseHandler`]: A list of handlers that might be used if - the user is in a conversation, but every handler for their current state returned - :obj:`False` on :meth:`check_update`. - """ - return self._fallbacks - - @fallbacks.setter - def fallbacks(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to fallbacks after initialization.") - - @property - def allow_reentry(self) -> bool: - """:obj:`bool`: Determines if a user can restart a conversation with an entry point.""" - return self._allow_reentry - - @allow_reentry.setter - def allow_reentry(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to allow_reentry after initialization." - ) - - @property - def per_user(self) -> bool: - """:obj:`bool`: If the conversation key should contain the User's ID.""" - return self._per_user - - @per_user.setter - def per_user(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to per_user after initialization.") - - @property - def per_chat(self) -> bool: - """:obj:`bool`: If the conversation key should contain the Chat's ID.""" - return self._per_chat - - @per_chat.setter - def per_chat(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to per_chat after initialization.") - - @property - def per_message(self) -> bool: - """:obj:`bool`: If the conversation key should contain the message's ID.""" - return self._per_message - - @per_message.setter - def per_message(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to per_message after initialization.") - - @property - def conversation_timeout( - self, - ) -> Optional[Union[float, dtm.timedelta]]: - """:obj:`float` | :obj:`datetime.timedelta`: Optional. When this - handler is inactive more than this timeout (in seconds), it will be automatically - ended. - """ - return self._conversation_timeout - - @conversation_timeout.setter - def conversation_timeout(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to conversation_timeout after initialization." - ) - - @property - def name(self) -> Optional[str]: - """:obj:`str`: Optional. The name for this :class:`ConversationHandler`.""" - return self._name - - @name.setter - def name(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to name after initialization.") - - @property - def persistent(self) -> bool: - """:obj:`bool`: Optional. If the conversations dict for this handler should be - saved. :attr:`name` is required and persistence has to be set in - :attr:`Application <.Application.persistence>`. - """ - return self._persistent - - @persistent.setter - def persistent(self, _: object) -> NoReturn: - raise AttributeError("You can not assign a new value to persistent after initialization.") - - @property - def map_to_parent(self) -> Optional[dict[object, object]]: - """dict[:obj:`object`, :obj:`object`]: Optional. A :obj:`dict` that can be - used to instruct a nested :class:`ConversationHandler` to transition into a mapped state on - its parent :class:`ConversationHandler` in place of a specified nested state. - """ - return self._map_to_parent - - @map_to_parent.setter - def map_to_parent(self, _: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to map_to_parent after initialization." - ) - - async def _initialize_persistence( - self, application: "Application" - ) -> dict[str, TrackingDict[ConversationKey, object]]: - """Initializes the persistence for this handler and its child conversations. - While this method is marked as protected, we expect it to be called by the - Application/parent conversations. It's just protected to hide it from users. - - Args: - application (:class:`telegram.ext.Application`): The application. - - Returns: - A dict {conversation.name -> TrackingDict}, which contains all dict of this - conversation and possible child conversations. - - """ - if not (self.persistent and self.name and application.persistence): - raise RuntimeError( - "This handler is not persistent, has no name or the application has no " - "persistence!" - ) - - current_conversations = self._conversations - self._conversations = cast( - TrackingDict[ConversationKey, object], - TrackingDict(), - ) - # In the conversation already processed updates - self._conversations.update(current_conversations) - # above might be partly overridden but that's okay since we warn about that in - # add_handler - stored_data = await application.persistence.get_conversations(self.name) - self._conversations.update_no_track(stored_data) - - # Since CH.END is stored as normal state, we need to properly parse it here in order to - # actually end the conversation, i.e. delete the key from the _conversations dict - # This also makes sure that these entries are deleted from the persisted data on the next - # run of Application.update_persistence - for key, state in stored_data.items(): - if state == self.END: - self._update_state(new_state=self.END, key=key) - - out = {self.name: self._conversations} - - for handler in self._child_conversations: - out.update( - await handler._initialize_persistence( # pylint: disable=protected-access - application=application - ) - ) - - return out - - def _get_key(self, update: Update) -> ConversationKey: - """Builds the conversation key associated with the update.""" - chat = update.effective_chat - user = update.effective_user - - key: list[Union[int, str]] = [] - - if self.per_chat: - if chat is None: - raise RuntimeError("Can't build key for update without effective chat!") - key.append(chat.id) - - if self.per_user: - if user is None: - raise RuntimeError("Can't build key for update without effective user!") - key.append(user.id) - - if self.per_message: - if update.callback_query is None: - raise RuntimeError("Can't build key for update without CallbackQuery!") - if update.callback_query.inline_message_id: - key.append(update.callback_query.inline_message_id) - else: - key.append(update.callback_query.message.message_id) # type: ignore[union-attr] - - return tuple(key) - - async def _schedule_job_delayed( - self, - new_state: asyncio.Task, - application: "Application[Any, CCT, Any, Any, Any, JobQueue]", - update: Update, - context: CCT, - conversation_key: ConversationKey, - ) -> None: - try: - effective_new_state = await new_state - except Exception as exc: - _LOGGER.debug( - "Non-blocking handler callback raised exception. Not scheduling conversation " - "timeout.", - exc_info=exc, - ) - return None - return self._schedule_job( - new_state=effective_new_state, - application=application, - update=update, - context=context, - conversation_key=conversation_key, - ) - - def _schedule_job( - self, - new_state: object, - application: "Application[Any, CCT, Any, Any, Any, JobQueue]", - update: Update, - context: CCT, - conversation_key: ConversationKey, - ) -> None: - """Schedules a job which executes :meth:`_trigger_timeout` upon conversation timeout.""" - if new_state == self.END: - return - - try: - # both job_queue & conversation_timeout are checked before calling _schedule_job - j_queue = application.job_queue - self.timeout_jobs[conversation_key] = j_queue.run_once( # type: ignore[union-attr] - self._trigger_timeout, - self.conversation_timeout, # type: ignore[arg-type] - data=_ConversationTimeoutContext(conversation_key, update, application, context), - ) - except Exception as exc: - _LOGGER.exception("Failed to schedule timeout.", exc_info=exc) - - # pylint: disable=too-many-return-statements - def check_update(self, update: object) -> Optional[_CheckUpdateType[CCT]]: - """ - Determines whether an update should be handled by this conversation handler, and if so in - which state the conversation currently is. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return None - # Ignore messages in channels - if update.channel_post or update.edited_channel_post: - return None - if self.per_chat and not update.effective_chat: - return None - if self.per_user and not update.effective_user: - return None - if self.per_message and not update.callback_query: - return None - if update.callback_query and self.per_chat and not update.callback_query.message: - return None - - key = self._get_key(update) - state = self._conversations.get(key) - check: Optional[object] = None - - # Resolve futures - if isinstance(state, PendingState): - _LOGGER.debug("Waiting for asyncio Task to finish ...") - - # check if future is finished or not - if state.done(): - res = state.resolve() - # Special case if an error was raised in a non-blocking entry-point - if state.old_state is None and state.task.exception(): - self._conversations.pop(key, None) - state = None - else: - self._update_state(res, key) - state = self._conversations.get(key) - - # if not then handle WAITING state instead - else: - handlers = self.states.get(self.WAITING, []) - for handler_ in handlers: - check = handler_.check_update(update) - if check is not None and check is not False: - return self.WAITING, key, handler_, check - return None - - _LOGGER.debug("Selecting conversation %s with state %s", str(key), str(state)) - - handler: Optional[BaseHandler] = None - - # Search entry points for a match - if state is None or self.allow_reentry: - for entry_point in self.entry_points: - check = entry_point.check_update(update) - if check is not None and check is not False: - handler = entry_point - break - - else: - if state is None: - return None - - # Get the handler list for current state, if we didn't find one yet and we're still here - if state is not None and handler is None: - for candidate in self.states.get(state, []): - check = candidate.check_update(update) - if check is not None and check is not False: - handler = candidate - break - - # Find a fallback handler if all other handlers fail - else: - for fallback in self.fallbacks: - check = fallback.check_update(update) - if check is not None and check is not False: - handler = fallback - break - - else: - return None - - return state, key, handler, check # type: ignore[return-value] - - async def handle_update( # type: ignore[override] - self, - update: Update, - application: "Application[Any, CCT, Any, Any, Any, Any]", - check_result: _CheckUpdateType[CCT], - context: CCT, - ) -> Optional[object]: - """Send the update to the callback for the current state and BaseHandler - - Args: - check_result: The result from :meth:`check_update`. For this handler it's a tuple of - the conversation state, key, handler, and the handler's check result. - update (:class:`telegram.Update`): Incoming telegram update. - application (:class:`telegram.ext.Application`): Application that originated the - update. - context (:class:`telegram.ext.CallbackContext`): The context as provided by - the application. - - """ - current_state, conversation_key, handler, handler_check_result = check_result - raise_dp_handler_stop = False - - async with self._timeout_jobs_lock: - # Remove the old timeout job (if present) - timeout_job = self.timeout_jobs.pop(conversation_key, None) - - if timeout_job is not None: - timeout_job.schedule_removal() - - # Resolution order of "block": - # 1. Setting of the selected handler - # 2. Setting of the ConversationHandler - # 3. Default values of the bot - if handler.block is not DEFAULT_TRUE: - block = handler.block - elif self._block is not DEFAULT_TRUE: - block = self._block - elif isinstance(application.bot, ExtBot) and application.bot.defaults is not None: - block = application.bot.defaults.block - else: - block = DefaultValue.get_value(handler.block) - - try: # Now create task or await the callback - if block: - new_state: object = await handler.handle_update( - update, application, handler_check_result, context - ) - else: - new_state = application.create_task( - coroutine=handler.handle_update( - update, application, handler_check_result, context - ), - update=update, - name=f"ConversationHandler:{update.update_id}:handle_update:non_blocking_cb", - ) - except ApplicationHandlerStop as exception: - new_state = exception.state - raise_dp_handler_stop = True - async with self._timeout_jobs_lock: - if self.conversation_timeout: - if application.job_queue is None: - warn( - "Ignoring `conversation_timeout` because the Application has no JobQueue.", - stacklevel=1, - ) - elif not application.job_queue.scheduler.running: - warn( - "Ignoring `conversation_timeout` because the Applications JobQueue is " - "not running.", - stacklevel=1, - ) - elif isinstance(new_state, asyncio.Task): - # Add the new timeout job - # checking if the new state is self.END is done in _schedule_job - application.create_task( - self._schedule_job_delayed( - new_state, application, update, context, conversation_key - ), - update=update, - name=f"ConversationHandler:{update.update_id}:handle_update:timeout_job", - ) - else: - self._schedule_job(new_state, application, update, context, conversation_key) - - if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent: - self._update_state(self.END, conversation_key, handler) - if raise_dp_handler_stop: - raise ApplicationHandlerStop(self.map_to_parent.get(new_state)) - return self.map_to_parent.get(new_state) - - if current_state != self.WAITING: - self._update_state(new_state, conversation_key, handler) - - if raise_dp_handler_stop: - # Don't pass the new state here. If we're in a nested conversation, the parent is - # expecting None as return value. - raise ApplicationHandlerStop - # Signals a possible parent conversation to stay in the current state - return None - - def _update_state( - self, new_state: object, key: ConversationKey, handler: Optional[BaseHandler] = None - ) -> None: - if new_state == self.END: - if key in self._conversations: - # If there is no key in conversations, nothing is done. - del self._conversations[key] - - elif isinstance(new_state, asyncio.Task): - self._conversations[key] = PendingState( - old_state=self._conversations.get(key), task=new_state - ) - - elif new_state is not None: - if new_state not in self.states: - warn( - f"{repr(handler.callback.__name__) if handler is not None else 'BaseHandler'} " - f"returned state {new_state} which is unknown to the " - f"ConversationHandler{' ' + self.name if self.name is not None else ''}.", - stacklevel=2, - ) - self._conversations[key] = new_state - - async def _trigger_timeout(self, context: CCT) -> None: - """This is run whenever a conversation has timed out. Also makes sure that all handlers - which are in the :attr:`TIMEOUT` state and whose :meth:`BaseHandler.check_update` returns - :obj:`True` is handled. - """ - job = cast("Job", context.job) - ctxt = cast(_ConversationTimeoutContext, job.data) - - _LOGGER.debug( - "Conversation timeout was triggered for conversation %s!", ctxt.conversation_key - ) - - callback_context = ctxt.callback_context - - async with self._timeout_jobs_lock: - found_job = self.timeout_jobs.get(ctxt.conversation_key) - if found_job is not job: - # The timeout has been cancelled in handle_update - return - del self.timeout_jobs[ctxt.conversation_key] - - # Now run all handlers which are in TIMEOUT state - handlers = self.states.get(self.TIMEOUT, []) - for handler in handlers: - check = handler.check_update(ctxt.update) - if check is not None and check is not False: - try: - await handler.handle_update( - ctxt.update, ctxt.application, check, callback_context - ) - except ApplicationHandlerStop: - warn( - "ApplicationHandlerStop in TIMEOUT state of " - "ConversationHandler has no effect. Ignoring.", - stacklevel=2, - ) - - self._update_state(self.END, ctxt.conversation_key) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/inlinequeryhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/inlinequeryhandler.py deleted file mode 100755 index 31106ba..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/inlinequeryhandler.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the InlineQueryHandler class.""" -import re -from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union, cast - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class InlineQueryHandler(BaseHandler[Update, CCT, RT]): - """ - BaseHandler class to handle Telegram updates that contain a - :attr:`telegram.Update.inline_query`. - Optionally based on a regex. Read the documentation of the :mod:`re` module for more - information. - - Warning: - * When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - * :attr:`telegram.InlineQuery.chat_type` will not be set for inline queries from secret - chats and may not be set for inline queries coming from third-party clients. These - updates won't be handled, if :attr:`chat_types` is passed. - - Examples: - :any:`Inline Bot ` - - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pattern (:obj:`str` | :func:`re.Pattern `, optional): Regex pattern. - If not :obj:`None`, :func:`re.match` is used on :attr:`telegram.InlineQuery.query` - to determine if an update should be handled by this handler. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - chat_types (list[:obj:`str`], optional): List of allowed chat types. If passed, will only - handle inline queries with the appropriate :attr:`telegram.InlineQuery.chat_type`. - - .. versionadded:: 13.5 - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - pattern (:obj:`str` | :func:`re.Pattern `): Optional. Regex pattern to test - :attr:`telegram.InlineQuery.query` against. - chat_types (list[:obj:`str`]): Optional. List of allowed chat types. - - .. versionadded:: 13.5 - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("chat_types", "pattern") - - def __init__( - self: "InlineQueryHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - pattern: Optional[Union[str, Pattern[str]]] = None, - block: DVType[bool] = DEFAULT_TRUE, - chat_types: Optional[list[str]] = None, - ): - super().__init__(callback, block=block) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern: Optional[Union[str, Pattern[str]]] = pattern - self.chat_types: Optional[list[str]] = chat_types - - def check_update(self, update: object) -> Optional[Union[bool, Match[str]]]: - """ - Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` | :obj:`re.match` - - """ - if isinstance(update, Update) and update.inline_query: - if (self.chat_types is not None) and ( - update.inline_query.chat_type not in self.chat_types - ): - return False - if ( - self.pattern - and update.inline_query.query - and (match := re.match(self.pattern, update.inline_query.query)) - ): - return match - if not self.pattern: - return True - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Union[bool, Match[str]]], - ) -> None: - """Add the result of ``re.match(pattern, update.inline_query.query)`` to - :attr:`CallbackContext.matches` as list with one element. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagehandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagehandler.py deleted file mode 100755 index 625531a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagehandler.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the MessageHandler class.""" -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext import filters as filters_module -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class MessageHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram messages. They might contain text, media or status - updates. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - filters (:class:`telegram.ext.filters.BaseFilter`): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :mod:`telegram.ext.filters`. Filters can be combined using bitwise - operators (& for and, | for or, ~ for not). Passing :obj:`None` is a shortcut - to passing :class:`telegram.ext.filters.ALL`. - - .. seealso:: :wiki:`Advanced Filters ` - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - filters (:class:`telegram.ext.filters.BaseFilter`): Only allow updates with these Filters. - See :mod:`telegram.ext.filters` for a full list of all available filters. - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("filters",) - - def __init__( - self: "MessageHandler[CCT, RT]", - filters: Optional[filters_module.BaseFilter], - callback: HandlerCallback[Update, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - self.filters: filters_module.BaseFilter = ( - filters if filters is not None else filters_module.ALL - ) - - def check_update(self, update: object) -> Optional[Union[bool, dict[str, list[Any]]]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update): - return self.filters.check_update(update) or False - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Union[bool, dict[str, object]]], - ) -> None: - """Adds possible output of data filters to the :class:`CallbackContext`.""" - if isinstance(check_result, dict): - context.update(check_result) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagereactionhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagereactionhandler.py deleted file mode 100755 index 15f4f3d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/messagereactionhandler.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the MessageReactionHandler class.""" - -from typing import Final, Optional - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import RT, SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, HandlerCallback - - -class MessageReactionHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain a message reaction. - - Note: - The following rules apply to both ``username`` and the ``chat_id`` param groups, - respectively: - - * If none of them are passed, the handler does not filter the update for that specific - attribute. - * If a chat ID **or** a username is passed, the updates will be filtered with that - specific attribute. - * If a chat ID **and** a username are passed, an update containing **any** of them will be - filtered. - * :attr:`telegram.MessageReactionUpdated.actor_chat` is *not* considered for - :paramref:`user_id` and :paramref:`user_username` filtering. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - .. versionadded:: 20.8 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - message_reaction_types (:obj:`int`, optional): Pass one of - :attr:`MESSAGE_REACTION_UPDATED`, :attr:`MESSAGE_REACTION_COUNT_UPDATED` or - :attr:`MESSAGE_REACTION` to specify if this handler should handle only updates with - :attr:`telegram.Update.message_reaction`, - :attr:`telegram.Update.message_reaction_count` or both. Defaults to - :attr:`MESSAGE_REACTION`. - chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters reactions to allow - only those which happen in the specified chat ID(s). - chat_username (:obj:`str` | Collection[:obj:`str`], optional): Filters reactions to allow - only those which happen in the specified username(s). - user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters reactions to allow - only those which are set by the specified chat ID(s) (this can be the chat itself in - the case of anonymous users, see the - :paramref:`telegram.MessageReactionUpdated.actor_chat`). - user_username (:obj:`str` | Collection[:obj:`str`], optional): Filters reactions to allow - only those which are set by the specified username(s) (this can be the chat itself in - the case of anonymous users, see the - :paramref:`telegram.MessageReactionUpdated.actor_chat`). - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - message_reaction_types (:obj:`int`): Optional. Specifies if this handler should handle only - updates with :attr:`telegram.Update.message_reaction`, - :attr:`telegram.Update.message_reaction_count` or both. - block (:obj:`bool`): Determines whether the callback will run in a blocking way. - - """ - - __slots__ = ( - "_chat_ids", - "_chat_usernames", - "_user_ids", - "_user_usernames", - "message_reaction_types", - ) - - MESSAGE_REACTION_UPDATED: Final[int] = -1 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.message_reaction`.""" - MESSAGE_REACTION_COUNT_UPDATED: Final[int] = 0 - """:obj:`int`: Used as a constant to handle only - :attr:`telegram.Update.message_reaction_count`.""" - MESSAGE_REACTION: Final[int] = 1 - """:obj:`int`: Used as a constant to handle both :attr:`telegram.Update.message_reaction` - and :attr:`telegram.Update.message_reaction_count`.""" - - def __init__( - self: "MessageReactionHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - chat_id: Optional[SCT[int]] = None, - chat_username: Optional[SCT[str]] = None, - user_id: Optional[SCT[int]] = None, - user_username: Optional[SCT[str]] = None, - message_reaction_types: int = MESSAGE_REACTION, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - self.message_reaction_types: int = message_reaction_types - - self._chat_ids = parse_chat_id(chat_id) - self._chat_usernames = parse_username(chat_username) - if (user_id or user_username) and message_reaction_types in ( - self.MESSAGE_REACTION, - self.MESSAGE_REACTION_COUNT_UPDATED, - ): - raise ValueError( - "You can not filter for users and include anonymous reactions. Set " - "`message_reaction_types` to MESSAGE_REACTION_UPDATED." - ) - self._user_ids = parse_chat_id(user_id) - self._user_usernames = parse_username(user_username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return False - - if not (update.message_reaction or update.message_reaction_count): - return False - - if ( - self.message_reaction_types == self.MESSAGE_REACTION_UPDATED - and update.message_reaction_count - ): - return False - - if ( - self.message_reaction_types == self.MESSAGE_REACTION_COUNT_UPDATED - and update.message_reaction - ): - return False - - if not any((self._chat_ids, self._chat_usernames, self._user_ids, self._user_usernames)): - return True - - # Extract chat and user IDs and usernames from the update for comparison - chat_id = chat.id if (chat := update.effective_chat) else None - chat_username = chat.username if chat else None - user_id = user.id if (user := update.effective_user) else None - user_username = user.username if user else None - - return ( - bool(self._chat_ids and (chat_id in self._chat_ids)) - or bool(self._chat_usernames and (chat_username in self._chat_usernames)) - or bool(self._user_ids and (user_id in self._user_ids)) - or bool(self._user_usernames and (user_username in self._user_usernames)) - ) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/paidmediapurchasedhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/paidmediapurchasedhandler.py deleted file mode 100755 index 2f273e9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/paidmediapurchasedhandler.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PaidMediaPurchased class.""" - -from typing import Optional - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import CCT, RT, HandlerCallback - - -class PaidMediaPurchasedHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram - :attr:`purchased paid media `. - - .. versionadded:: 21.6 - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only - those which are from the specified user ID(s). - - username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only - those which are from the specified username(s). - - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - """ - - __slots__ = ( - "_user_ids", - "_usernames", - ) - - def __init__( - self: "PaidMediaPurchasedHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - user_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - self._user_ids = parse_chat_id(user_id) - self._usernames = parse_username(username) - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update) or not update.purchased_paid_media: - return False - - if not self._user_ids and not self._usernames: - return True - if update.purchased_paid_media.from_user.id in self._user_ids: - return True - return update.purchased_paid_media.from_user.username in self._usernames diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollanswerhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollanswerhandler.py deleted file mode 100755 index 69f1893..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollanswerhandler.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PollAnswerHandler class.""" - - -from telegram import Update -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, RT - - -class PollAnswerHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain a - :attr:`poll answer `. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Poll Bot ` - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.poll_answer) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollhandler.py deleted file mode 100755 index 36fc9bc..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/pollhandler.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PollHandler class.""" - - -from telegram import Update -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, RT - - -class PollHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram updates that contain a - :attr:`poll `. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Poll Bot ` - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.poll) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/precheckoutqueryhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/precheckoutqueryhandler.py deleted file mode 100755 index 04bf395..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/precheckoutqueryhandler.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PreCheckoutQueryHandler class.""" - - -import re -from re import Pattern -from typing import Optional, TypeVar, Union - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") - - -class PreCheckoutQueryHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram :attr:`telegram.Update.pre_checkout_query`. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Payment Bot ` - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - pattern (:obj:`str` | :func:`re.Pattern `, optional): Optional. Regex pattern - to test :attr:`telegram.PreCheckoutQuery.invoice_payload` against. - - .. versionadded:: 20.8 - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - pattern (:obj:`str` | :func:`re.Pattern `, optional): Optional. Regex pattern - to test :attr:`telegram.PreCheckoutQuery.invoice_payload` against. - - .. versionadded:: 20.8 - - """ - - __slots__ = ("pattern",) - - def __init__( - self: "PreCheckoutQueryHandler[CCT, RT]", - callback: HandlerCallback[Update, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - pattern: Optional[Union[str, Pattern[str]]] = None, - ): - super().__init__(callback, block=block) - - self.pattern: Optional[Pattern[str]] = re.compile(pattern) if pattern is not None else None - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.pre_checkout_query: - invoice_payload = update.pre_checkout_query.invoice_payload - if self.pattern: - if self.pattern.match(invoice_payload): - return True - else: - return True - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/prefixhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/prefixhandler.py deleted file mode 100755 index a6e4f38..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/prefixhandler.py +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PrefixHandler class.""" -import itertools -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union - -from telegram import Update -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import SCT, DVType -from telegram.ext import filters as filters_module -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class PrefixHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle custom prefix commands. - - This is an intermediate handler between :class:`MessageHandler` and :class:`CommandHandler`. - It supports configurable commands with the same options as :class:`CommandHandler`. It will - respond to every combination of :paramref:`prefix` and :paramref:`command`. - It will add a :obj:`list` to the :class:`CallbackContext` named :attr:`CallbackContext.args`, - containing a list of strings, which is the text following the command split on single or - consecutive whitespace characters. - - Examples: - - Single prefix and command: - - .. code:: python - - PrefixHandler("!", "test", callback) # will respond to '!test'. - - Multiple prefixes, single command: - - .. code:: python - - PrefixHandler(["!", "#"], "test", callback) # will respond to '!test' and '#test'. - - Multiple prefixes and commands: - - .. code:: python - - PrefixHandler( - ["!", "#"], ["test", "help"], callback - ) # will respond to '!test', '#test', '!help' and '#help'. - - - By default, the handler listens to messages as well as edited messages. To change this behavior - use :attr:`~filters.UpdateType.EDITED_MESSAGE ` - - Note: - * :class:`PrefixHandler` does *not* handle (edited) channel posts. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - .. versionchanged:: 20.0 - - * :class:`PrefixHandler` is no longer a subclass of :class:`CommandHandler`. - * Removed the attributes ``command`` and ``prefix``. Instead, the new :attr:`commands` - contains all commands that this handler listens to as a :class:`frozenset`, which - includes the prefixes. - * Updating the prefixes and commands this handler listens to is no longer possible. - - Args: - prefix (:obj:`str` | Collection[:obj:`str`]): - The prefix(es) that will precede :paramref:`command`. - command (:obj:`str` | Collection[:obj:`str`]): - The command or list of commands this handler should listen for. Case-insensitive. - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - filters (:class:`telegram.ext.filters.BaseFilter`, optional): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :mod:`telegram.ext.filters`. Filters can be combined using bitwise - operators (``&`` for :keyword:`and`, ``|`` for :keyword:`or`, ``~`` for :keyword:`not`) - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - commands (frozenset[:obj:`str`]): The commands that this handler will listen for, i.e. the - combinations of :paramref:`prefix` and :paramref:`command`. - callback (:term:`coroutine function`): The callback function for this handler. - filters (:class:`telegram.ext.filters.BaseFilter`): Optional. Only allow updates with these - Filters. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - # 'prefix' is a class property, & 'command' is included in the superclass, so they're left out. - __slots__ = ("commands", "filters") - - def __init__( - self: "PrefixHandler[CCT, RT]", - prefix: SCT[str], - command: SCT[str], - callback: HandlerCallback[Update, CCT, RT], - filters: Optional[filters_module.BaseFilter] = None, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback=callback, block=block) - - prefixes = {prefix.lower()} if isinstance(prefix, str) else {x.lower() for x in prefix} - - commands = {command.lower()} if isinstance(command, str) else {x.lower() for x in command} - - self.commands: frozenset[str] = frozenset( - p + c for p, c in itertools.product(prefixes, commands) - ) - self.filters: filters_module.BaseFilter = ( - filters if filters is not None else filters_module.UpdateType.MESSAGES - ) - - def check_update( - self, update: object - ) -> Optional[Union[bool, tuple[list[str], Optional[Union[bool, dict[Any, Any]]]]]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`list`: The list of args for the handler. - - """ - if isinstance(update, Update) and update.effective_message: - message = update.effective_message - - if message.text: - text_list = message.text.split() - if text_list[0].lower() not in self.commands: - return None - filter_result = self.filters.check_update(update) - if filter_result: - return text_list[1:], filter_result - return False - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Union[bool, tuple[list[str], Optional[bool]]]], - ) -> None: - """Add text after the command to :attr:`CallbackContext.args` as list, split on single - whitespaces and add output of data filters to :attr:`CallbackContext` as well. - """ - if isinstance(check_result, tuple): - context.args = check_result[0] - if isinstance(check_result[1], dict): - context.update(check_result[1]) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/shippingqueryhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/shippingqueryhandler.py deleted file mode 100755 index 1795a93..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/shippingqueryhandler.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ShippingQueryHandler class.""" - - -from telegram import Update -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, RT - - -class ShippingQueryHandler(BaseHandler[Update, CCT, RT]): - """Handler class to handle Telegram :attr:`telegram.Update.shipping_query`. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Examples: - :any:`Payment Bot ` - - Args: - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: Update, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the callback will run in a blocking way.. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.shipping_query) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringcommandhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringcommandhandler.py deleted file mode 100755 index 4ce7a9b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringcommandhandler.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the StringCommandHandler class.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, RT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - - -class StringCommandHandler(BaseHandler[str, CCT, RT]): - """Handler class to handle string commands. Commands are string updates that start with - ``/``. The handler will add a :obj:`list` to the - :class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings, - which is the text following the command split on single whitespace characters. - - Note: - This handler is not used to handle Telegram :class:`telegram.Update`, but strings manually - put in the queue. For example to send messages with the bot using command line or API. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - command (:obj:`str`): The command this handler should listen for. - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: str, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - command (:obj:`str`): The command this handler should listen for. - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("command",) - - def __init__( - self: "StringCommandHandler[CCT, RT]", - command: str, - callback: HandlerCallback[str, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - self.command: str = command - - def check_update(self, update: object) -> Optional[list[str]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:obj:`object`): The incoming update. - - Returns: - list[:obj:`str`]: List containing the text command split on whitespace. - - """ - if isinstance(update, str) and update.startswith("/"): - args = update[1:].split(" ") - if args[0] == self.command: - return args[1:] - return None - - def collect_additional_context( - self, - context: CCT, - update: str, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[list[str]], - ) -> None: - """Add text after the command to :attr:`CallbackContext.args` as list, split on single - whitespaces. - """ - context.args = check_result diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringregexhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringregexhandler.py deleted file mode 100755 index dda0052..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/stringregexhandler.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the StringRegexHandler class.""" - -import re -from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union - -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -if TYPE_CHECKING: - from telegram.ext import Application - -RT = TypeVar("RT") - - -class StringRegexHandler(BaseHandler[str, CCT, RT]): - """Handler class to handle string updates based on a regex which checks the update content. - - Read the documentation of the :mod:`re` module for more information. The :func:`re.match` - function is used to determine if an update should be handled by this handler. - - Note: - This handler is not used to handle Telegram :class:`telegram.Update`, but strings manually - put in the queue. For example to send messages with the bot using command line or API. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - pattern (:obj:`str` | :func:`re.Pattern `): The regex pattern. - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: str, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - pattern (:obj:`str` | :func:`re.Pattern `): The regex pattern. - callback (:term:`coroutine function`): The callback function for this handler. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("pattern",) - - def __init__( - self: "StringRegexHandler[CCT, RT]", - pattern: Union[str, Pattern[str]], - callback: HandlerCallback[str, CCT, RT], - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern: Union[str, Pattern[str]] = pattern - - def check_update(self, update: object) -> Optional[Match[str]]: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:obj:`object`): The incoming update. - - Returns: - :obj:`None` | :obj:`re.match` - - """ - if isinstance(update, str) and (match := re.match(self.pattern, update)): - return match - return None - - def collect_additional_context( - self, - context: CCT, - update: str, # noqa: ARG002 - application: "Application[Any, CCT, Any, Any, Any, Any]", # noqa: ARG002 - check_result: Optional[Match[str]], - ) -> None: - """Add the result of ``re.match(pattern, update)`` to :attr:`CallbackContext.matches` as - list with one element. - """ - if self.pattern and check_result: - context.matches = [check_result] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/typehandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_handlers/typehandler.py deleted file mode 100755 index 0d6ce78..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_handlers/typehandler.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the TypeHandler class.""" - -from typing import Optional, TypeVar - -from telegram._utils.defaultvalue import DEFAULT_TRUE -from telegram._utils.types import DVType -from telegram.ext._handlers.basehandler import BaseHandler -from telegram.ext._utils.types import CCT, HandlerCallback - -RT = TypeVar("RT") -UT = TypeVar("UT") -# If this is written directly next to the type variable mypy gets confused with [valid-type]. This -# could be reported to them, but I doubt they would change this since we override a builtin type -GenericUT = type[UT] - - -class TypeHandler(BaseHandler[UT, CCT, RT]): - """Handler class to handle updates of custom types. - - Warning: - When setting :paramref:`block` to :obj:`False`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - type (:external:class:`type`): The :external:class:`type` of updates this handler should - process, as determined by :obj:`isinstance` - callback (:term:`coroutine function`): The callback function for this handler. Will be - called when :meth:`check_update` has determined that an update should be processed by - this handler. Callback signature:: - - async def callback(update: object, context: CallbackContext) - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - strict (:obj:`bool`, optional): Use ``type`` instead of :obj:`isinstance`. - Default is :obj:`False`. - block (:obj:`bool`, optional): Determines whether the return value of the callback should - be awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. - - .. seealso:: :wiki:`Concurrency` - - Attributes: - type (:external:class:`type`): The :external:class:`type` of updates this handler should - process. - callback (:term:`coroutine function`): The callback function for this handler. - strict (:obj:`bool`): Use :external:class:`type` instead of :obj:`isinstance`. Default is - :obj:`False`. - block (:obj:`bool`): Determines whether the return value of the callback should be - awaited before processing the next handler in - :meth:`telegram.ext.Application.process_update`. - - """ - - __slots__ = ("strict", "type") - - def __init__( - self: "TypeHandler[UT, CCT, RT]", - type: GenericUT[UT], # pylint: disable=redefined-builtin - callback: HandlerCallback[UT, CCT, RT], - strict: bool = False, - block: DVType[bool] = DEFAULT_TRUE, - ): - super().__init__(callback, block=block) - self.type: GenericUT[UT] = type - self.strict: Optional[bool] = strict - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handler's :attr:`callback`. - - Args: - update (:obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not self.strict: - return isinstance(update, self.type) - return type(update) is self.type # pylint: disable=unidiomatic-typecheck diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_jobqueue.py b/venv/lib/python3.11/site-packages/telegram/ext/_jobqueue.py deleted file mode 100755 index 70c6405..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_jobqueue.py +++ /dev/null @@ -1,1013 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes JobQueue and Job.""" -import asyncio -import datetime as dtm -import re -import weakref -from typing import TYPE_CHECKING, Any, Generic, Optional, Union, cast, overload - -try: - from apscheduler.executors.asyncio import AsyncIOExecutor - from apscheduler.schedulers.asyncio import AsyncIOScheduler - - APS_AVAILABLE = True -except ImportError: - APS_AVAILABLE = False - -from telegram._utils.datetime import UTC, localize -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import JSONDict -from telegram.ext._extbot import ExtBot -from telegram.ext._utils.types import CCT, JobCallback - -if TYPE_CHECKING: - from collections.abc import Iterable - - if APS_AVAILABLE: - from apscheduler.job import Job as APSJob - - from telegram.ext import Application - - -_ALL_DAYS = tuple(range(7)) -_LOGGER = get_logger(__name__, class_name="JobQueue") - - -class JobQueue(Generic[CCT]): - """This class allows you to periodically perform tasks with the bot. It is a convenience - wrapper for the APScheduler library. - - This class is a :class:`~typing.Generic` class and accepts one type variable that specifies - the type of the argument ``context`` of the job callbacks (:paramref:`~run_once.callback`) of - :meth:`run_once` and the other scheduling methods. - - Important: - If you want to use this class, you must install PTB with the optional requirement - ``job-queue``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[job-queue]" - - Examples: - :any:`Timer Bot ` - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Job Queue ` - - .. versionchanged:: 20.0 - To use this class, PTB must be installed via - ``pip install "python-telegram-bot[job-queue]"``. - - Attributes: - scheduler (:class:`apscheduler.schedulers.asyncio.AsyncIOScheduler`): The scheduler. - - Warning: - This scheduler is configured by :meth:`set_application`. Additional configuration - settings can be made by users. However, calling - :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` will delete any - previous configuration settings. Therefore, please make sure to pass the values - returned by :attr:`scheduler_configuration` to the method call in addition to your - custom values. - Alternatively, you can also use methods like - :meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using - :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether. - - .. versionchanged:: 20.0 - Uses :class:`~apscheduler.schedulers.asyncio.AsyncIOScheduler` instead of - :class:`~apscheduler.schedulers.background.BackgroundScheduler` - - """ - - __slots__ = ("_application", "_executor", "scheduler") - _CRON_MAPPING = ("sun", "mon", "tue", "wed", "thu", "fri", "sat") - - def __init__(self) -> None: - if not APS_AVAILABLE: - raise RuntimeError( - "To use `JobQueue`, PTB must be installed via `pip install " - '"python-telegram-bot[job-queue]"`.' - ) - - self._application: Optional[weakref.ReferenceType[Application]] = None - self._executor = AsyncIOExecutor() - self.scheduler: "AsyncIOScheduler" = AsyncIOScheduler( # noqa: UP037 - **self.scheduler_configuration - ) - - def __repr__(self) -> str: - """Give a string representation of the JobQueue in the form ``JobQueue[application=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs(self, application=self.application) - - @property - def application(self) -> "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]": - """The application this JobQueue is associated with.""" - if self._application is None: - raise RuntimeError("No application was set for this JobQueue.") - application = self._application() - if application is not None: - return application - raise RuntimeError("The application instance is no longer alive.") - - @property - def scheduler_configuration(self) -> JSONDict: - """Provides configuration values that are used by :class:`JobQueue` for :attr:`scheduler`. - - Tip: - Since calling - :meth:`scheduler.configure() ` - deletes any previous setting, please make sure to pass these values to the method call - in addition to your custom values: - - .. code-block:: python - - scheduler.configure(..., **job_queue.scheduler_configuration) - - Alternatively, you can also use methods like - :meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using - :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether. - - .. versionadded:: 20.7 - - Returns: - dict[:obj:`str`, :obj:`object`]: The configuration values as dictionary. - - """ - timezone: dtm.tzinfo = UTC - if ( - self._application - and isinstance(self.application.bot, ExtBot) - and self.application.bot.defaults - ): - timezone = self.application.bot.defaults.tzinfo or UTC - - return { - "timezone": timezone, - "executors": {"default": self._executor}, - } - - def _tz_now(self) -> dtm.datetime: - return dtm.datetime.now(self.scheduler.timezone) - - @overload - def _parse_time_input(self, time: None, shift_day: bool = False) -> None: ... - - @overload - def _parse_time_input( - self, - time: Union[float, dtm.timedelta, dtm.datetime, dtm.time], - shift_day: bool = False, - ) -> dtm.datetime: ... - - def _parse_time_input( - self, - time: Union[float, dtm.timedelta, dtm.datetime, dtm.time, None], - shift_day: bool = False, - ) -> Optional[dtm.datetime]: - if time is None: - return None - if isinstance(time, (int, float)): - return self._tz_now() + dtm.timedelta(seconds=time) - if isinstance(time, dtm.timedelta): - return self._tz_now() + time - if isinstance(time, dtm.time): - date_time = dtm.datetime.combine( - dtm.datetime.now(tz=time.tzinfo or self.scheduler.timezone).date(), time - ) - if date_time.tzinfo is None: - # dtm.combine uses the tzinfo of `time`, which might be None, so we still have - # to localize it - date_time = localize(date_time, self.scheduler.timezone) - if shift_day and date_time <= dtm.datetime.now(UTC): - date_time += dtm.timedelta(days=1) - return date_time - return time - - def set_application( - self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]" - ) -> None: - """Set the application to be used by this JobQueue. - - Args: - application (:class:`telegram.ext.Application`): The application. - - """ - self._application = weakref.ref(application) - self.scheduler.configure(**self.scheduler_configuration) - - @staticmethod - async def job_callback(job_queue: "JobQueue[CCT]", job: "Job[CCT]") -> None: - """This method is used as a callback for the APScheduler jobs. - - More precisely, the ``func`` argument of :class:`apscheduler.job.Job` is set to this method - and the ``arg`` argument (representing positional arguments to ``func``) is set to a tuple - containing the :class:`JobQueue` itself and the :class:`~telegram.ext.Job` instance. - - Tip: - This method is a static method rather than a bound method. This makes the arguments - more transparent and allows for easier handling of PTBs integration of APScheduler - when utilizing advanced features of APScheduler. - - Hint: - This method is effectively a wrapper for :meth:`telegram.ext.Job.run`. - - .. versionadded:: 20.4 - - Args: - job_queue (:class:`JobQueue`): The job queue that created the job. - job (:class:`~telegram.ext.Job`): The job to run. - """ - await job.run(job_queue.application) - - def run_once( - self, - callback: JobCallback[CCT], - when: Union[float, dtm.timedelta, dtm.datetime, dtm.time], - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - job_kwargs: Optional[JSONDict] = None, - ) -> "Job[CCT]": - """Creates a new :class:`Job` instance that runs once and adds it to the queue. - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - when (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`): - Time in or at which the job should run. This parameter will be interpreted - depending on its type. - - * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the - job should run. - * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the - job should run. - * :obj:`datetime.datetime` will be interpreted as a specific date and time at - which the job should run. If the timezone (:attr:`datetime.datetime.tzinfo`) is - :obj:`None`, the default timezone of the bot will be used, which is UTC unless - :attr:`telegram.ext.Defaults.tzinfo` is used. - * :obj:`datetime.time` will be interpreted as a specific time of day at which the - job should run. This could be either today or, if the time has already passed, - tomorrow. If the timezone (:attr:`datetime.time.tzinfo`) is :obj:`None`, the - default timezone of the bot will be used, which is UTC unless - :attr:`telegram.ext.Defaults.tzinfo` is used. - - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`. - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - date_time = self._parse_time_input(when, shift_day=True) - - j = self.scheduler.add_job( - self.job_callback, - name=name, - trigger="date", - run_date=date_time, - args=(self, job), - timezone=date_time.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - - job._job = j # pylint: disable=protected-access - return job - - def run_repeating( - self, - callback: JobCallback[CCT], - interval: Union[float, dtm.timedelta], - first: Optional[Union[float, dtm.timedelta, dtm.datetime, dtm.time]] = None, - last: Optional[Union[float, dtm.timedelta, dtm.datetime, dtm.time]] = None, - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - job_kwargs: Optional[JSONDict] = None, - ) -> "Job[CCT]": - """Creates a new :class:`Job` instance that runs at specified intervals and adds it to the - queue. - - Note: - For a note about DST, please see the documentation of `APScheduler`_. - - .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html - #daylight-saving-time-behavior - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`): The interval in which - the job will run. If it is an :obj:`int` or a :obj:`float`, it will be interpreted - as seconds. - first (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`, optional): - Time in or at which the job should run. This parameter will be interpreted - depending on its type. - - * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the - job should run. - * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the - job should run. - * :obj:`datetime.datetime` will be interpreted as a specific date and time at - which the job should run. If the timezone (:attr:`datetime.datetime.tzinfo`) is - :obj:`None`, the default timezone of the bot will be used. - * :obj:`datetime.time` will be interpreted as a specific time of day at which the - job should run. This could be either today or, if the time has already passed, - tomorrow. If the timezone (:attr:`datetime.time.tzinfo`) is :obj:`None`, the - default timezone of the bot will be used, which is UTC unless - :attr:`telegram.ext.Defaults.tzinfo` is used. - - Defaults to :paramref:`interval` - - Note: - Setting :paramref:`first` to ``0``, ``datetime.datetime.now()`` or another - value that indicates that the job should run immediately will not work due - to how the APScheduler library works. If you want to run a job immediately, - we recommend to use an approach along the lines of:: - - job = context.job_queue.run_repeating(callback, interval=5) - await job.run(context.application) - - .. seealso:: :meth:`telegram.ext.Job.run` - - last (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`, optional): - Latest possible time for the job to run. This parameter will be interpreted - depending on its type. See :paramref:`first` for details. - - If :paramref:`last` is :obj:`datetime.datetime` or :obj:`datetime.time` type - and ``last.tzinfo`` is :obj:`None`, the default timezone of the bot will be - assumed, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used. - - Defaults to :obj:`None`. - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`. - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - - dt_first = self._parse_time_input(first) - dt_last = self._parse_time_input(last) - - if dt_last and dt_first and dt_last < dt_first: - raise ValueError("'last' must not be before 'first'!") - - if isinstance(interval, dtm.timedelta): - interval = interval.total_seconds() - - j = self.scheduler.add_job( - self.job_callback, - trigger="interval", - args=(self, job), - start_date=dt_first, - end_date=dt_last, - seconds=interval, - name=name, - **job_kwargs, - ) - - job._job = j # pylint: disable=protected-access - return job - - def run_monthly( - self, - callback: JobCallback[CCT], - when: dtm.time, - day: int, - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - job_kwargs: Optional[JSONDict] = None, - ) -> "Job[CCT]": - """Creates a new :class:`Job` that runs on a monthly basis and adds it to the queue. - - .. versionchanged:: 20.0 - The ``day_is_strict`` argument was removed. Instead one can now pass ``-1`` to the - :paramref:`day` parameter to have the job run on the last day of the month. - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - when (:obj:`datetime.time`): Time of day at which the job should run. If the timezone - (``when.tzinfo``) is :obj:`None`, the default timezone of the bot will be used, - which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used. - day (:obj:`int`): Defines the day of the month whereby the job would run. It should - be within the range of ``1`` and ``31``, inclusive. If a month has fewer days than - this number, the job will not run in this month. Passing ``-1`` leads to the job - running on the last day of the month. - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`. - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - - j = self.scheduler.add_job( - self.job_callback, - trigger="cron", - args=(self, job), - name=name, - day="last" if day == -1 else day, - hour=when.hour, - minute=when.minute, - second=when.second, - timezone=when.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - job._job = j # pylint: disable=protected-access - return job - - def run_daily( - self, - callback: JobCallback[CCT], - time: dtm.time, - days: tuple[int, ...] = _ALL_DAYS, - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - job_kwargs: Optional[JSONDict] = None, - ) -> "Job[CCT]": - """Creates a new :class:`Job` that runs on a daily basis and adds it to the queue. - - Note: - For a note about DST, please see the documentation of `APScheduler`_. - - .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html - #daylight-saving-time-behavior - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone - (:obj:`datetime.time.tzinfo`) is :obj:`None`, the default timezone of the bot will - be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used. - days (tuple[:obj:`int`], optional): Defines on which days of the week the job should - run (where ``0-6`` correspond to sunday - saturday). By default, the job will run - every day. - - .. versionchanged:: 20.0 - Changed day of the week mapping of 0-6 from monday-sunday to sunday-saturday. - - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`. - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - - j = self.scheduler.add_job( - self.job_callback, - name=name, - args=(self, job), - trigger="cron", - day_of_week=",".join([self._CRON_MAPPING[d] for d in days]), - hour=time.hour, - minute=time.minute, - second=time.second, - timezone=time.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - - job._job = j # pylint: disable=protected-access - return job - - def run_custom( - self, - callback: JobCallback[CCT], - job_kwargs: JSONDict, - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - ) -> "Job[CCT]": - """Creates a new custom defined :class:`Job`. - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by - the new job. Callback signature:: - - async def callback(context: CallbackContext) - - job_kwargs (:obj:`dict`): Arbitrary keyword arguments. Used as arguments for - :meth:`apscheduler.schedulers.base.BaseScheduler.add_job`. - data (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - - .. versionchanged:: 20.0 - Renamed the parameter ``context`` to :paramref:`data`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:attr:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will - be available in the callback. - - .. versionadded:: 20.0 - - user_id (:obj:`int`, optional): User id of the user associated with this job. If - passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will - be available in the callback. - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job - queue. - - """ - name = name or callback.__name__ - job = Job(callback=callback, data=data, name=name, chat_id=chat_id, user_id=user_id) - - j = self.scheduler.add_job(self.job_callback, args=(self, job), name=name, **job_kwargs) - - job._job = j # pylint: disable=protected-access - return job - - async def start(self) -> None: - # this method async just in case future versions need that - """Starts the :class:`~telegram.ext.JobQueue`.""" - if not self.scheduler.running: - self.scheduler.start() - - async def stop(self, wait: bool = True) -> None: - """Shuts down the :class:`~telegram.ext.JobQueue`. - - Args: - wait (:obj:`bool`, optional): Whether to wait until all currently running jobs - have finished. Defaults to :obj:`True`. - - """ - # the interface methods of AsyncIOExecutor are currently not really asyncio-compatible - # so we apply some small tweaks here to try and smoothen the integration into PTB - # TODO: When APS 4.0 hits, we should be able to remove the tweaks - if wait: - # Unfortunately AsyncIOExecutor just cancels them all ... - await asyncio.gather( - *self._executor._pending_futures, # pylint: disable=protected-access - return_exceptions=True, - ) - if self.scheduler.running: - self.scheduler.shutdown(wait=wait) - # scheduler.shutdown schedules a task in the event loop but immediately returns - # so give it a tiny bit of time to actually shut down. - await asyncio.sleep(0.01) - - def jobs(self, pattern: Union[str, re.Pattern[str], None] = None) -> tuple["Job[CCT]", ...]: - """Returns a tuple of all *scheduled* jobs that are currently in the :class:`JobQueue`. - - Args: - pattern (:obj:`str` | :obj:`re.Pattern`, optional): A regular expression pattern. If - passed, only jobs whose name matches the pattern will be returned. - Defaults to :obj:`None`. - - Hint: - This uses :func:`re.search` and not :func:`re.match`. - - .. versionadded:: 21.10 - - Returns: - tuple[:class:`Job`]: Tuple of all *scheduled* jobs. - """ - jobs_generator: Iterable[Job] = ( - Job.from_aps_job(job) for job in self.scheduler.get_jobs() - ) - if pattern is None: - return tuple(jobs_generator) - return tuple( - job for job in jobs_generator if (job.name and re.compile(pattern).search(job.name)) - ) - - def get_jobs_by_name(self, name: str) -> tuple["Job[CCT]", ...]: - """Returns a tuple of all *scheduled* jobs with the given name that are currently - in the :class:`JobQueue`. - - Hint: - This method is a convenience wrapper for :meth:`jobs` with a pattern that matches the - given name. - - Returns: - tuple[:class:`Job`]: Tuple of all *scheduled* jobs matching the name. - """ - return self.jobs(f"^{re.escape(name)}$") - - -class Job(Generic[CCT]): - """This class is a convenience wrapper for the jobs held in a :class:`telegram.ext.JobQueue`. - With the current backend APScheduler, :attr:`job` holds a :class:`apscheduler.job.Job` - instance. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :class:`id ` is equal. - - This class is a :class:`~typing.Generic` class and accepts one type variable that specifies - the type of the argument ``context`` of :paramref:`callback`. - - Important: - If you want to use this class, you must install PTB with the optional requirement - ``job-queue``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[job-queue]" - - Note: - All attributes and instance methods of :attr:`job` are also directly available as - attributes/methods of the corresponding :class:`telegram.ext.Job` object. - - Warning: - This class should not be instantiated manually. - Use the methods of :class:`telegram.ext.JobQueue` to schedule jobs. - - .. seealso:: :wiki:`Job Queue ` - - .. versionchanged:: 20.0 - - * Removed argument and attribute ``job_queue``. - * Renamed ``Job.context`` to :attr:`Job.data`. - * Removed argument ``job`` - * To use this class, PTB must be installed via - ``pip install "python-telegram-bot[job-queue]"``. - - Args: - callback (:term:`coroutine function`): The callback function that should be executed by the - new job. Callback signature:: - - async def callback(context: CallbackContext) - - data (:obj:`object`, optional): Additional data needed for the :paramref:`callback` - function. Can be accessed through :attr:`Job.data` in the callback. Defaults to - :obj:`None`. - name (:obj:`str`, optional): The name of the new job. Defaults to - :external:obj:`callback.__name__ `. - chat_id (:obj:`int`, optional): Chat id of the chat that this job is associated with. - - .. versionadded:: 20.0 - user_id (:obj:`int`, optional): User id of the user that this job is associated with. - - .. versionadded:: 20.0 - Attributes: - callback (:term:`coroutine function`): The callback function that should be executed by the - new job. - data (:obj:`object`): Optional. Additional data needed for the :attr:`callback` function. - name (:obj:`str`): Optional. The name of the new job. - chat_id (:obj:`int`): Optional. Chat id of the chat that this job is associated with. - - .. versionadded:: 20.0 - user_id (:obj:`int`): Optional. User id of the user that this job is associated with. - - .. versionadded:: 20.0 - """ - - __slots__ = ( - "_enabled", - "_job", - "_removed", - "callback", - "chat_id", - "data", - "name", - "user_id", - ) - - def __init__( - self, - callback: JobCallback[CCT], - data: Optional[object] = None, - name: Optional[str] = None, - chat_id: Optional[int] = None, - user_id: Optional[int] = None, - ): - if not APS_AVAILABLE: - raise RuntimeError( - "To use `Job`, PTB must be installed via `pip install " - '"python-telegram-bot[job-queue]"`.' - ) - - self.callback: JobCallback[CCT] = callback - self.data: Optional[object] = data - self.name: Optional[str] = name or callback.__name__ - self.chat_id: Optional[int] = chat_id - self.user_id: Optional[int] = user_id - - self._removed = False - self._enabled = False - - self._job = cast("APSJob", None) - - def __getattr__(self, item: str) -> object: - """Overrides :py:meth:`object.__getattr__` to get specific attribute of the - :class:`telegram.ext.Job` object or of its attribute :class:`apscheduler.job.Job`, - if exists. - - Args: - item (:obj:`str`): The name of the attribute. - - Returns: - :object: The value of the attribute. - - Raises: - :exc:`AttributeError`: If the attribute does not exist in both - :class:`telegram.ext.Job` and :class:`apscheduler.job.Job` objects. - """ - try: - return getattr(self.job, item) - except AttributeError as exc: - raise AttributeError( - f"Neither 'telegram.ext.Job' nor 'apscheduler.job.Job' has attribute '{item}'" - ) from exc - - def __eq__(self, other: object) -> bool: - """Defines equality condition for the :class:`telegram.ext.Job` object. - Two objects of this class are considered to be equal if their - :class:`id ` are equal. - - Returns: - :obj:`True` if both objects have :paramref:`id` parameters identical. - :obj:`False` otherwise. - """ - if isinstance(other, self.__class__): - return self.id == other.id - return False - - def __hash__(self) -> int: - """Builds a hash value for this object such that the hash of two objects is - equal if and only if the objects are equal in terms of :meth:`__eq__`. - - Returns: - :obj:`int`: The hash value of the object. - """ - return hash(self.id) - - def __repr__(self) -> str: - """Give a string representation of the job in the form - ``Job[id=..., name=..., callback=..., trigger=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs( - self, - id=self.job.id, - name=self.name, - callback=self.callback.__name__, - trigger=self.job.trigger, - ) - - @property - def job(self) -> "APSJob": - """:class:`apscheduler.job.Job`: The APS Job this job is a wrapper for. - - .. versionchanged:: 20.0 - This property is now read-only. - """ - return self._job - - @property - def removed(self) -> bool: - """:obj:`bool`: Whether this job is due to be removed.""" - return self._removed - - @property - def enabled(self) -> bool: - """:obj:`bool`: Whether this job is enabled.""" - return self._enabled - - @enabled.setter - def enabled(self, status: bool) -> None: - if status: - self.job.resume() - else: - self.job.pause() - self._enabled = status - - @property - def next_t(self) -> Optional[dtm.datetime]: - """ - :class:`datetime.datetime`: Datetime for the next job execution. - Datetime is localized according to :attr:`datetime.datetime.tzinfo`. - If job is removed or already ran it equals to :obj:`None`. - - Warning: - This attribute is only available, if the :class:`telegram.ext.JobQueue` this job - belongs to is already started. Otherwise APScheduler raises an :exc:`AttributeError`. - """ - return self.job.next_run_time - - @classmethod - def from_aps_job(cls, aps_job: "APSJob") -> "Job[CCT]": - """Provides the :class:`telegram.ext.Job` that is associated with the given APScheduler - job. - - Tip: - This method can be useful when using advanced APScheduler features along with - :class:`telegram.ext.JobQueue`. - - .. versionadded:: 20.4 - - Args: - aps_job (:class:`apscheduler.job.Job`): The APScheduler job - - Returns: - :class:`telegram.ext.Job` - """ - ext_job = aps_job.args[1] - ext_job._job = aps_job # pylint: disable=protected-access - return ext_job - - async def run( - self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]" - ) -> None: - """Executes the callback function independently of the jobs schedule. Also calls - :meth:`telegram.ext.Application.update_persistence`. - - .. versionchanged:: 20.0 - Calls :meth:`telegram.ext.Application.update_persistence`. - - Args: - application (:class:`telegram.ext.Application`): The application this job is associated - with. - """ - # We shield the task such that the job isn't cancelled mid-run - await asyncio.shield(self._run(application)) - - async def _run( - self, application: "Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]" - ) -> None: - try: - try: - context = application.context_types.context.from_job(self, application) - except Exception as exc: - _LOGGER.critical( - "Error while building CallbackContext for job %s. Job will not be run.", - self._job, - exc_info=exc, - ) - return - - await context.refresh_data() - await self.callback(context) - except Exception as exc: - await application.create_task( - application.process_error(None, exc, job=self), - name=f"Job:{self.id}:run:process_error", - ) - finally: - # This is internal logic of application - let's keep it private for now - application._mark_for_persistence_update(job=self) # pylint: disable=protected-access - - def schedule_removal(self) -> None: - """ - Schedules this job for removal from the :class:`JobQueue`. It will be removed without - executing its callback function again. - """ - self.job.remove() - self._removed = True diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_picklepersistence.py b/venv/lib/python3.11/site-packages/telegram/ext/_picklepersistence.py deleted file mode 100755 index c2f4c01..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_picklepersistence.py +++ /dev/null @@ -1,562 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PicklePersistence class.""" -import pickle -from copy import deepcopy -from pathlib import Path -from typing import Any, Callable, Optional, TypeVar, Union, cast, overload - -from telegram import Bot, TelegramObject -from telegram._utils.types import FilePathInput -from telegram._utils.warnings import warn -from telegram.ext import BasePersistence, PersistenceInput -from telegram.ext._contexttypes import ContextTypes -from telegram.ext._utils.types import BD, CD, UD, CDCData, ConversationDict, ConversationKey - -_REPLACED_KNOWN_BOT = "a known bot replaced by PTB's PicklePersistence" -_REPLACED_UNKNOWN_BOT = "an unknown bot replaced by PTB's PicklePersistence" - -TelegramObj = TypeVar("TelegramObj", bound=TelegramObject) - - -def _all_subclasses(cls: type[TelegramObj]) -> set[type[TelegramObj]]: - """Gets all subclasses of the specified object, recursively. from - https://stackoverflow.com/a/3862957/9706202 - """ - subclasses = cls.__subclasses__() - return set(subclasses).union([s for c in subclasses for s in _all_subclasses(c)]) - - -def _reconstruct_to(cls: type[TelegramObj], kwargs: dict) -> TelegramObj: - """ - This method is used for unpickling. The data, which is in the form a dictionary, is - converted back into a class. Works mostly the same as :meth:`TelegramObject.__setstate__`. - This function should be kept in place for backwards compatibility even if the pickling logic - is changed, since `_custom_reduction` places references to this function into the pickled data. - """ - obj = cls.__new__(cls) - obj.__setstate__(kwargs) - return obj - - -def _custom_reduction(cls: TelegramObj) -> tuple[Callable, tuple[type[TelegramObj], dict]]: - """ - This method is used for pickling. The bot attribute is preserved so _BotPickler().persistent_id - works as intended. - """ - data = cls._get_attrs(include_private=True) # pylint: disable=protected-access - # MappingProxyType is not pickable, so we convert it to a dict - # no need to convert back to MPT in _reconstruct_to, since it's done in __setstate__ - data["api_kwargs"] = dict(data["api_kwargs"]) # type: ignore[arg-type] - return _reconstruct_to, (cls.__class__, data) - - -class _BotPickler(pickle.Pickler): - __slots__ = ("_bot",) - - def __init__(self, bot: Bot, *args: Any, **kwargs: Any): - self._bot = bot - super().__init__(*args, **kwargs) - - def reducer_override( - self, obj: TelegramObj - ) -> tuple[Callable, tuple[type[TelegramObj], dict]]: - """ - This method is used for pickling. The bot attribute is preserved so - _BotPickler().persistent_id works as intended. - """ - if not isinstance(obj, TelegramObject): - return NotImplemented - - return _custom_reduction(obj) - - def persistent_id(self, obj: object) -> Optional[str]: - """Used to 'mark' the Bot, so it can be replaced later. See - https://docs.python.org/3/library/pickle.html#pickle.Pickler.persistent_id for more info - """ - if obj is self._bot: - return _REPLACED_KNOWN_BOT - if isinstance(obj, Bot): - warn( - "Unknown bot instance found. Will be replaced by `None` during unpickling", - stacklevel=2, - ) - return _REPLACED_UNKNOWN_BOT - return None # pickles as usual - - -class _BotUnpickler(pickle.Unpickler): - __slots__ = ("_bot",) - - def __init__(self, bot: Bot, *args: Any, **kwargs: Any): - self._bot = bot - super().__init__(*args, **kwargs) - - def persistent_load(self, pid: str) -> Optional[Bot]: - """Replaces the bot with the current bot if known, else it is replaced by :obj:`None`.""" - if pid == _REPLACED_KNOWN_BOT: - return self._bot - if pid == _REPLACED_UNKNOWN_BOT: - return None - raise pickle.UnpicklingError("Found unknown persistent id when unpickling!") - - -class PicklePersistence(BasePersistence[UD, CD, BD]): - """Using python's builtin :mod:`pickle` for making your bot persistent. - - Attention: - The interface provided by this class is intended to be accessed exclusively by - :class:`~telegram.ext.Application`. Calling any of the methods below manually might - interfere with the integration of persistence into :class:`~telegram.ext.Application`. - - Note: - This implementation of :class:`BasePersistence` uses the functionality of the pickle module - to support serialization of bot instances. Specifically any reference to - :attr:`~BasePersistence.bot` will be replaced by a placeholder before pickling and - :attr:`~BasePersistence.bot` will be inserted back when loading the data. - - Examples: - :any:`Persistent Conversation Bot ` - - .. seealso:: :wiki:`Making Your Bot Persistent ` - - .. versionchanged:: 20.0 - - * The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`. - * The parameter and attribute ``filename`` were replaced by :attr:`filepath`. - * :attr:`filepath` now also accepts :obj:`pathlib.Path` as argument. - - Args: - filepath (:obj:`str` | :obj:`pathlib.Path`): The filepath for storing the pickle files. - When :attr:`single_file` is :obj:`False` this will be used as a prefix. - store_data (:class:`~telegram.ext.PersistenceInput`, optional): Specifies which kinds of - data will be saved by this persistence instance. By default, all available kinds of - data will be saved. - single_file (:obj:`bool`, optional): When :obj:`False` will store 5 separate files of - `filename_user_data`, `filename_bot_data`, `filename_chat_data`, - `filename_callback_data` and `filename_conversations`. Default is :obj:`True`. - on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when - :meth:`flush` is called and keep data in memory until that happens. When - :obj:`False` will store data on any transaction *and* on call to :meth:`flush`. - Default is :obj:`False`. - context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance - of :class:`telegram.ext.ContextTypes` to customize the types used in the - ``context`` interface. If not passed, the defaults documented in - :class:`telegram.ext.ContextTypes` will be used. - - .. versionadded:: 13.6 - update_interval (:obj:`int` | :obj:`float`, optional): The - :class:`~telegram.ext.Application` will update - the persistence in regular intervals. This parameter specifies the time (in seconds) to - wait between two consecutive runs of updating the persistence. Defaults to 60 seconds. - - .. versionadded:: 20.0 - Attributes: - filepath (:obj:`str` | :obj:`pathlib.Path`): The filepath for storing the pickle files. - When :attr:`single_file` is :obj:`False` this will be used as a prefix. - store_data (:class:`~telegram.ext.PersistenceInput`): Specifies which kinds of data will - be saved by this persistence instance. - single_file (:obj:`bool`): Optional. When :obj:`False` will store 5 separate files of - `filename_user_data`, `filename_bot_data`, `filename_chat_data`, - `filename_callback_data` and `filename_conversations`. Default is :obj:`True`. - on_flush (:obj:`bool`): Optional. When :obj:`True` will only save to file when - :meth:`flush` is called and keep data in memory until that happens. When - :obj:`False` will store data on any transaction *and* on call to :meth:`flush`. - Default is :obj:`False`. - context_types (:class:`telegram.ext.ContextTypes`): Container for the types used - in the ``context`` interface. - - .. versionadded:: 13.6 - """ - - __slots__ = ( - "bot_data", - "callback_data", - "chat_data", - "context_types", - "conversations", - "filepath", - "on_flush", - "single_file", - "user_data", - ) - - @overload - def __init__( - self: "PicklePersistence[dict[Any, Any], dict[Any, Any], dict[Any, Any]]", - filepath: FilePathInput, - store_data: Optional[PersistenceInput] = None, - single_file: bool = True, - on_flush: bool = False, - update_interval: float = 60, - ): ... - - @overload - def __init__( - self: "PicklePersistence[UD, CD, BD]", - filepath: FilePathInput, - store_data: Optional[PersistenceInput] = None, - single_file: bool = True, - on_flush: bool = False, - update_interval: float = 60, - context_types: Optional[ContextTypes[Any, UD, CD, BD]] = None, - ): ... - - def __init__( - self, - filepath: FilePathInput, - store_data: Optional[PersistenceInput] = None, - single_file: bool = True, - on_flush: bool = False, - update_interval: float = 60, - context_types: Optional[ContextTypes[Any, UD, CD, BD]] = None, - ): - super().__init__(store_data=store_data, update_interval=update_interval) - self.filepath: Path = Path(filepath) - self.single_file: Optional[bool] = single_file - self.on_flush: Optional[bool] = on_flush - self.user_data: Optional[dict[int, UD]] = None - self.chat_data: Optional[dict[int, CD]] = None - self.bot_data: Optional[BD] = None - self.callback_data: Optional[CDCData] = None - self.conversations: Optional[dict[str, dict[tuple[Union[int, str], ...], object]]] = None - self.context_types: ContextTypes[Any, UD, CD, BD] = cast( - ContextTypes[Any, UD, CD, BD], context_types or ContextTypes() - ) - - def _load_singlefile(self) -> None: - try: - with self.filepath.open("rb") as file: - data = _BotUnpickler(self.bot, file).load() - - self.user_data = data["user_data"] - self.chat_data = data["chat_data"] - # For backwards compatibility with files not containing bot data - self.bot_data = data.get("bot_data", self.context_types.bot_data()) - self.callback_data = data.get("callback_data", {}) - self.conversations = data["conversations"] - except OSError: - self.conversations = {} - self.user_data = {} - self.chat_data = {} - self.bot_data = self.context_types.bot_data() - self.callback_data = None - except pickle.UnpicklingError as exc: - filename = self.filepath.name - raise TypeError(f"File {filename} does not contain valid pickle data") from exc - except Exception as exc: - raise TypeError(f"Something went wrong unpickling {self.filepath.name}") from exc - - def _load_file(self, filepath: Path) -> Any: - try: - with filepath.open("rb") as file: - return _BotUnpickler(self.bot, file).load() - - except OSError: - return None - except pickle.UnpicklingError as exc: - raise TypeError(f"File {filepath.name} does not contain valid pickle data") from exc - except Exception as exc: - raise TypeError(f"Something went wrong unpickling {filepath.name}") from exc - - def _dump_singlefile(self) -> None: - data = { - "conversations": self.conversations, - "user_data": self.user_data, - "chat_data": self.chat_data, - "bot_data": self.bot_data, - "callback_data": self.callback_data, - } - with self.filepath.open("wb") as file: - _BotPickler(self.bot, file, protocol=pickle.HIGHEST_PROTOCOL).dump(data) - - def _dump_file(self, filepath: Path, data: object) -> None: - with filepath.open("wb") as file: - _BotPickler(self.bot, file, protocol=pickle.HIGHEST_PROTOCOL).dump(data) - - async def get_user_data(self) -> dict[int, UD]: - """Returns the user_data from the pickle file if it exists or an empty :obj:`dict`. - - Returns: - dict[:obj:`int`, :obj:`dict`]: The restored user data. - """ - if self.user_data: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_user_data")) - if not data: - data = {} - self.user_data = data - else: - self._load_singlefile() - return deepcopy(self.user_data) # type: ignore[arg-type] - - async def get_chat_data(self) -> dict[int, CD]: - """Returns the chat_data from the pickle file if it exists or an empty :obj:`dict`. - - Returns: - dict[:obj:`int`, :obj:`dict`]: The restored chat data. - """ - if self.chat_data: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_chat_data")) - if not data: - data = {} - self.chat_data = data - else: - self._load_singlefile() - return deepcopy(self.chat_data) # type: ignore[arg-type] - - async def get_bot_data(self) -> BD: - """Returns the bot_data from the pickle file if it exists or an empty object of type - :obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`. - - Returns: - :obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`: The restored bot data. - """ - if self.bot_data: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_bot_data")) - if not data: - data = self.context_types.bot_data() - self.bot_data = data - else: - self._load_singlefile() - return deepcopy(self.bot_data) # type: ignore[return-value] - - async def get_callback_data(self) -> Optional[CDCData]: - """Returns the callback data from the pickle file if it exists or :obj:`None`. - - .. versionadded:: 13.6 - - Returns: - tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], - dict[:obj:`str`, :obj:`str`]] | :obj:`None`: The restored metadata or :obj:`None`, - if no data was stored. - """ - if self.callback_data: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_callback_data")) - if not data: - data = None - self.callback_data = data - else: - self._load_singlefile() - if self.callback_data is None: - return None - return deepcopy(self.callback_data) - - async def get_conversations(self, name: str) -> ConversationDict: - """Returns the conversations from the pickle file if it exists or an empty dict. - - Args: - name (:obj:`str`): The handlers name. - - Returns: - :obj:`dict`: The restored conversations for the handler. - """ - if self.conversations: - pass - elif not self.single_file: - data = self._load_file(Path(f"{self.filepath}_conversations")) - if not data: - data = {name: {}} - self.conversations = data - else: - self._load_singlefile() - return self.conversations.get(name, {}).copy() # type: ignore[union-attr] - - async def update_conversation( - self, name: str, key: ConversationKey, new_state: Optional[object] - ) -> None: - """Will update the conversations for the given handler and depending on :attr:`on_flush` - save the pickle file. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:class:`object`): The new state for the given key. - """ - if not self.conversations: - self.conversations = {} - if self.conversations.setdefault(name, {}).get(key) == new_state: - return - self.conversations[name][key] = new_state - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_conversations"), self.conversations) - else: - self._dump_singlefile() - - async def update_user_data(self, user_id: int, data: UD) -> None: - """Will update the user_data and depending on :attr:`on_flush` save the pickle file. - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.Application.user_data` ``[user_id]``. - """ - if self.user_data is None: - self.user_data = {} - if self.user_data.get(user_id) == data: - return - self.user_data[user_id] = data - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_user_data"), self.user_data) - else: - self._dump_singlefile() - - async def update_chat_data(self, chat_id: int, data: CD) -> None: - """Will update the chat_data and depending on :attr:`on_flush` save the pickle file. - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.Application.chat_data` ``[chat_id]``. - """ - if self.chat_data is None: - self.chat_data = {} - if self.chat_data.get(chat_id) == data: - return - self.chat_data[chat_id] = data - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_chat_data"), self.chat_data) - else: - self._dump_singlefile() - - async def update_bot_data(self, data: BD) -> None: - """Will update the bot_data and depending on :attr:`on_flush` save the pickle file. - - Args: - data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`): The - :attr:`telegram.ext.Application.bot_data`. - """ - if self.bot_data == data: - return - self.bot_data = data - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_bot_data"), self.bot_data) - else: - self._dump_singlefile() - - async def update_callback_data(self, data: CDCData) -> None: - """Will update the callback_data (if changed) and depending on :attr:`on_flush` save the - pickle file. - - .. versionadded:: 13.6 - - Args: - data (tuple[list[tuple[:obj:`str`, :obj:`float`, \ - dict[:obj:`str`, :class:`object`]]], dict[:obj:`str`, :obj:`str`]]): - The relevant data to restore :class:`telegram.ext.CallbackDataCache`. - """ - if self.callback_data == data: - return - self.callback_data = data - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_callback_data"), self.callback_data) - else: - self._dump_singlefile() - - async def drop_chat_data(self, chat_id: int) -> None: - """Will delete the specified key from the ``chat_data`` and depending on - :attr:`on_flush` save the pickle file. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`): The chat id to delete from the persistence. - """ - if self.chat_data is None: - return - self.chat_data.pop(chat_id, None) - - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_chat_data"), self.chat_data) - else: - self._dump_singlefile() - - async def drop_user_data(self, user_id: int) -> None: - """Will delete the specified key from the ``user_data`` and depending on - :attr:`on_flush` save the pickle file. - - .. versionadded:: 20.0 - - Args: - user_id (:obj:`int`): The user id to delete from the persistence. - """ - if self.user_data is None: - return - self.user_data.pop(user_id, None) - - if not self.on_flush: - if not self.single_file: - self._dump_file(Path(f"{self.filepath}_user_data"), self.user_data) - else: - self._dump_singlefile() - - async def refresh_user_data(self, user_id: int, user_data: UD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data` - """ - - async def refresh_chat_data(self, chat_id: int, chat_data: CD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data` - """ - - async def refresh_bot_data(self, bot_data: BD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data` - """ - - async def flush(self) -> None: - """Will save all data in memory to pickle file(s).""" - if self.single_file: - if ( - self.user_data - or self.chat_data - or self.bot_data - or self.callback_data - or self.conversations - ): - self._dump_singlefile() - else: - if self.user_data: - self._dump_file(Path(f"{self.filepath}_user_data"), self.user_data) - if self.chat_data: - self._dump_file(Path(f"{self.filepath}_chat_data"), self.chat_data) - if self.bot_data: - self._dump_file(Path(f"{self.filepath}_bot_data"), self.bot_data) - if self.callback_data: - self._dump_file(Path(f"{self.filepath}_callback_data"), self.callback_data) - if self.conversations: - self._dump_file(Path(f"{self.filepath}_conversations"), self.conversations) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_updater.py b/venv/lib/python3.11/site-packages/telegram/ext/_updater.py deleted file mode 100755 index 11c225c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_updater.py +++ /dev/null @@ -1,904 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the class Updater, which tries to make creating Telegram bots intuitive.""" - -import asyncio -import contextlib -import ssl -from collections.abc import Coroutine, Sequence -from pathlib import Path -from types import TracebackType -from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union - -from telegram._utils.defaultvalue import DEFAULT_80, DEFAULT_IP, DEFAULT_NONE, DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.types import DVType, ODVInput -from telegram.error import InvalidToken, RetryAfter, TelegramError, TimedOut - -try: - from telegram.ext._utils.webhookhandler import WebhookAppClass, WebhookServer - - WEBHOOKS_AVAILABLE = True -except ImportError: - WEBHOOKS_AVAILABLE = False - -if TYPE_CHECKING: - from socket import socket - - from telegram import Bot - - -_UpdaterType = TypeVar("_UpdaterType", bound="Updater") # pylint: disable=invalid-name -_LOGGER = get_logger(__name__) - - -class Updater(contextlib.AbstractAsyncContextManager["Updater"]): - """This class fetches updates for the bot either via long polling or by starting a webhook - server. Received updates are enqueued into the :attr:`update_queue` and may be fetched from - there to handle them appropriately. - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with updater: - # code - - is roughly equivalent to - - .. code:: python - - try: - await updater.initialize() - # code - finally: - await updater.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Builder Pattern ` - - .. versionchanged:: 20.0 - - * Removed argument and attribute ``user_sig_handler`` - * The only arguments and attributes are now :attr:`bot` and :attr:`update_queue` as now - the sole purpose of this class is to fetch updates. The entry point to a PTB application - is now :class:`telegram.ext.Application`. - - Args: - bot (:class:`telegram.Bot`): The bot used with this Updater. - update_queue (:class:`asyncio.Queue`): Queue for the updates. - - Attributes: - bot (:class:`telegram.Bot`): The bot used with this Updater. - update_queue (:class:`asyncio.Queue`): Queue for the updates. - - """ - - __slots__ = ( - "__lock", - "__polling_cleanup_cb", - "__polling_task", - "__polling_task_stop_event", - "_httpd", - "_initialized", - "_last_update_id", - "_running", - "bot", - "update_queue", - ) - - def __init__( - self, - bot: "Bot", - update_queue: "asyncio.Queue[object]", - ): - self.bot: Bot = bot - self.update_queue: asyncio.Queue[object] = update_queue - - self._last_update_id = 0 - self._running = False - self._initialized = False - self._httpd: Optional[WebhookServer] = None - self.__lock = asyncio.Lock() - self.__polling_task: Optional[asyncio.Task] = None - self.__polling_task_stop_event: asyncio.Event = asyncio.Event() - self.__polling_cleanup_cb: Optional[Callable[[], Coroutine[Any, Any, None]]] = None - - async def __aenter__(self: _UpdaterType) -> _UpdaterType: # noqa: PYI019 - """ - |async_context_manager| :meth:`initializes ` the Updater. - - Returns: - The initialized Updater instance. - - Raises: - :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. - """ - try: - await self.initialize() - except Exception: - await self.shutdown() - raise - return self - - async def __aexit__( - self, - exc_type: Optional[type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - """|async_context_manager| :meth:`shuts down ` the Updater.""" - # Make sure not to return `True` so that exceptions are not suppressed - # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ - await self.shutdown() - - def __repr__(self) -> str: - """Give a string representation of the updater in the form ``Updater[bot=...]``. - - As this class doesn't implement :meth:`object.__str__`, the default implementation - will be used, which is equivalent to :meth:`__repr__`. - - Returns: - :obj:`str` - """ - return build_repr_with_selected_attrs(self, bot=self.bot) - - @property - def running(self) -> bool: - return self._running - - async def initialize(self) -> None: - """Initializes the Updater & the associated :attr:`bot` by calling - :meth:`telegram.Bot.initialize`. - - .. seealso:: - :meth:`shutdown` - """ - if self._initialized: - _LOGGER.debug("This Updater is already initialized.") - return - - await self.bot.initialize() - self._initialized = True - - async def shutdown(self) -> None: - """ - Shutdown the Updater & the associated :attr:`bot` by calling :meth:`telegram.Bot.shutdown`. - - .. seealso:: - :meth:`initialize` - - Raises: - :exc:`RuntimeError`: If the updater is still running. - """ - if self.running: - raise RuntimeError("This Updater is still running!") - - if not self._initialized: - _LOGGER.debug("This Updater is already shut down. Returning.") - return - - await self.bot.shutdown() - self._initialized = False - _LOGGER.debug("Shut down of Updater complete") - - async def start_polling( - self, - poll_interval: float = 0.0, - timeout: int = 10, # noqa: ASYNC109 - bootstrap_retries: int = -1, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - allowed_updates: Optional[Sequence[str]] = None, - drop_pending_updates: Optional[bool] = None, - error_callback: Optional[Callable[[TelegramError], None]] = None, - ) -> "asyncio.Queue[object]": - """Starts polling updates from Telegram. - - .. versionchanged:: 20.0 - Removed the ``clean`` argument in favor of :paramref:`drop_pending_updates`. - - Args: - poll_interval (:obj:`float`, optional): Time to wait between polling updates from - Telegram in seconds. Default is ``0.0``. - timeout (:obj:`int`, optional): Passed to - :paramref:`telegram.Bot.get_updates.timeout`. Defaults to ``10`` seconds. - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely (default) - * 0 - no retries - * > 0 - retry up to X times - read_timeout (:obj:`float`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.read_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. versionchanged:: 20.7 - Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE` instead of - ``2``. - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_read_timeout` or - :paramref:`telegram.Bot.get_updates_request`. - write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.write_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_write_timeout` or - :paramref:`telegram.Bot.get_updates_request`. - connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.connect_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_connect_timeout` or - :paramref:`telegram.Bot.get_updates_request`. - pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.Bot.get_updates.pool_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. deprecated:: 20.7 - Deprecated in favor of setting the timeout via - :meth:`telegram.ext.ApplicationBuilder.get_updates_pool_timeout` or - :paramref:`telegram.Bot.get_updates_request`. - allowed_updates (Sequence[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.get_updates`. - - .. versionchanged:: 21.9 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - - .. versionadded :: 13.4 - error_callback (Callable[[:exc:`telegram.error.TelegramError`], :obj:`None`], \ - optional): Callback to handle :exc:`telegram.error.TelegramError` s that occur - while calling :meth:`telegram.Bot.get_updates` during polling. Defaults to - :obj:`None`, in which case errors will be logged. Callback signature:: - - def callback(error: telegram.error.TelegramError) - - Note: - The :paramref:`error_callback` must *not* be a :term:`coroutine function`! If - asynchronous behavior of the callback is wanted, please schedule a task from - within the callback. - - Returns: - :class:`asyncio.Queue`: The update queue that can be filled from the main thread. - - Raises: - :exc:`RuntimeError`: If the updater is already running or was not initialized. - - """ - # We refrain from issuing deprecation warnings for the timeout parameters here, as we - # already issue them in `Application`. This means that there are no warnings when using - # `Updater` without `Application`, but this is a rather special use case. - - if error_callback and asyncio.iscoroutinefunction(error_callback): - raise TypeError( - "The `error_callback` must not be a coroutine function! Use an ordinary function " - "instead. " - ) - - async with self.__lock: - if self.running: - raise RuntimeError("This Updater is already running!") - if not self._initialized: - raise RuntimeError("This Updater was not initialized via `Updater.initialize`!") - - self._running = True - - try: - # Create & start tasks - polling_ready = asyncio.Event() - - await self._start_polling( - poll_interval=poll_interval, - timeout=timeout, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - bootstrap_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - allowed_updates=allowed_updates, - ready=polling_ready, - error_callback=error_callback, - ) - - _LOGGER.debug("Waiting for polling to start") - await polling_ready.wait() - _LOGGER.debug("Polling updates from Telegram started") - except Exception: - self._running = False - raise - return self.update_queue - - async def _start_polling( - self, - poll_interval: float, - timeout: int, # noqa: ASYNC109 - read_timeout: ODVInput[float], - write_timeout: ODVInput[float], - connect_timeout: ODVInput[float], - pool_timeout: ODVInput[float], - bootstrap_retries: int, - drop_pending_updates: Optional[bool], - allowed_updates: Optional[Sequence[str]], - ready: asyncio.Event, - error_callback: Optional[Callable[[TelegramError], None]], - ) -> None: - _LOGGER.debug("Updater started (polling)") - - # the bootstrapping phase does two things: - # 1) make sure there is no webhook set - # 2) apply drop_pending_updates - await self._bootstrap( - bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url="", - allowed_updates=None, - ) - - _LOGGER.debug("Bootstrap done") - - async def polling_action_cb() -> bool: - try: - updates = await self.bot.get_updates( - offset=self._last_update_id, - timeout=timeout, - read_timeout=read_timeout, - connect_timeout=connect_timeout, - write_timeout=write_timeout, - pool_timeout=pool_timeout, - allowed_updates=allowed_updates, - ) - except TelegramError: - # TelegramErrors should be processed by the network retry loop - raise - except Exception as exc: - # Other exceptions should not. Let's log them for now. - _LOGGER.critical( - "Something went wrong processing the data received from Telegram. " - "Received data was *not* processed!", - exc_info=exc, - ) - return True - - if updates: - if not self.running: - _LOGGER.critical( - "Updater stopped unexpectedly. Pulled updates will be ignored and pulled " - "again on restart." - ) - else: - for update in updates: - await self.update_queue.put(update) - self._last_update_id = updates[-1].update_id + 1 # Add one to 'confirm' it - - return True # Keep fetching updates & don't quit. Polls with poll_interval. - - def default_error_callback(exc: TelegramError) -> None: - _LOGGER.exception("Exception happened while polling for updates.", exc_info=exc) - - # Start task that runs in background, pulls - # updates from Telegram and inserts them in the update queue of the - # Application. - self.__polling_task = asyncio.create_task( - self._network_loop_retry( - action_cb=polling_action_cb, - on_err_cb=error_callback or default_error_callback, - description="getting Updates", - interval=poll_interval, - stop_event=self.__polling_task_stop_event, - ), - name="Updater:start_polling:polling_task", - ) - - # Prepare a cleanup callback to await on _stop_polling - # Calling get_updates one more time with the latest `offset` parameter ensures that - # all updates that where put into the update queue are also marked as "read" to TG, - # so we do not receive them again on the next startup - # We define this here so that we can use the same parameters as in the polling task - async def _get_updates_cleanup() -> None: - _LOGGER.debug( - "Calling `get_updates` one more time to mark all fetched updates as read." - ) - try: - await self.bot.get_updates( - offset=self._last_update_id, - # We don't want to do long polling here! - timeout=0, - read_timeout=read_timeout, - connect_timeout=connect_timeout, - write_timeout=write_timeout, - pool_timeout=pool_timeout, - allowed_updates=allowed_updates, - ) - except TelegramError: - _LOGGER.exception( - "Error while calling `get_updates` one more time to mark all fetched updates " - "as read: %s. Suppressing error to ensure graceful shutdown. When polling for " - "updates is restarted, updates may be fetched again. Please adjust timeouts " - "via `ApplicationBuilder` or the parameter `get_updates_request` of `Bot`.", - ) - - self.__polling_cleanup_cb = _get_updates_cleanup - - if ready is not None: - ready.set() - - async def start_webhook( - self, - listen: DVType[str] = DEFAULT_IP, - port: DVType[int] = DEFAULT_80, - url_path: str = "", - cert: Optional[Union[str, Path]] = None, - key: Optional[Union[str, Path]] = None, - bootstrap_retries: int = 0, - webhook_url: Optional[str] = None, - allowed_updates: Optional[Sequence[str]] = None, - drop_pending_updates: Optional[bool] = None, - ip_address: Optional[str] = None, - max_connections: int = 40, - secret_token: Optional[str] = None, - unix: Optional[Union[str, Path, "socket"]] = None, - ) -> "asyncio.Queue[object]": - """ - Starts a small http server to listen for updates via webhook. If :paramref:`cert` - and :paramref:`key` are not provided, the webhook will be started directly on - ``http://listen:port/url_path``, so SSL can be handled by another - application. Else, the webhook will be started on - ``https://listen:port/url_path``. Also calls :meth:`telegram.Bot.set_webhook` as required. - - Important: - If you want to use this method, you must install PTB with the optional requirement - ``webhooks``, i.e. - - .. code-block:: bash - - pip install "python-telegram-bot[webhooks]" - - .. seealso:: :wiki:`Webhooks` - - .. versionchanged:: 13.4 - :meth:`start_webhook` now *always* calls :meth:`telegram.Bot.set_webhook`, so pass - ``webhook_url`` instead of calling ``updater.bot.set_webhook(webhook_url)`` manually. - .. versionchanged:: 20.0 - - * Removed the ``clean`` argument in favor of :paramref:`drop_pending_updates` and - removed the deprecated argument ``force_event_loop``. - - Args: - listen (:obj:`str`, optional): IP-Address to listen on. Defaults to - `127.0.0.1 `_. - port (:obj:`int`, optional): Port the bot should be listening on. Must be one of - :attr:`telegram.constants.SUPPORTED_WEBHOOK_PORTS` unless the bot is running - behind a proxy. Defaults to ``80``. - url_path (:obj:`str`, optional): Path inside url (http(s)://listen:port/). - Defaults to ``''``. - cert (:class:`pathlib.Path` | :obj:`str`, optional): Path to the SSL certificate file. - key (:class:`pathlib.Path` | :obj:`str`, optional): Path to the SSL key file. - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - - .. versionadded :: 13.4 - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely - * 0 - no retries (default) - * > 0 - retry up to X times - webhook_url (:obj:`str`, optional): Explicitly specify the webhook url. Useful behind - NAT, reverse proxy, etc. Default is derived from :paramref:`listen`, - :paramref:`port`, :paramref:`url_path`, :paramref:`cert`, and :paramref:`key`. - ip_address (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`. - Defaults to :obj:`None`. - - .. versionadded :: 13.4 - allowed_updates (Sequence[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.set_webhook`. Defaults to :obj:`None`. - - .. versionchanged:: 21.9 - Accepts any :class:`collections.abc.Sequence` as input instead of just a list - max_connections (:obj:`int`, optional): Passed to - :meth:`telegram.Bot.set_webhook`. Defaults to ``40``. - - .. versionadded:: 13.6 - secret_token (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`. - Defaults to :obj:`None`. - - When added, the web server started by this call will expect the token to be set in - the ``X-Telegram-Bot-Api-Secret-Token`` header of an incoming request and will - raise a :class:`http.HTTPStatus.FORBIDDEN ` error if either the - header isn't set or it is set to a wrong token. - - .. versionadded:: 20.0 - unix (:class:`pathlib.Path` | :obj:`str` | :class:`socket.socket`, optional): Can be - either: - - * the path to the unix socket file as :class:`pathlib.Path` or :obj:`str`. This - will be passed to `tornado.netutil.bind_unix_socket `_ to create the socket. - If the Path does not exist, the file will be created. - - * or the socket itself. This option allows you to e.g. restrict the permissions of - the socket for improved security. Note that you need to pass the correct family, - type and socket options yourself. - - Caution: - This parameter is a replacement for the default TCP bind. Therefore, it is - mutually exclusive with :paramref:`listen` and :paramref:`port`. When using - this param, you must also run a reverse proxy to the unix socket and set the - appropriate :paramref:`webhook_url`. - - .. versionadded:: 20.8 - .. versionchanged:: 21.1 - Added support to pass a socket instance itself. - Returns: - :class:`queue.Queue`: The update queue that can be filled from the main thread. - - Raises: - :exc:`RuntimeError`: If the updater is already running or was not initialized. - """ - if not WEBHOOKS_AVAILABLE: - raise RuntimeError( - "To use `start_webhook`, PTB must be installed via `pip install " - '"python-telegram-bot[webhooks]"`.' - ) - # unix has special requirements what must and mustn't be set when using it - if unix: - error_msg = ( - "You can not pass unix and {0}, only use one. Unix if you want to " - "initialize a unix socket, or {0} for a standard TCP server." - ) - if not isinstance(listen, DefaultValue): - raise RuntimeError(error_msg.format("listen")) - if not isinstance(port, DefaultValue): - raise RuntimeError(error_msg.format("port")) - if not webhook_url: - raise RuntimeError( - "Since you set unix, you also need to set the URL to the webhook " - "of the proxy you run in front of the unix socket." - ) - - async with self.__lock: - if self.running: - raise RuntimeError("This Updater is already running!") - if not self._initialized: - raise RuntimeError("This Updater was not initialized via `Updater.initialize`!") - - self._running = True - - try: - # Create & start tasks - webhook_ready = asyncio.Event() - - await self._start_webhook( - listen=DefaultValue.get_value(listen), - port=DefaultValue.get_value(port), - url_path=url_path, - cert=cert, - key=key, - bootstrap_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url=webhook_url, - allowed_updates=allowed_updates, - ready=webhook_ready, - ip_address=ip_address, - max_connections=max_connections, - secret_token=secret_token, - unix=unix, - ) - - _LOGGER.debug("Waiting for webhook server to start") - await webhook_ready.wait() - _LOGGER.debug("Webhook server started") - except Exception: - self._running = False - raise - - # Return the update queue so the main thread can insert updates - return self.update_queue - - async def _start_webhook( - self, - listen: str, - port: int, - url_path: str, - bootstrap_retries: int, - allowed_updates: Optional[Sequence[str]], - cert: Optional[Union[str, Path]] = None, - key: Optional[Union[str, Path]] = None, - drop_pending_updates: Optional[bool] = None, - webhook_url: Optional[str] = None, - ready: Optional[asyncio.Event] = None, - ip_address: Optional[str] = None, - max_connections: int = 40, - secret_token: Optional[str] = None, - unix: Optional[Union[str, Path, "socket"]] = None, - ) -> None: - _LOGGER.debug("Updater thread started (webhook)") - - if not url_path.startswith("/"): - url_path = f"/{url_path}" - - # Create Tornado app instance - app = WebhookAppClass(url_path, self.bot, self.update_queue, secret_token) - - # Form SSL Context - # An SSLError is raised if the private key does not match with the certificate - # Note that we only use the SSL certificate for the WebhookServer, if the key is also - # present. This is because the WebhookServer may not actually be in charge of performing - # the SSL handshake, e.g. in case a reverse proxy is used - if cert is not None and key is not None: - try: - ssl_ctx: Optional[ssl.SSLContext] = ssl.create_default_context( - ssl.Purpose.CLIENT_AUTH - ) - ssl_ctx.load_cert_chain(cert, key) # type: ignore[union-attr] - except ssl.SSLError as exc: - raise TelegramError("Invalid SSL Certificate") from exc - else: - ssl_ctx = None - # Create and start server - self._httpd = WebhookServer(listen, port, app, ssl_ctx, unix) - - if not webhook_url: - webhook_url = self._gen_webhook_url( - protocol="https" if ssl_ctx else "http", - listen=DefaultValue.get_value(listen), - port=port, - url_path=url_path, - ) - - # We pass along the cert to the webhook if present. - await self._bootstrap( - # Passing a Path or string only works if the bot is running against a local bot API - # server, so let's read the contents - cert=Path(cert).read_bytes() if cert else None, - max_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url=webhook_url, - allowed_updates=allowed_updates, - ip_address=ip_address, - max_connections=max_connections, - secret_token=secret_token, - ) - - await self._httpd.serve_forever(ready=ready) - - @staticmethod - def _gen_webhook_url(protocol: str, listen: str, port: int, url_path: str) -> str: - # TODO: double check if this should be https in any case - the docs of start_webhook - # say differently! - return f"{protocol}://{listen}:{port}{url_path}" - - async def _network_loop_retry( - self, - action_cb: Callable[..., Coroutine], - on_err_cb: Callable[[TelegramError], None], - description: str, - interval: float, - stop_event: Optional[asyncio.Event], - ) -> None: - """Perform a loop calling `action_cb`, retrying after network errors. - - Stop condition for loop: `self.running` evaluates :obj:`False` or return value of - `action_cb` evaluates :obj:`False`. - - Args: - action_cb (:term:`coroutine function`): Network oriented callback function to call. - on_err_cb (:obj:`callable`): Callback to call when TelegramError is caught. Receives - the exception object as a parameter. - description (:obj:`str`): Description text to use for logs and exception raised. - interval (:obj:`float` | :obj:`int`): Interval to sleep between each call to - `action_cb`. - stop_event (:class:`asyncio.Event` | :obj:`None`): Event to wait on for stopping the - loop. Setting the event will make the loop exit even if `action_cb` is currently - running. - - """ - - async def do_action() -> bool: - if not stop_event: - return await action_cb() - - action_cb_task = asyncio.create_task(action_cb()) - stop_task = asyncio.create_task(stop_event.wait()) - done, pending = await asyncio.wait( - (action_cb_task, stop_task), return_when=asyncio.FIRST_COMPLETED - ) - with contextlib.suppress(asyncio.CancelledError): - for task in pending: - task.cancel() - - if stop_task in done: - _LOGGER.debug("Network loop retry %s was cancelled", description) - return False - - return action_cb_task.result() - - _LOGGER.debug("Start network loop retry %s", description) - cur_interval = interval - while self.running: - try: - if not await do_action(): - break - except RetryAfter as exc: - _LOGGER.info("%s", exc) - cur_interval = 0.5 + exc.retry_after - except TimedOut as toe: - _LOGGER.debug("Timed out %s: %s", description, toe) - # If failure is due to timeout, we should retry asap. - cur_interval = 0 - except InvalidToken: - _LOGGER.exception("Invalid token; aborting") - raise - except TelegramError as telegram_exc: - on_err_cb(telegram_exc) - - # increase waiting times on subsequent errors up to 30secs - cur_interval = 1 if cur_interval == 0 else min(30, 1.5 * cur_interval) - else: - cur_interval = interval - - if cur_interval: - await asyncio.sleep(cur_interval) - - async def _bootstrap( - self, - max_retries: int, - webhook_url: Optional[str], - allowed_updates: Optional[Sequence[str]], - drop_pending_updates: Optional[bool] = None, - cert: Optional[bytes] = None, - bootstrap_interval: float = 1, - ip_address: Optional[str] = None, - max_connections: int = 40, - secret_token: Optional[str] = None, - ) -> None: - """Prepares the setup for fetching updates: delete or set the webhook and drop pending - updates if appropriate. If there are unsuccessful attempts, this will retry as specified by - :paramref:`max_retries`. - """ - retries = 0 - - async def bootstrap_del_webhook() -> bool: - _LOGGER.debug("Deleting webhook") - if drop_pending_updates: - _LOGGER.debug("Dropping pending updates from Telegram server") - await self.bot.delete_webhook(drop_pending_updates=drop_pending_updates) - return False - - async def bootstrap_set_webhook() -> bool: - _LOGGER.debug("Setting webhook") - if drop_pending_updates: - _LOGGER.debug("Dropping pending updates from Telegram server") - await self.bot.set_webhook( - url=webhook_url, # type: ignore[arg-type] - certificate=cert, - allowed_updates=allowed_updates, - ip_address=ip_address, - drop_pending_updates=drop_pending_updates, - max_connections=max_connections, - secret_token=secret_token, - ) - return False - - def bootstrap_on_err_cb(exc: Exception) -> None: - # We need this since retries is an immutable object otherwise and the changes - # wouldn't propagate outside of thi function - nonlocal retries - - if not isinstance(exc, InvalidToken) and (max_retries < 0 or retries < max_retries): - retries += 1 - _LOGGER.warning( - "Failed bootstrap phase; try=%s max_retries=%s", retries, max_retries - ) - else: - _LOGGER.error("Failed bootstrap phase after %s retries (%s)", retries, exc) - raise exc - - # Dropping pending updates from TG can be efficiently done with the drop_pending_updates - # parameter of delete/start_webhook, even in the case of polling. Also, we want to make - # sure that no webhook is configured in case of polling, so we just always call - # delete_webhook for polling - if drop_pending_updates or not webhook_url: - await self._network_loop_retry( - bootstrap_del_webhook, - bootstrap_on_err_cb, - "bootstrap del webhook", - bootstrap_interval, - stop_event=None, - ) - - # Reset the retries counter for the next _network_loop_retry call - retries = 0 - - # Restore/set webhook settings, if needed. Again, we don't know ahead if a webhook is set, - # so we set it anyhow. - if webhook_url: - await self._network_loop_retry( - bootstrap_set_webhook, - bootstrap_on_err_cb, - "bootstrap set webhook", - bootstrap_interval, - stop_event=None, - ) - - async def stop(self) -> None: - """Stops the polling/webhook. - - .. seealso:: - :meth:`start_polling`, :meth:`start_webhook` - - Raises: - :exc:`RuntimeError`: If the updater is not running. - """ - async with self.__lock: - if not self.running: - raise RuntimeError("This Updater is not running!") - - _LOGGER.debug("Stopping Updater") - - self._running = False - - await self._stop_httpd() - await self._stop_polling() - - _LOGGER.debug("Updater.stop() is complete") - - async def _stop_httpd(self) -> None: - """Stops the Webhook server by calling ``WebhookServer.shutdown()``""" - if self._httpd: - _LOGGER.debug("Waiting for current webhook connection to be closed.") - await self._httpd.shutdown() - self._httpd = None - - async def _stop_polling(self) -> None: - """Stops the polling task by awaiting it.""" - if self.__polling_task: - _LOGGER.debug("Waiting background polling task to finish up.") - self.__polling_task_stop_event.set() - - with contextlib.suppress(asyncio.CancelledError): - await self.__polling_task - # It only fails in rare edge-cases, e.g. when `stop()` is called directly - # after start_polling(), but lets better be safe than sorry ... - - self.__polling_task = None - self.__polling_task_stop_event.clear() - - if self.__polling_cleanup_cb: - await self.__polling_cleanup_cb() - self.__polling_cleanup_cb = None - else: - _LOGGER.warning( - "No polling cleanup callback defined. The last fetched updates may be " - "fetched again on the next polling start." - ) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__init__.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__init__.py deleted file mode 100755 index da47adb..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index bf51ff950b6f89cf98fd9a14cc60959d5ee01c3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196 zcmZ3^%ge<81UIM5%2HrvV0aATzyKqZ@tF*nKP@rFynpdWulbNJnP+5|ZpJ%LRXsBPDS(2(-keHmEn4Vg! zUy_=WnqHKctDjm?q90#cl9^MiA0MBYmst`YuUAm{i^C>2KczG$)vkyYXb;FG#r#0x R12ZEd;|B&9Q3P}{0{~tIGME4W diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/_update_parsing.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/_update_parsing.cpython-311.pyc deleted file mode 100755 index ef1208225c9c2158cea06ed6900e4bbf60994721..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2116 zcmb_d&1)M+6ra(`-nA5e)Ywg}#LWcPO=QTf6Q^!4#&%E-Z31q=p(%z|9`BB%ZC1O> z?8;bshg6E4>{xy=pP^jLFj@Z&`Wz0_~ujJ>`JoafKPqeefxIa z$GkW1_g266_9hU}U%&kN?awkoe~XtUbv1;epFr3_23kf2Hewbo#+GAP$dV-$haa&e>kQG8i8b}GzoKht94Mc=;?$@Gvb2=B7sz1b zXH6sM=FBf~TZeORQ5+-*?gl(I(N>?|rr!tE^Oo@v@`Y`KHjyv98?+w-OSmKA1MN{Z zQ33Bm)aR|p5UC|2w24k@(|F^H+q%wN=noZD`ouJdBf4x^EQE#VTSF1SAgWH-=eV=M zY>)ZvHfmZ5dRm$wVFHdkpV~SLBk-^UrmnIlB1RQ=n(`#fg%uS(<1BWx2Q4f_n#o_z{&ql{T}P==Uy95 zL^cr_vCcl9jS5401o?e}Ix*N80X`)0jUP^s(yaMys5CWaVx?uIh7-2rbJK<46|>H$ zA*OR>WnpE7m^tEd=D|2dhKt8|q2rjvU`)Y%v;gcb!r@VWJ@Osi#Cx#vHW{Zz;7hcF zF?yUbFq9bM1K_a;1AUIOqO-LAy_?})Jo~R8^MClxdiOD7}LMJgYqlT5`S;pAVB= zOeX?4n}siFHXC&NWfvOC1yFXsRZpai|8`sVBCH9eUh#$KBd05}Bn+NYf6xWr73ZwC_EqX#-5V?ZtlYdw;(F zzxO#mba%@L+V30R&%XiGA8fMUk}cxt9U$%_3(X-*uwu4QiOt0XM#t@VB{7%abix)Z z$+;w_MO&(*=28NRA(A3p4+VrC!5g(X*-DZmNu1nYK$b*eR*EQvq}6pNF_(t@#Gy4A z*19ca2B~Rd62#1w${wz`R$vosx{hy@9S@g?T_qG30>|{rE-X-D8$PkH?_$`m5?FSM z*e?-WrEZZL73}$jxuD6irr||GJ>W7di&$f0_=EG>d0D<`PzQL%WDM;xC?byUVYdK6 z4h%3T0r{{6oJ?1q;J^cttx?CY?HbP4xLUiMrv|NI!?Ex=$Mw&(Hn@1;p&GtiGMpmu zn4Fh&00VQ@D_ewu_&g=X0&~c0u`sC>qlVczu)%W8paS-COSlH+d34xzi<s1y+!v6RM+WYi zDm62p6f(ti52{0$C1g<7nI>IVRjwwMZ*pV0J}p~F86u^b2$xvR=|;#Y1bh+47VW);1CaHht#FA zZ37@XM7Jz7Y>(u$_D%#U+_Jw4QGgqxv1l+CrXU<3-SDwjaswMu!=?af4#ieVZg4yv z3Q43X@49ww4Bspf;Gmo>ipGCungxD(>dUKB2I%J(++@IExOtt3Tx1S}Xu|V?N>p*c z=CaRG1(#D}*NZHhdf6$sY9c(Mcc3Ednp`#szkQ*kU%P(g%H)kuv`9WEs&Og-{%H!j zFb*O-b|b*P7qi)tTOrwsK}|P%)h)WCS)*FbE)r)k3o*=AYktXfMzxWVtXKBQa24vF z0d*$p6PvJ7m?g`8RuBBL?Pa5?SgnQK9fr}PpzJKX9))fVHP4___u6VB)3+Wp6O!1! zmwD>}+5BQBGgQwEZKsBw?zcev zp`QNrVE^|VT2lcLFnWEU_Up`X^qo8*#Wzn)#NxlkL?An=4~qz|KF@%-|5DAFZ&#rC zcBSe3G`+sYJOo*f;Emdfu)w)#%o1jxlFhek6uoqKw)#J7-@3%=tQw!5ol-^0f)FMP zIx9$_V!FJXIIMU}lz6Va2vxkG=K%<6>;P6C^9*C!3jcb@{`Ekn14{*;vU$-CF; z=`%ah*}8Q0u{69Z4ev*Ai0xhHO< z>pg=zidt9H$I8gAGP0wL)|Jt%#a-p%wsNs??8Lnfn-WrbTD;8^O82gR^b~ZXY4r%) z2pv9bx*kfc@(}qc`taHEC`&|`1RAa#W#6Ij#6G~a2;3U`jo{q(2O diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/trackingdict.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/trackingdict.cpython-311.pyc deleted file mode 100755 index b74b8f83f7bf4266f8c94f4d4b18de440c3817db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6929 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/types.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/types.cpython-311.pyc deleted file mode 100755 index 25d0c26330b4db8a05555febbebe26cb811b22bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2248 zcmbVMyKmb@80SNz9@bla$aWetPLozaBGz#1AV!ncmQ%ZVwXu~3WndVTc$S&)Asne7 z%2234hm0NyR46iNC{h>g;L$^e{s}a|!R2J2Q#S$GGW9!&s%04gijv0zx#MU z$6^r*om621r3%+i2AofMzgfMXi z@yC%*?C=9+Y@Nzw=Od9vGB&_+AtJz2fGEhYEy3Ip?7rwSMuJLI;3?RqP(nh@ zf+@kUA!}M)DAmCO37T5MGOi1@I^n?w=Y_(yY*dg%;tb{h2eK1ORS<^o zC5+^!WE*AQg+$fmx4Ui@Co zmP;DCCszqWInIj}zy9*pW?}VK;m+sxS3GvnsC%ITY>Jq9!D79NzLK%WJv4y49PNd^ zsM>@^4d(2UY3Eoku>>ry$u_#H>MBs;C5V4XEepvgL5S2B-}658$hYIMRD8Ik*LeKY>Kzdia9Gn8;Q@5 z@l1ry7prx9+cakLGc%$EeQ>1;9Uw!mi#<+6;6&VnPSgN{#=<lfCSwuQU>enR6|1Z{C@{?q(JoD%oZNP*0Q^O6~-99yVuNT+7}q>}7UW zfBMFmoO4I!-Q>0X;r;R-v-{h>pLLQeZe+C)Y%?6V#riUl1rYD_Kzh diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/webhookhandler.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/ext/_utils/__pycache__/webhookhandler.cpython-311.pyc deleted file mode 100755 index a856b72c6f5636b6399d880fac10727f5a0ff4d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11323 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 diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/_update_parsing.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/_update_parsing.py deleted file mode 100755 index 2d62a6b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/_update_parsing.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions related to parsing updates and their contents. - -.. versionadded:: 20.8 - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from typing import Optional - -from telegram._utils.types import SCT - - -def parse_chat_id(chat_id: Optional[SCT[int]]) -> frozenset[int]: - """Accepts a chat id or collection of chat ids and returns a frozenset of chat ids.""" - if chat_id is None: - return frozenset() - if isinstance(chat_id, int): - return frozenset({chat_id}) - return frozenset(chat_id) - - -def parse_username(username: Optional[SCT[str]]) -> frozenset[str]: - """Accepts a username or collection of usernames and returns a frozenset of usernames. - Strips the leading ``@`` if present. - """ - if username is None: - return frozenset() - if isinstance(username, str): - return frozenset({username.removeprefix("@")}) - return frozenset(usr.removeprefix("@") for usr in username) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/stack.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/stack.py deleted file mode 100755 index e4eef2b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/stack.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions related to inspecting the program stack. - -.. versionadded:: 20.0 - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from pathlib import Path -from types import FrameType -from typing import Optional - -from telegram._utils.logging import get_logger - -_LOGGER = get_logger(__name__) - - -def was_called_by(frame: Optional[FrameType], caller: Path) -> bool: - """Checks if the passed frame was called by the specified file. - - Example: - .. code:: pycon - - >>> was_called_by(inspect.currentframe(), Path(__file__)) - True - - Arguments: - frame (:obj:`FrameType`): The frame - usually the return value of - ``inspect.currentframe()``. If :obj:`None` is passed, the return value will be - :obj:`False`. - caller (:obj:`pathlib.Path`): File that should be the caller. - - Returns: - :obj:`bool`: Whether the frame was called by the specified file. - """ - if frame is None: - return False - - try: - return _was_called_by(frame, caller) - except Exception as exc: - _LOGGER.debug( - "Failed to check if frame was called by `caller`. Assuming that it was not.", - exc_info=exc, - ) - return False - - -def _was_called_by(frame: FrameType, caller: Path) -> bool: - # https://stackoverflow.com/a/57712700/10606962 - if Path(frame.f_code.co_filename).resolve() == caller: - return True - while frame.f_back: - frame = frame.f_back - if Path(frame.f_code.co_filename).resolve() == caller: - return True - return False diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/trackingdict.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/trackingdict.py deleted file mode 100755 index 810ecc6..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/trackingdict.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains a mutable mapping that keeps track of the keys that where accessed. - -.. versionadded:: 20.0 - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from collections import UserDict -from collections.abc import Mapping -from typing import Final, Generic, Optional, TypeVar, Union - -from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue - -_VT = TypeVar("_VT") -_KT = TypeVar("_KT") -_T = TypeVar("_T") - - -class TrackingDict(UserDict, Generic[_KT, _VT]): - """Mutable mapping that keeps track of which keys where accessed with write access. - Read-access is not tracked. - - Note: - * ``setdefault()`` and ``pop`` are considered writing only depending on whether the - key is present - * deleting values is considered writing - """ - - DELETED: Final = object() - """Special marker indicating that an entry was deleted.""" - - __slots__ = ("_write_access_keys",) - - def __init__(self) -> None: - super().__init__() - self._write_access_keys: set[_KT] = set() - - def __setitem__(self, key: _KT, value: _VT) -> None: - self.__track_write(key) - super().__setitem__(key, value) - - def __delitem__(self, key: _KT) -> None: - self.__track_write(key) - super().__delitem__(key) - - def __track_write(self, key: Union[_KT, set[_KT]]) -> None: - if isinstance(key, set): - self._write_access_keys |= key - else: - self._write_access_keys.add(key) - - def pop_accessed_keys(self) -> set[_KT]: - """Returns all keys that were write-accessed since the last time this method was called.""" - out = self._write_access_keys - self._write_access_keys = set() - return out - - def pop_accessed_write_items(self) -> list[tuple[_KT, _VT]]: - """ - Returns all keys & corresponding values as set of tuples that were write-accessed since - the last time this method was called. If a key was deleted, the value will be - :attr:`DELETED`. - """ - keys = self.pop_accessed_keys() - return [(key, self.get(key, self.DELETED)) for key in keys] - - def mark_as_accessed(self, key: _KT) -> None: - """Use this method have the key returned again in the next call to - :meth:`pop_accessed_write_items` or :meth:`pop_accessed_keys` - """ - self._write_access_keys.add(key) - - # Override methods to track access - - def update_no_track(self, mapping: Mapping[_KT, _VT]) -> None: - """Like ``update``, but doesn't count towards write access.""" - for key, value in mapping.items(): - self.data[key] = value - - # Mypy seems a bit inconsistent about what it wants as types for `default` and return value - # so we just ignore a bit - def pop( # type: ignore[override] - self, - key: _KT, - default: _VT = DEFAULT_NONE, # type: ignore[assignment] - ) -> _VT: - if key in self: - self.__track_write(key) - if isinstance(default, DefaultValue): - return super().pop(key) - return super().pop(key, default=default) - - def clear(self) -> None: - self.__track_write(set(super().keys())) - super().clear() - - # Mypy seems a bit inconsistent about what it wants as types for `default` and return value - # so we just ignore a bit - def setdefault(self: "TrackingDict[_KT, _T]", key: _KT, default: Optional[_T] = None) -> _T: - if key in self: - return self[key] - - self.__track_write(key) - self[key] = default # type: ignore[assignment] - return default # type: ignore[return-value] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/types.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/types.py deleted file mode 100755 index 6aa35c8..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/types.py +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains custom typing aliases. - -.. versionadded:: 13.6 - -Warning: - Contents of this module are intended to be used internally by the library and *not* by the - user. Changes to this module are not considered breaking changes and may not be documented in - the changelog. -""" -from collections.abc import Coroutine, MutableMapping -from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union - -if TYPE_CHECKING: - from typing import Optional - - from telegram import Bot - from telegram.ext import BaseRateLimiter, CallbackContext, JobQueue - -CCT = TypeVar("CCT", bound="CallbackContext[Any, Any, Any, Any]") -"""An instance of :class:`telegram.ext.CallbackContext` or a custom subclass. - -.. versionadded:: 13.6 -""" - -RT = TypeVar("RT") -UT = TypeVar("UT") -HandlerCallback = Callable[[UT, CCT], Coroutine[Any, Any, RT]] -"""Type of a handler callback - - .. versionadded:: 20.0 -""" -JobCallback = Callable[[CCT], Coroutine[Any, Any, Any]] -"""Type of a job callback - - .. versionadded:: 20.0 -""" - -ConversationKey = tuple[Union[int, str], ...] -ConversationDict = MutableMapping[ConversationKey, object] -"""dict[tuple[:obj:`int` | :obj:`str`, ...], Optional[:obj:`object`]]: - Dicts as maintained by the :class:`telegram.ext.ConversationHandler`. - - .. versionadded:: 13.6 -""" - -CDCData = tuple[list[tuple[str, float, dict[str, Any]]], dict[str, str]] -"""tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]], \ - dict[:obj:`str`, :obj:`str`]]: Data returned by - :attr:`telegram.ext.CallbackDataCache.persistence_data`. - - .. versionadded:: 13.6 -""" - -BT = TypeVar("BT", bound="Bot") -"""Type of the bot. - -.. versionadded:: 20.0 -""" -UD = TypeVar("UD") -"""Type of the user data for a single user. - -.. versionadded:: 13.6 -""" -CD = TypeVar("CD") -"""Type of the chat data for a single user. - -.. versionadded:: 13.6 -""" -BD = TypeVar("BD") -"""Type of the bot data. - -.. versionadded:: 13.6 -""" -JQ = TypeVar("JQ", bound=Union[None, "JobQueue"]) -"""Type of the job queue. - -.. versionadded:: 20.0""" - -RL = TypeVar("RL", bound="Optional[BaseRateLimiter]") -"""Type of the rate limiter. - -.. versionadded:: 20.0""" - -RLARGS = TypeVar("RLARGS") -"""Type of the rate limiter arguments. - -.. versionadded:: 20.0""" -FilterDataDict = dict[str, list[Any]] diff --git a/venv/lib/python3.11/site-packages/telegram/ext/_utils/webhookhandler.py b/venv/lib/python3.11/site-packages/telegram/ext/_utils/webhookhandler.py deleted file mode 100755 index 0c101c8..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/_utils/webhookhandler.py +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=missing-module-docstring -import asyncio -import json -from http import HTTPStatus -from pathlib import Path -from socket import socket -from ssl import SSLContext -from types import TracebackType -from typing import TYPE_CHECKING, Optional, Union - -# Instead of checking for ImportError here, we do that in `updater.py`, where we import from -# this module. Doing it here would be tricky, as the classes below subclass tornado classes -import tornado.web -from tornado.httpserver import HTTPServer - -try: - from tornado.netutil import bind_unix_socket - - UNIX_AVAILABLE = True -except ImportError: - UNIX_AVAILABLE = False - -from telegram import Update -from telegram._utils.logging import get_logger -from telegram.ext._extbot import ExtBot - -if TYPE_CHECKING: - from telegram import Bot - -# This module is not visible to users, so we log as Updater -_LOGGER = get_logger(__name__, class_name="Updater") - - -class WebhookServer: - """Thin wrapper around ``tornado.httpserver.HTTPServer``.""" - - __slots__ = ( - "_http_server", - "_server_lock", - "_shutdown_lock", - "is_running", - "listen", - "port", - "unix", - ) - - def __init__( - self, - listen: str, - port: int, - webhook_app: "WebhookAppClass", - ssl_ctx: Optional[SSLContext], - unix: Optional[Union[str, Path, socket]] = None, - ): - if unix and not UNIX_AVAILABLE: - raise RuntimeError("This OS does not support binding unix sockets.") - self._http_server = HTTPServer(webhook_app, ssl_options=ssl_ctx) - self.listen = listen - self.port = port - self.is_running = False - self.unix = None - if unix and isinstance(unix, socket): - self.unix = unix - elif unix: - self.unix = bind_unix_socket(str(unix)) - self._server_lock = asyncio.Lock() - self._shutdown_lock = asyncio.Lock() - - async def serve_forever(self, ready: Optional[asyncio.Event] = None) -> None: - async with self._server_lock: - if self.unix: - self._http_server.add_socket(self.unix) - else: - self._http_server.listen(self.port, address=self.listen) - - self.is_running = True - if ready is not None: - ready.set() - - _LOGGER.debug("Webhook Server started.") - - async def shutdown(self) -> None: - async with self._shutdown_lock: - if not self.is_running: - _LOGGER.debug("Webhook Server is already shut down. Returning") - return - self.is_running = False - self._http_server.stop() - await self._http_server.close_all_connections() - _LOGGER.debug("Webhook Server stopped") - - -class WebhookAppClass(tornado.web.Application): - """Application used in the Webserver""" - - def __init__( - self, - webhook_path: str, - bot: "Bot", - update_queue: asyncio.Queue, - secret_token: Optional[str] = None, - ): - self.shared_objects = { - "bot": bot, - "update_queue": update_queue, - "secret_token": secret_token, - } - handlers = [(rf"{webhook_path}/?", TelegramHandler, self.shared_objects)] - tornado.web.Application.__init__(self, handlers) # type: ignore - - def log_request(self, handler: tornado.web.RequestHandler) -> None: - """Overrides the default implementation since we have our own logging setup.""" - - -# pylint: disable=abstract-method -class TelegramHandler(tornado.web.RequestHandler): - """BaseHandler that processes incoming requests from Telegram""" - - __slots__ = ("bot", "secret_token", "update_queue") - - SUPPORTED_METHODS = ("POST",) # type: ignore[assignment] - - def initialize(self, bot: "Bot", update_queue: asyncio.Queue, secret_token: str) -> None: - """Initialize for each request - that's the interface provided by tornado""" - # pylint: disable=attribute-defined-outside-init - self.bot = bot - self.update_queue = update_queue - self.secret_token = secret_token - if secret_token: - _LOGGER.debug( - "The webhook server has a secret token, expecting it in incoming requests now" - ) - - def set_default_headers(self) -> None: - """Sets default headers""" - self.set_header("Content-Type", 'application/json; charset="utf-8"') - - async def post(self) -> None: - """Handle incoming POST request""" - _LOGGER.debug("Webhook triggered") - self._validate_post() - - json_string = self.request.body.decode() - data = json.loads(json_string) - self.set_status(HTTPStatus.OK) - _LOGGER.debug("Webhook received data: %s", json_string) - - try: - update = Update.de_json(data, self.bot) - except Exception as exc: - _LOGGER.critical( - "Something went wrong processing the data received from Telegram. " - "Received data was *not* processed! Received data was: %r", - data, - exc_info=exc, - ) - raise tornado.web.HTTPError( - HTTPStatus.BAD_REQUEST, reason="Update could not be processed" - ) from exc - - if update: - _LOGGER.debug( - "Received Update with ID %d on Webhook", - # For some reason pylint thinks update is a general TelegramObject - update.update_id, # pylint: disable=no-member - ) - - # handle arbitrary callback data, if necessary - if isinstance(self.bot, ExtBot): - self.bot.insert_callback_data(update) - - await self.update_queue.put(update) - - def _validate_post(self) -> None: - """Only accept requests with content type JSON""" - ct_header = self.request.headers.get("Content-Type", None) - if ct_header != "application/json": - raise tornado.web.HTTPError(HTTPStatus.FORBIDDEN) - # verifying that the secret token is the one the user set when the user set one - if self.secret_token is not None: - token = self.request.headers.get("X-Telegram-Bot-Api-Secret-Token") - if not token: - _LOGGER.debug("Request did not include the secret token") - raise tornado.web.HTTPError( - HTTPStatus.FORBIDDEN, reason="Request did not include the secret token" - ) - if token != self.secret_token: - _LOGGER.debug("Request had the wrong secret token: %s", token) - raise tornado.web.HTTPError( - HTTPStatus.FORBIDDEN, reason="Request had the wrong secret token" - ) - - def log_exception( - self, - typ: Optional[type[BaseException]], - value: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - """Override the default logging and instead use our custom logging.""" - _LOGGER.debug( - "%s - %s", - self.request.remote_ip, - "Exception in TelegramHandler", - exc_info=(typ, value, tb) if typ and value and tb else value, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/ext/filters.py b/venv/lib/python3.11/site-packages/telegram/ext/filters.py deleted file mode 100755 index e1e16c6..0000000 --- a/venv/lib/python3.11/site-packages/telegram/ext/filters.py +++ /dev/null @@ -1,2939 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -""" -This module contains filters for use with :class:`telegram.ext.MessageHandler`, -:class:`telegram.ext.CommandHandler`, or :class:`telegram.ext.PrefixHandler`. - -.. versionchanged:: 20.0 - - #. Filters are no longer callable, if you're using a custom filter and are calling an existing - filter, then switch to the new syntax: ``filters.{filter}.check_update(update)``. - #. Removed the ``Filters`` class. The filters are now directly attributes/classes of the - :mod:`~telegram.ext.filters` module. - #. The names of all filters has been updated: - - * Filter classes which are ready for use, e.g ``Filters.all`` are now capitalized, e.g - ``filters.ALL``. - * Filters which need to be initialized are now in CamelCase. E.g. ``filters.User(...)``. - * Filters which do both (like ``Filters.text``) are now split as ready-to-use version - ``filters.TEXT`` and class version ``filters.Text(...)``. - -""" - -__all__ = ( - "ALL", - "ANIMATION", - "ATTACHMENT", - "AUDIO", - "BOOST_ADDED", - "CAPTION", - "CHAT", - "COMMAND", - "CONTACT", - "EFFECT_ID", - "FORWARDED", - "GAME", - "GIVEAWAY", - "GIVEAWAY_WINNERS", - "HAS_MEDIA_SPOILER", - "HAS_PROTECTED_CONTENT", - "INVOICE", - "IS_AUTOMATIC_FORWARD", - "IS_FROM_OFFLINE", - "IS_TOPIC_MESSAGE", - "LOCATION", - "PAID_MEDIA", - "PASSPORT_DATA", - "PHOTO", - "POLL", - "PREMIUM_USER", - "REPLY", - "REPLY_TO_STORY", - "SENDER_BOOST_COUNT", - "STORY", - "SUCCESSFUL_PAYMENT", - "TEXT", - "USER", - "USER_ATTACHMENT", - "VENUE", - "VIA_BOT", - "VIDEO", - "VIDEO_NOTE", - "VOICE", - "BaseFilter", - "Caption", - "CaptionEntity", - "CaptionRegex", - "Chat", - "ChatType", - "Command", - "Dice", - "Document", - "Entity", - "ForwardedFrom", - "Language", - "Mention", - "MessageFilter", - "Regex", - "SenderChat", - "StatusUpdate", - "Sticker", - "SuccessfulPayment", - "Text", - "UpdateFilter", - "UpdateType", - "User", - "ViaBot", -) -import mimetypes -import re -from abc import ABC, abstractmethod -from collections.abc import Collection, Iterable, Sequence -from re import Match, Pattern -from typing import NoReturn, Optional, Union, cast - -from telegram import Chat as TGChat -from telegram import ( - Message, - MessageEntity, - MessageOriginChannel, - MessageOriginChat, - MessageOriginUser, - Update, -) -from telegram import User as TGUser -from telegram._utils.types import SCT -from telegram.constants import DiceEmoji as DiceEmojiEnum -from telegram.ext._utils._update_parsing import parse_chat_id, parse_username -from telegram.ext._utils.types import FilterDataDict - - -class BaseFilter: - """Base class for all Filters. - - Filters subclassing from this class can combined using bitwise operators: - - And:: - - filters.TEXT & filters.Entity(MENTION) - - Or:: - - filters.AUDIO | filters.VIDEO - - Exclusive Or:: - - filters.Regex('To Be') ^ filters.Regex('Not 2B') - - Not:: - - ~ filters.COMMAND - - Also works with more than two filters:: - - filters.TEXT & (filters.Entity("url") | filters.Entity("text_link")) - filters.TEXT & (~ filters.FORWARDED) - - Note: - Filters use the same short circuiting logic as python's :keyword:`and`, :keyword:`or` and - :keyword:`not`. This means that for example:: - - filters.Regex(r'(a?x)') | filters.Regex(r'(b?x)') - - With ``message.text == 'x'``, will only ever return the matches for the first filter, - since the second one is never evaluated. - - If you want to create your own filters create a class inheriting from either - :class:`MessageFilter` or :class:`UpdateFilter` and implement a ``filter()`` - method that returns a boolean: :obj:`True` if the message should be - handled, :obj:`False` otherwise. - Note that the filters work only as class instances, not actual class objects (so remember to - initialize your filter classes). - - By default, the filters name (what will get printed when converted to a string for display) - will be the class name. If you want to overwrite this assign a better name to the :attr:`name` - class variable. - - .. versionadded:: 20.0 - Added the arguments :attr:`name` and :attr:`data_filter`. - - Args: - name (:obj:`str`): Name for this filter. Defaults to the type of filter. - data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should - return a dict with lists. The dict will be merged with - :class:`telegram.ext.CallbackContext`'s internal dict in most cases - (depends on the handler). - """ - - __slots__ = ("_data_filter", "_name") - - def __init__(self, name: Optional[str] = None, data_filter: bool = False): - self._name = self.__class__.__name__ if name is None else name - self._data_filter = data_filter - - def __and__(self, other: "BaseFilter") -> "BaseFilter": - """Defines `AND` bitwise operator for :class:`BaseFilter` object. - The combined filter accepts an update only if it is accepted by both filters. - For example, ``filters.PHOTO & filters.CAPTION`` will only accept messages that contain - both a photo and a caption. - - Returns: - :obj:`BaseFilter` - """ - return _MergedFilter(self, and_filter=other) - - def __or__(self, other: "BaseFilter") -> "BaseFilter": - """Defines `OR` bitwise operator for :class:`BaseFilter` object. - The combined filter accepts an update only if it is accepted by any of the filters. - For example, ``filters.PHOTO | filters.CAPTION`` will only accept messages that contain - photo or caption or both. - - Returns: - :obj:`BaseFilter` - """ - return _MergedFilter(self, or_filter=other) - - def __xor__(self, other: "BaseFilter") -> "BaseFilter": - """Defines `XOR` bitwise operator for :class:`BaseFilter` object. - The combined filter accepts an update only if it is accepted by any of the filters and - not both of them. For example, ``filters.PHOTO ^ filters.CAPTION`` will only accept - messages that contain photo or caption, not both of them. - - Returns: - :obj:`BaseFilter` - """ - return _XORFilter(self, other) - - def __invert__(self) -> "BaseFilter": - """Defines `NOT` bitwise operator for :class:`BaseFilter` object. - The combined filter accepts an update only if it is accepted by any of the filters. - For example, ``~ filters.PHOTO`` will only accept messages that do not contain photo. - - Returns: - :obj:`BaseFilter` - """ - return _InvertedFilter(self) - - def __repr__(self) -> str: - """Gives name for this filter. - - .. seealso:: - :meth:`name` - - Returns: - :obj:`str`: - """ - return self.name - - @property - def data_filter(self) -> bool: - """:obj:`bool`: Whether this filter is a data filter.""" - return self._data_filter - - @data_filter.setter - def data_filter(self, value: bool) -> None: - self._data_filter = value - - @property - def name(self) -> str: - """:obj:`str`: Name for this filter.""" - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - - def check_update(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - """Checks if the specified update should be handled by this filter. - - .. versionchanged:: 21.1 - This filter now also returns :obj:`True` if the update contains - :attr:`~telegram.Update.business_message` - or :attr:`~telegram.Update.edited_business_message`. - - Args: - update (:class:`telegram.Update`): The update to check. - - Returns: - :obj:`bool`: :obj:`True` if the update contains one of - :attr:`~telegram.Update.channel_post`, :attr:`~telegram.Update.message`, - :attr:`~telegram.Update.edited_channel_post`, - :attr:`~telegram.Update.edited_message`, :attr:`telegram.Update.business_message`, - :attr:`telegram.Update.edited_business_message`, or :obj:`False` otherwise. - """ - return bool( # Only message updates should be handled. - update.channel_post - or update.message - or update.edited_channel_post - or update.edited_message - or update.business_message - or update.edited_business_message - ) - - -class MessageFilter(BaseFilter): - """Base class for all Message Filters. In contrast to :class:`UpdateFilter`, the object passed - to :meth:`filter` is :attr:`telegram.Update.effective_message`. - - Please see :class:`BaseFilter` for details on how to create custom filters. - - .. seealso:: :wiki:`Advanced Filters ` - - """ - - __slots__ = () - - def check_update(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - """Checks if the specified update should be handled by this filter by passing - :attr:`~telegram.Update.effective_message` to :meth:`filter`. - - Args: - update (:class:`telegram.Update`): The update to check. - - Returns: - :obj:`bool` | dict[:obj:`str`, :obj:`list`] | :obj:`None`: If the update should be - handled by this filter, returns :obj:`True` or a dict with lists, in case the filter - is a data filter. If the update should not be handled by this filter, :obj:`False` or - :obj:`None`. - """ - if super().check_update(update): - return self.filter(update.effective_message) # type: ignore[arg-type] - return False - - @abstractmethod - def filter(self, message: Message) -> Optional[Union[bool, FilterDataDict]]: - """This method must be overwritten. - - Args: - message (:class:`telegram.Message`): The message that is tested. - - Returns: - :obj:`dict` or :obj:`bool` - - """ - - -class UpdateFilter(BaseFilter): - """Base class for all Update Filters. In contrast to :class:`MessageFilter`, the object - passed to :meth:`filter` is an instance of :class:`telegram.Update`, which allows to create - filters like :attr:`telegram.ext.filters.UpdateType.EDITED_MESSAGE`. - - Please see :class:`telegram.ext.filters.BaseFilter` for details on how to create custom - filters. - - """ - - __slots__ = () - - def check_update(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - """Checks if the specified update should be handled by this filter. - - Args: - update (:class:`telegram.Update`): The update to check. - - Returns: - :obj:`bool` | dict[:obj:`str`, :obj:`list`] | :obj:`None`: If the update should be - handled by this filter, returns :obj:`True` or a dict with lists, in case the filter - is a data filter. If the update should not be handled by this filter, :obj:`False` or - :obj:`None`. - """ - return self.filter(update) if super().check_update(update) else False - - @abstractmethod - def filter(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - """This method must be overwritten. - - Args: - update (:class:`telegram.Update`): The update that is tested. - - Returns: - :obj:`dict` or :obj:`bool`. - - """ - - -class _InvertedFilter(UpdateFilter): - """Represents a filter that has been inverted. - - Args: - f: The filter to invert. - - """ - - __slots__ = ("inv_filter",) - - def __init__(self, f: BaseFilter): - super().__init__() - self.inv_filter = f - - def filter(self, update: Update) -> bool: - return not bool(self.inv_filter.check_update(update)) - - @property - def name(self) -> str: - return f"" - - @name.setter - def name(self, _: str) -> NoReturn: - raise RuntimeError("Cannot set name for combined filters.") - - -class _MergedFilter(UpdateFilter): - """Represents a filter consisting of two other filters. - - Args: - base_filter: Filter 1 of the merged filter. - and_filter: Optional filter to "and" with base_filter. Mutually exclusive with or_filter. - or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter. - - """ - - __slots__ = ("and_filter", "base_filter", "or_filter") - - def __init__( - self, - base_filter: BaseFilter, - and_filter: Optional[BaseFilter] = None, - or_filter: Optional[BaseFilter] = None, - ): - super().__init__() - self.base_filter = base_filter - if self.base_filter.data_filter: - self.data_filter = True - self.and_filter = and_filter - if ( - self.and_filter - and not isinstance(self.and_filter, bool) - and self.and_filter.data_filter - ): - self.data_filter = True - self.or_filter = or_filter - if self.or_filter and not isinstance(self.and_filter, bool) and self.or_filter.data_filter: - self.data_filter = True - - @staticmethod - def _merge(base_output: Union[bool, dict], comp_output: Union[bool, dict]) -> FilterDataDict: - base = base_output if isinstance(base_output, dict) else {} - comp = comp_output if isinstance(comp_output, dict) else {} - for k in comp: - # Make sure comp values are lists - comp_value = comp[k] if isinstance(comp[k], list) else [] - try: - # If base is a list then merge - if isinstance(base[k], list): - base[k] += comp_value - else: - base[k] = [base[k], *comp_value] - except KeyError: - base[k] = comp_value - return base - - # pylint: disable=too-many-return-statements - def filter(self, update: Update) -> Union[bool, FilterDataDict]: - base_output = self.base_filter.check_update(update) - # We need to check if the filters are data filters and if so return the merged data. - # If it's not a data filter or an or_filter but no matches return bool - if self.and_filter: - # And filter needs to short circuit if base is falsy - if base_output: - comp_output = self.and_filter.check_update(update) - if comp_output: - if self.data_filter: - merged = self._merge(base_output, comp_output) - if merged: - return merged - return True - elif self.or_filter: - # Or filter needs to short circuit if base is truthy - if base_output: - if self.data_filter: - return base_output - return True - - comp_output = self.or_filter.check_update(update) - if comp_output: - if self.data_filter: - return comp_output - return True - return False - - @property - def name(self) -> str: - return ( - f"<{self.base_filter} {'and' if self.and_filter else 'or'} " - f"{self.and_filter or self.or_filter}>" - ) - - @name.setter - def name(self, _: str) -> NoReturn: - raise RuntimeError("Cannot set name for combined filters.") - - -class _XORFilter(UpdateFilter): - """Convenience filter acting as wrapper for :class:`MergedFilter` representing the an XOR gate - for two filters. - - Args: - base_filter: Filter 1 of the merged filter. - xor_filter: Filter 2 of the merged filter. - - """ - - __slots__ = ("base_filter", "merged_filter", "xor_filter") - - def __init__(self, base_filter: BaseFilter, xor_filter: BaseFilter): - super().__init__() - self.base_filter = base_filter - self.xor_filter = xor_filter - self.merged_filter = (base_filter & ~xor_filter) | (~base_filter & xor_filter) - - def filter(self, update: Update) -> Optional[Union[bool, FilterDataDict]]: - return self.merged_filter.check_update(update) - - @property - def name(self) -> str: - return f"<{self.base_filter} xor {self.xor_filter}>" - - @name.setter - def name(self, _: str) -> NoReturn: - raise RuntimeError("Cannot set name for combined filters.") - - -class _All(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: # noqa: ARG002 - return True - - -ALL = _All(name="filters.ALL") -"""All Messages.""" - - -class _Animation(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.animation) - - -ANIMATION = _Animation(name="filters.ANIMATION") -"""Messages that contain :attr:`telegram.Message.animation`.""" - - -class _Attachment(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.effective_attachment) - - -ATTACHMENT = _Attachment(name="filters.ATTACHMENT") -"""Messages that contain :meth:`telegram.Message.effective_attachment`. - -.. versionadded:: 13.6""" - - -class _Audio(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.audio) - - -AUDIO = _Audio(name="filters.AUDIO") -"""Messages that contain :attr:`telegram.Message.audio`.""" - - -class Caption(MessageFilter): - """Messages with a caption. If a list of strings is passed, it filters messages to only - allow those whose caption is appearing in the given list. - - Examples: - ``MessageHandler(filters.Caption(['PTB rocks!', 'PTB']), callback_method_2)`` - - .. seealso:: - :attr:`telegram.ext.filters.CAPTION` - - Args: - strings (list[:obj:`str`] | tuple[:obj:`str`], optional): Which captions to allow. Only - exact matches are allowed. If not specified, will allow any message with a caption. - """ - - __slots__ = ("strings",) - - def __init__(self, strings: Optional[Union[list[str], tuple[str, ...]]] = None): - self.strings: Optional[Sequence[str]] = strings - super().__init__(name=f"filters.Caption({strings})" if strings else "filters.CAPTION") - - def filter(self, message: Message) -> bool: - if self.strings is None: - return bool(message.caption) - return message.caption in self.strings if message.caption else False - - -CAPTION = Caption() -"""Shortcut for :class:`telegram.ext.filters.Caption()`. - -Examples: - To allow any caption, simply use ``MessageHandler(filters.CAPTION, callback_method)``. -""" - - -class CaptionEntity(MessageFilter): - """ - Filters media messages to only allow those which have a :class:`telegram.MessageEntity` - where their :class:`~telegram.MessageEntity.type` matches `entity_type`. - - Examples: - ``MessageHandler(filters.CaptionEntity("hashtag"), callback_method)`` - - Args: - entity_type (:obj:`str`): Caption Entity type to check for. All types can be found as - constants in :class:`telegram.MessageEntity`. - - """ - - __slots__ = ("entity_type",) - - def __init__(self, entity_type: str): - self.entity_type: str = entity_type - super().__init__(name=f"filters.CaptionEntity({self.entity_type})") - - def filter(self, message: Message) -> bool: - return any(entity.type == self.entity_type for entity in message.caption_entities) - - -class CaptionRegex(MessageFilter): - """ - Filters updates by searching for an occurrence of :paramref:`~CaptionRegex.pattern` in the - message caption. - - This filter works similarly to :class:`Regex`, with the only exception being that - it applies to the message caption instead of the text. - - Examples: - Use ``MessageHandler(filters.PHOTO & filters.CaptionRegex(r'help'), callback)`` - to capture all photos with caption containing the word 'help'. - - Note: - This filter will not work on simple text messages, but only on media with caption. - - Args: - pattern (:obj:`str` | :func:`re.Pattern `): The regex pattern. - """ - - __slots__ = ("pattern",) - - def __init__(self, pattern: Union[str, Pattern[str]]): - if isinstance(pattern, str): - pattern = re.compile(pattern) - self.pattern: Pattern[str] = pattern - super().__init__(name=f"filters.CaptionRegex({self.pattern})", data_filter=True) - - def filter(self, message: Message) -> Optional[dict[str, list[Match[str]]]]: - if message.caption and (match := self.pattern.search(message.caption)): - return {"matches": [match]} - return {} - - -class _ChatUserBaseFilter(MessageFilter, ABC): - __slots__ = ( - "_chat_id_name", - "_chat_ids", - "_username_name", - "_usernames", - "allow_empty", - ) - - def __init__( - self, - chat_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - allow_empty: bool = False, - ): - super().__init__() - self._chat_id_name: str = "chat_id" - self._username_name: str = "username" - self.allow_empty: bool = allow_empty - - self._chat_ids: set[int] = set() - self._usernames: set[str] = set() - - self._set_chat_ids(chat_id) - self._set_usernames(username) - - @abstractmethod - def _get_chat_or_user(self, message: Message) -> Union[TGChat, TGUser, None]: ... - - def _set_chat_ids(self, chat_id: Optional[SCT[int]]) -> None: - if chat_id and self._usernames: - raise RuntimeError( - f"Can't set {self._chat_id_name} in conjunction with (already set) " - f"{self._username_name}s." - ) - self._chat_ids = set(parse_chat_id(chat_id)) - - def _set_usernames(self, username: Optional[SCT[str]]) -> None: - if username and self._chat_ids: - raise RuntimeError( - f"Can't set {self._username_name} in conjunction with (already set) " - f"{self._chat_id_name}s." - ) - self._usernames = set(parse_username(username)) - - @property - def chat_ids(self) -> frozenset[int]: - return frozenset(self._chat_ids) - - @chat_ids.setter - def chat_ids(self, chat_id: SCT[int]) -> None: - self._set_chat_ids(chat_id) - - @property - def usernames(self) -> frozenset[str]: - """Which username(s) to allow through. - - Warning: - :attr:`usernames` will give a *copy* of the saved usernames as :obj:`frozenset`. This - is to ensure thread safety. To add/remove a user, you should use :meth:`add_usernames`, - and :meth:`remove_usernames`. Only update the entire set by - ``filter.usernames = new_set``, if you are entirely sure that it is not causing race - conditions, as this will complete replace the current set of allowed users. - - Returns: - frozenset(:obj:`str`) - """ - return frozenset(self._usernames) - - @usernames.setter - def usernames(self, username: SCT[str]) -> None: - self._set_usernames(username) - - def add_usernames(self, username: SCT[str]) -> None: - """ - Add one or more chats to the allowed usernames. - - Args: - username(:obj:`str` | Collection[:obj:`str`]): Which username(s) to - allow through. Leading ``'@'`` s in usernames will be discarded. - """ - if self._chat_ids: - raise RuntimeError( - f"Can't set {self._username_name} in conjunction with (already set) " - f"{self._chat_id_name}s." - ) - - parsed_username = set(parse_username(username)) - self._usernames |= parsed_username - - def _add_chat_ids(self, chat_id: SCT[int]) -> None: - if self._usernames: - raise RuntimeError( - f"Can't set {self._chat_id_name} in conjunction with (already set) " - f"{self._username_name}s." - ) - - parsed_chat_id = set(parse_chat_id(chat_id)) - - self._chat_ids |= parsed_chat_id - - def remove_usernames(self, username: SCT[str]) -> None: - """ - Remove one or more chats from allowed usernames. - - Args: - username(:obj:`str` | Collection[:obj:`str`]): Which username(s) to - disallow through. Leading ``'@'`` s in usernames will be discarded. - """ - if self._chat_ids: - raise RuntimeError( - f"Can't set {self._username_name} in conjunction with (already set) " - f"{self._chat_id_name}s." - ) - - parsed_username = set(parse_username(username)) - self._usernames -= parsed_username - - def _remove_chat_ids(self, chat_id: SCT[int]) -> None: - if self._usernames: - raise RuntimeError( - f"Can't set {self._chat_id_name} in conjunction with (already set) " - f"{self._username_name}s." - ) - parsed_chat_id = set(parse_chat_id(chat_id)) - self._chat_ids -= parsed_chat_id - - def filter(self, message: Message) -> bool: - chat_or_user = self._get_chat_or_user(message) - if chat_or_user: - if self.chat_ids: - return chat_or_user.id in self.chat_ids - if self.usernames: - return bool(chat_or_user.username and chat_or_user.username in self.usernames) - return self.allow_empty - return False - - @property - def name(self) -> str: - return ( - f"filters.{self.__class__.__name__}(" - f"{', '.join(str(s) for s in (self.usernames or self.chat_ids))})" - ) - - @name.setter - def name(self, _: str) -> NoReturn: - raise RuntimeError(f"Cannot set name for filters.{self.__class__.__name__}") - - -class Chat(_ChatUserBaseFilter): - """Filters messages to allow only those which are from a specified chat ID or username. - - Examples: - ``MessageHandler(filters.Chat(-1234), callback_method)`` - - Warning: - :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_chat_ids`, and - :meth:`remove_chat_ids`. Only update the entire set by ``filter.chat_ids = new_set``, - if you are entirely sure that it is not causing race conditions, as this will complete - replace the current set of allowed chats. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`], optional): - Which chat ID(s) to allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Attributes: - chat_ids (set(:obj:`int`)): Which chat ID(s) to allow through. - allow_empty (:obj:`bool`): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. - - Raises: - RuntimeError: If ``chat_id`` and ``username`` are both present. - """ - - __slots__ = () - - def _get_chat_or_user(self, message: Message) -> Optional[TGChat]: - return message.chat - - def add_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Add one or more chats to the allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which chat ID(s) to allow - through. - """ - return super()._add_chat_ids(chat_id) - - def remove_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Remove one or more chats from allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which chat ID(s) to - disallow through. - """ - return super()._remove_chat_ids(chat_id) - - -class _Chat(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.chat) - - -CHAT = _Chat(name="filters.CHAT") -"""This filter filters *any* message that has a :attr:`telegram.Message.chat`. - -.. deprecated:: 20.8 - This filter has no effect since :attr:`telegram.Message.chat` is always present. -""" - - -class ChatType: # A convenience namespace for Chat types. - """Subset for filtering the type of chat. - - Examples: - Use these filters like: ``filters.ChatType.CHANNEL`` or - ``filters.ChatType.SUPERGROUP`` etc. - - Caution: - ``filters.ChatType`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _Channel(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type == TGChat.CHANNEL - - CHANNEL = _Channel(name="filters.ChatType.CHANNEL") - """Updates from channel.""" - - class _Group(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type == TGChat.GROUP - - GROUP = _Group(name="filters.ChatType.GROUP") - """Updates from group.""" - - class _Groups(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type in [TGChat.GROUP, TGChat.SUPERGROUP] - - GROUPS = _Groups(name="filters.ChatType.GROUPS") - """Update from group *or* supergroup.""" - - class _Private(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type == TGChat.PRIVATE - - PRIVATE = _Private(name="filters.ChatType.PRIVATE") - """Update from private chats.""" - - class _SuperGroup(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return message.chat.type == TGChat.SUPERGROUP - - SUPERGROUP = _SuperGroup(name="filters.ChatType.SUPERGROUP") - """Updates from supergroup.""" - - -class Command(MessageFilter): - """ - Messages with a :attr:`telegram.MessageEntity.BOT_COMMAND`. By default, only allows - messages `starting` with a bot command. Pass :obj:`False` to also allow messages that contain a - bot command `anywhere` in the text. - - Examples: - ``MessageHandler(filters.Command(False), command_anywhere_callback)`` - - .. seealso:: - :attr:`telegram.ext.filters.COMMAND`. - - Note: - :attr:`telegram.ext.filters.TEXT` also accepts messages containing a command. - - Args: - only_start (:obj:`bool`, optional): Whether to only allow messages that `start` with a bot - command. Defaults to :obj:`True`. - """ - - __slots__ = ("only_start",) - - def __init__(self, only_start: bool = True): - self.only_start: bool = only_start - super().__init__(f"filters.Command({only_start})" if not only_start else "filters.COMMAND") - - def filter(self, message: Message) -> bool: - if not message.entities: - return False - - first = message.entities[0] - - if self.only_start: - return bool(first.type == MessageEntity.BOT_COMMAND and first.offset == 0) - return bool(any(e.type == MessageEntity.BOT_COMMAND for e in message.entities)) - - -COMMAND = Command() -"""Shortcut for :class:`telegram.ext.filters.Command()`. - -Examples: - To allow messages starting with a command use - ``MessageHandler(filters.COMMAND, command_at_start_callback)``. -""" - - -class _Contact(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.contact) - - -CONTACT = _Contact(name="filters.CONTACT") -"""Messages that contain :attr:`telegram.Message.contact`.""" - - -class _Dice(MessageFilter): - __slots__ = ("emoji", "values") - - def __init__(self, values: Optional[SCT[int]] = None, emoji: Optional[DiceEmojiEnum] = None): - super().__init__() - self.emoji: Optional[DiceEmojiEnum] = emoji - self.values: Optional[Collection[int]] = [values] if isinstance(values, int) else values - - if emoji: # for filters.Dice.BASKETBALL - self.name = f"filters.Dice.{emoji.name}" - if self.values and emoji: # for filters.Dice.Dice(4) SLOT_MACHINE -> SlotMachine - self.name = f"filters.Dice.{emoji.name.title().replace('_', '')}({self.values})" - elif values: # for filters.Dice(4) - self.name = f"filters.Dice({self.values})" - else: - self.name = "filters.Dice.ALL" - - def filter(self, message: Message) -> bool: - if not (dice := message.dice): # no dice - return False - - if self.emoji: - emoji_match = dice.emoji == self.emoji - if self.values: - return dice.value in self.values and emoji_match # emoji and value - return emoji_match # emoji, no value - return dice.value in self.values if self.values else True # no emoji, only value - - -class Dice(_Dice): - """Dice Messages. If an integer or a list of integers is passed, it filters messages to only - allow those whose dice value is appearing in the given list. - - .. versionadded:: 13.4 - - Examples: - To allow any dice message, simply use - ``MessageHandler(filters.Dice.ALL, callback_method)``. - - To allow any dice message, but with value 3 `or` 4, use - ``MessageHandler(filters.Dice([3, 4]), callback_method)`` - - To allow only dice messages with the emoji 🎲, but any value, use - ``MessageHandler(filters.Dice.DICE, callback_method)``. - - To allow only dice messages with the emoji 🎯 and with value 6, use - ``MessageHandler(filters.Dice.Darts(6), callback_method)``. - - To allow only dice messages with the emoji ⚽ and with value 5 `or` 6, use - ``MessageHandler(filters.Dice.Football([5, 6]), callback_method)``. - - Note: - Dice messages don't have text. If you want to filter either text or dice messages, use - ``filters.TEXT | filters.Dice.ALL``. - - Args: - values (:obj:`int` | Collection[:obj:`int`], optional): - Which values to allow. If not specified, will allow the specified dice message. - """ - - __slots__ = () - - ALL = _Dice() - """Dice messages with any value and any emoji.""" - - class Basketball(_Dice): - """Dice messages with the emoji 🏀. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.BASKETBALL) - - BASKETBALL = _Dice(emoji=DiceEmojiEnum.BASKETBALL) - """Dice messages with the emoji 🏀. Matches any dice value.""" - - class Bowling(_Dice): - """Dice messages with the emoji 🎳. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.BOWLING) - - BOWLING = _Dice(emoji=DiceEmojiEnum.BOWLING) - """Dice messages with the emoji 🎳. Matches any dice value.""" - - class Darts(_Dice): - """Dice messages with the emoji 🎯. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.DARTS) - - DARTS = _Dice(emoji=DiceEmojiEnum.DARTS) - """Dice messages with the emoji 🎯. Matches any dice value.""" - - class Dice(_Dice): - """Dice messages with the emoji 🎲. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.DICE) - - DICE = _Dice(emoji=DiceEmojiEnum.DICE) - """Dice messages with the emoji 🎲. Matches any dice value.""" - - class Football(_Dice): - """Dice messages with the emoji ⚽. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.FOOTBALL) - - FOOTBALL = _Dice(emoji=DiceEmojiEnum.FOOTBALL) - """Dice messages with the emoji ⚽. Matches any dice value.""" - - class SlotMachine(_Dice): - """Dice messages with the emoji 🎰. Supports passing a list of integers. - - Args: - values (:obj:`int` | Collection[:obj:`int`]): Which values to allow. - """ - - __slots__ = () - - def __init__(self, values: SCT[int]): - super().__init__(values, emoji=DiceEmojiEnum.SLOT_MACHINE) - - SLOT_MACHINE = _Dice(emoji=DiceEmojiEnum.SLOT_MACHINE) - """Dice messages with the emoji 🎰. Matches any dice value.""" - - -class Document: - """ - Subset for messages containing a document/file. - - Examples: - Use these filters like: ``filters.Document.MP3``, - ``filters.Document.MimeType("text/plain")`` etc. Or just use ``filters.Document.ALL`` for - all document messages. - - Caution: - ``filters.Document`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _All(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.document) - - ALL = _All(name="filters.Document.ALL") - """Messages that contain a :attr:`telegram.Message.document`.""" - - class Category(MessageFilter): - """Filters documents by their category in the mime-type attribute. - - Args: - category (:obj:`str`): Category of the media you want to filter. - - Example: - ``filters.Document.Category('audio/')`` returns :obj:`True` for all types - of audio sent as a file, for example ``'audio/mpeg'`` or ``'audio/x-wav'``. - - Note: - This Filter only filters by the mime_type of the document, it doesn't check the - validity of the document. The user can manipulate the mime-type of a message and - send media with wrong types that don't fit to this handler. - """ - - __slots__ = ("_category",) - - def __init__(self, category: str): - self._category = category - super().__init__(name=f"filters.Document.Category('{self._category}')") - - def filter(self, message: Message) -> bool: - if message.document and message.document.mime_type: - return message.document.mime_type.startswith(self._category) - return False - - APPLICATION = Category("application/") - """Use as ``filters.Document.APPLICATION``.""" - AUDIO = Category("audio/") - """Use as ``filters.Document.AUDIO``.""" - IMAGE = Category("image/") - """Use as ``filters.Document.IMAGE``.""" - VIDEO = Category("video/") - """Use as ``filters.Document.VIDEO``.""" - TEXT = Category("text/") - """Use as ``filters.Document.TEXT``.""" - - class FileExtension(MessageFilter): - """This filter filters documents by their file ending/extension. - - Args: - file_extension (:obj:`str` | :obj:`None`): Media file extension you want to filter. - case_sensitive (:obj:`bool`, optional): Pass :obj:`True` to make the filter case - sensitive. Default: :obj:`False`. - - Example: - * ``filters.Document.FileExtension("jpg")`` - filters files with extension ``".jpg"``. - * ``filters.Document.FileExtension(".jpg")`` - filters files with extension ``"..jpg"``. - * ``filters.Document.FileExtension("Dockerfile", case_sensitive=True)`` - filters files with extension ``".Dockerfile"`` minding the case. - * ``filters.Document.FileExtension(None)`` - filters files without a dot in the filename. - - Note: - * This Filter only filters by the file ending/extension of the document, - it doesn't check the validity of document. - * The user can manipulate the file extension of a document and - send media with wrong types that don't fit to this handler. - * Case insensitive by default, - you may change this with the flag ``case_sensitive=True``. - * Extension should be passed without leading dot - unless it's a part of the extension. - * Pass :obj:`None` to filter files with no extension, - i.e. without a dot in the filename. - """ - - __slots__ = ("_file_extension", "is_case_sensitive") - - def __init__(self, file_extension: Optional[str], case_sensitive: bool = False): - super().__init__() - self.is_case_sensitive: bool = case_sensitive - if file_extension is None: - self._file_extension = None - self.name = "filters.Document.FileExtension(None)" - elif self.is_case_sensitive: - self._file_extension = f".{file_extension}" - self.name = ( - f"filters.Document.FileExtension({file_extension!r}, case_sensitive=True)" - ) - else: - self._file_extension = f".{file_extension}".lower() - self.name = f"filters.Document.FileExtension({file_extension.lower()!r})" - - def filter(self, message: Message) -> bool: - if message.document is None or message.document.file_name is None: - return False - if self._file_extension is None: - return "." not in message.document.file_name - if self.is_case_sensitive: - filename = message.document.file_name - else: - filename = message.document.file_name.lower() - return filename.endswith(self._file_extension) - - class MimeType(MessageFilter): - """This Filter filters documents by their mime-type attribute. - - Args: - mimetype (:obj:`str`): The mimetype to filter. - - Example: - ``filters.Document.MimeType('audio/mpeg')`` filters all audio in `.mp3` format. - - Note: - This Filter only filters by the mime_type of the document, it doesn't check the - validity of document. The user can manipulate the mime-type of a message and - send media with wrong types that don't fit to this handler. - """ - - __slots__ = ("mimetype",) - - def __init__(self, mimetype: str): - self.mimetype: str = mimetype - super().__init__(name=f"filters.Document.MimeType('{self.mimetype}')") - - def filter(self, message: Message) -> bool: - if message.document: - return message.document.mime_type == self.mimetype - return False - - APK = MimeType("application/vnd.android.package-archive") - """Use as ``filters.Document.APK``.""" - DOC = MimeType(mimetypes.types_map[".doc"]) - """Use as ``filters.Document.DOC``.""" - DOCX = MimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.document") - """Use as ``filters.Document.DOCX``.""" - EXE = MimeType(mimetypes.types_map[".exe"]) - """Use as ``filters.Document.EXE``.""" - MP4 = MimeType(mimetypes.types_map[".mp4"]) - """Use as ``filters.Document.MP4``.""" - GIF = MimeType(mimetypes.types_map[".gif"]) - """Use as ``filters.Document.GIF``.""" - JPG = MimeType(mimetypes.types_map[".jpg"]) - """Use as ``filters.Document.JPG``.""" - MP3 = MimeType(mimetypes.types_map[".mp3"]) - """Use as ``filters.Document.MP3``.""" - PDF = MimeType(mimetypes.types_map[".pdf"]) - """Use as ``filters.Document.PDF``.""" - PY = MimeType(mimetypes.types_map[".py"]) - """Use as ``filters.Document.PY``.""" - SVG = MimeType(mimetypes.types_map[".svg"]) - """Use as ``filters.Document.SVG``.""" - TXT = MimeType(mimetypes.types_map[".txt"]) - """Use as ``filters.Document.TXT``.""" - TARGZ = MimeType("application/x-compressed-tar") - """Use as ``filters.Document.TARGZ``.""" - WAV = MimeType(mimetypes.types_map[".wav"]) - """Use as ``filters.Document.WAV``.""" - XML = MimeType(mimetypes.types_map[".xml"]) - """Use as ``filters.Document.XML``.""" - ZIP = MimeType(mimetypes.types_map[".zip"]) - """Use as ``filters.Document.ZIP``.""" - - -class _EffectId(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.effect_id) - - -EFFECT_ID = _EffectId(name="filters.EFFECT_ID") -"""Messages that contain :attr:`telegram.Message.effect_id`. - -.. versionadded:: 21.3""" - - -class Entity(MessageFilter): - """ - Filters messages to only allow those which have a :class:`telegram.MessageEntity` - where their :class:`~telegram.MessageEntity.type` matches `entity_type`. - - Examples: - ``MessageHandler(filters.Entity("hashtag"), callback_method)`` - - Args: - entity_type (:obj:`str`): Entity type to check for. All types can be found as constants - in :class:`telegram.MessageEntity`. - - """ - - __slots__ = ("entity_type",) - - def __init__(self, entity_type: str): - self.entity_type: str = entity_type - super().__init__(name=f"filters.Entity({self.entity_type})") - - def filter(self, message: Message) -> bool: - return any(entity.type == self.entity_type for entity in message.entities) - - -class _Forwarded(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forward_origin) - - -FORWARDED = _Forwarded(name="filters.FORWARDED") -"""Messages that contain :attr:`telegram.Message.forward_origin`. - -.. versionchanged:: 20.8 - Now based on :attr:`telegram.Message.forward_origin` instead of - ``telegram.Message.forward_date``. -""" - - -class ForwardedFrom(_ChatUserBaseFilter): - """Filters messages to allow only those which are forwarded from the specified chat ID(s) - or username(s) based on :attr:`telegram.Message.forward_origin` and in particular - - * :attr:`telegram.MessageOriginUser.sender_user` - * :attr:`telegram.MessageOriginChat.sender_chat` - * :attr:`telegram.MessageOriginChannel.chat` - - .. versionadded:: 13.5 - - .. versionchanged:: 20.8 - Was previously based on ``telegram.Message.forward_from`` and - ``telegram.Message.forward_from_chat``. - - Examples: - ``MessageHandler(filters.ForwardedFrom(chat_id=1234), callback_method)`` - - Note: - When a user has disallowed adding a link to their account while forwarding their - messages, this filter will *not* work since - :attr:`telegram.Message.forward_origin` will be of type - :class:`telegram.MessageOriginHiddenUser`. However, this behaviour - is undocumented and might be changed by Telegram. - - Warning: - :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_chat_ids`, and - :meth:`remove_chat_ids`. Only update the entire set by ``filter.chat_ids = new_set``, if - you are entirely sure that it is not causing race conditions, as this will complete replace - the current set of allowed chats. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`], optional): - Which chat/user ID(s) to allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be - discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Attributes: - chat_ids (set(:obj:`int`)): Which chat/user ID(s) to allow through. - allow_empty (:obj:`bool`): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. - - Raises: - RuntimeError: If both ``chat_id`` and ``username`` are present. - """ - - __slots__ = () - - def _get_chat_or_user(self, message: Message) -> Union[TGUser, TGChat, None]: - if (forward_origin := message.forward_origin) is None: - return None - - if isinstance(forward_origin, MessageOriginUser): - return forward_origin.sender_user - if isinstance(forward_origin, MessageOriginChat): - return forward_origin.sender_chat - if isinstance(forward_origin, MessageOriginChannel): - return forward_origin.chat - - return None - - def add_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Add one or more chats to the allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which chat/user ID(s) to - allow through. - """ - return super()._add_chat_ids(chat_id) - - def remove_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Remove one or more chats from allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which chat/user ID(s) to - disallow through. - """ - return super()._remove_chat_ids(chat_id) - - -class _Game(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.game) - - -GAME = _Game(name="filters.GAME") -"""Messages that contain :attr:`telegram.Message.game`.""" - - -class _Giveaway(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.giveaway) - - -GIVEAWAY = _Giveaway(name="filters.GIVEAWAY") -"""Messages that contain :attr:`telegram.Message.giveaway`.""" - - -class _GiveawayWinners(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.giveaway_winners) - - -GIVEAWAY_WINNERS = _GiveawayWinners(name="filters.GIVEAWAY_WINNERS") -"""Messages that contain :attr:`telegram.Message.giveaway_winners`.""" - - -class _HasMediaSpoiler(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.has_media_spoiler) - - -HAS_MEDIA_SPOILER = _HasMediaSpoiler(name="filters.HAS_MEDIA_SPOILER") -"""Messages that contain :attr:`telegram.Message.has_media_spoiler`. - - .. versionadded:: 20.0 -""" - - -class _HasProtectedContent(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.has_protected_content) - - -HAS_PROTECTED_CONTENT = _HasProtectedContent(name="filters.HAS_PROTECTED_CONTENT") -"""Messages that contain :attr:`telegram.Message.has_protected_content`. - - .. versionadded:: 13.9 -""" - - -class _Invoice(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.invoice) - - -INVOICE = _Invoice(name="filters.INVOICE") -"""Messages that contain :attr:`telegram.Message.invoice`.""" - - -class _IsAutomaticForward(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.is_automatic_forward) - - -IS_AUTOMATIC_FORWARD = _IsAutomaticForward(name="filters.IS_AUTOMATIC_FORWARD") -"""Messages that contain :attr:`telegram.Message.is_automatic_forward`. - - .. versionadded:: 13.9 -""" - - -class _IsTopicMessage(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.is_topic_message) - - -IS_TOPIC_MESSAGE = _IsTopicMessage(name="filters.IS_TOPIC_MESSAGE") -"""Messages that contain :attr:`telegram.Message.is_topic_message`. - - .. versionadded:: 20.0 -""" - - -class _IsFromOffline(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.is_from_offline) - - -IS_FROM_OFFLINE = _IsFromOffline(name="filters.IS_FROM_OFFLINE") -"""Messages that contain :attr:`telegram.Message.is_from_offline`. - - .. versionadded:: 21.1 -""" - - -class Language(MessageFilter): - """Filters messages to only allow those which are from users with a certain language code. - - Note: - According to official Telegram Bot API documentation, not every single user has the - `language_code` attribute. Do not count on this filter working on all users. - - Examples: - ``MessageHandler(filters.Language("en"), callback_method)`` - - Args: - lang (:obj:`str` | Collection[:obj:`str`]): - Which language code(s) to allow through. - This will be matched using :obj:`str.startswith` meaning that - 'en' will match both 'en_US' and 'en_GB'. - - """ - - __slots__ = ("lang",) - - def __init__(self, lang: SCT[str]): - if isinstance(lang, str): - lang = cast(str, lang) - self.lang: Sequence[str] = [lang] - else: - lang = cast(list[str], lang) - self.lang = lang - super().__init__(name=f"filters.Language({self.lang})") - - def filter(self, message: Message) -> bool: - return bool( - message.from_user - and message.from_user.language_code - and any(message.from_user.language_code.startswith(x) for x in self.lang) - ) - - -class _Location(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.location) - - -LOCATION = _Location(name="filters.LOCATION") -"""Messages that contain :attr:`telegram.Message.location`.""" - - -class Mention(MessageFilter): - """Messages containing mentions of specified users or chats. - - Examples: - .. code-block:: python - - MessageHandler(filters.Mention("username"), callback) - MessageHandler(filters.Mention(["@username", 123456]), callback) - - .. versionadded:: 20.7 - - Args: - mentions (:obj:`int` | :obj:`str` | :class:`telegram.User` | Collection[:obj:`int` | \ - :obj:`str` | :class:`telegram.User`]): - Specifies the users and chats to filter for. Messages that do not mention at least one - of the specified users or chats will not be handled. Leading ``'@'`` s in usernames - will be discarded. - """ - - __slots__ = ("_mentions",) - - def __init__(self, mentions: SCT[Union[int, str, TGUser]]): - super().__init__(name=f"filters.Mention({mentions})") - if isinstance(mentions, Iterable) and not isinstance(mentions, str): - self._mentions = {self._fix_mention_username(mention) for mention in mentions} - else: - self._mentions = {self._fix_mention_username(mentions)} - - @staticmethod - def _fix_mention_username(mention: Union[int, str, TGUser]) -> Union[int, str, TGUser]: - if not isinstance(mention, str): - return mention - return mention.lstrip("@") - - @classmethod - def _check_mention(cls, message: Message, mention: Union[int, str, TGUser]) -> bool: - if not message.entities: - return False - - entity_texts = message.parse_entities( - types=[MessageEntity.MENTION, MessageEntity.TEXT_MENTION] - ) - - if isinstance(mention, TGUser): - return any( - mention.id == entity.user.id - or mention.username == entity.user.username - or mention.username == cls._fix_mention_username(entity_texts[entity]) - for entity in message.entities - if entity.user - ) or any( - mention.username == cls._fix_mention_username(entity_text) - for entity_text in entity_texts.values() - ) - if isinstance(mention, int): - return bool( - any(mention == entity.user.id for entity in message.entities if entity.user) - ) - return any( - mention == cls._fix_mention_username(entity_text) - for entity_text in entity_texts.values() - ) - - def filter(self, message: Message) -> bool: - return any(self._check_mention(message, mention) for mention in self._mentions) - - -class _PaidMedia(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.paid_media) - - -PAID_MEDIA = _PaidMedia(name="filters.PAID_MEDIA") -"""Messages that contain :attr:`telegram.Message.paid_media`. - -.. versionadded:: 21.4 -""" - - -class _PassportData(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.passport_data) - - -PASSPORT_DATA = _PassportData(name="filters.PASSPORT_DATA") -"""Messages that contain :attr:`telegram.Message.passport_data`.""" - - -class _Photo(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.photo) - - -PHOTO = _Photo("filters.PHOTO") -"""Messages that contain :attr:`telegram.Message.photo`.""" - - -class _Poll(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.poll) - - -POLL = _Poll(name="filters.POLL") -"""Messages that contain :attr:`telegram.Message.poll`.""" - - -class Regex(MessageFilter): - """ - Filters updates by searching for an occurrence of :paramref:`~Regex.pattern` in the message - text. - The :func:`re.search` function is used to determine whether an update should be filtered. - - Refer to the documentation of the :obj:`re` module for more information. - - To get the groups and groupdict matched, see :attr:`telegram.ext.CallbackContext.matches`. - - Examples: - Use ``MessageHandler(filters.Regex(r'help'), callback)`` to capture all messages that - contain the word 'help'. You can also use - ``MessageHandler(filters.Regex(re.compile(r'help', re.IGNORECASE)), callback)`` if - you want your pattern to be case insensitive. This approach is recommended - if you need to specify flags on your pattern. - - Note: - Filters use the same short circuiting logic as python's :keyword:`and`, :keyword:`or` and - :keyword:`not`. - This means that for example: - - >>> filters.Regex(r'(a?x)') | filters.Regex(r'(b?x)') - - With a :attr:`telegram.Message.text` of `x`, will only ever return the matches for the - first filter, since the second one is never evaluated. - - .. seealso:: :wiki:`Types of Handlers ` - - Args: - pattern (:obj:`str` | :func:`re.Pattern `): The regex pattern. - """ - - __slots__ = ("pattern",) - - def __init__(self, pattern: Union[str, Pattern[str]]): - if isinstance(pattern, str): - pattern = re.compile(pattern) - self.pattern: Pattern[str] = pattern - super().__init__(name=f"filters.Regex({self.pattern})", data_filter=True) - - def filter(self, message: Message) -> Optional[dict[str, list[Match[str]]]]: - if message.text and (match := self.pattern.search(message.text)): - return {"matches": [match]} - return {} - - -class _Reply(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.reply_to_message) - - -REPLY = _Reply(name="filters.REPLY") -"""Messages that contain :attr:`telegram.Message.reply_to_message`.""" - - -class _SenderChat(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sender_chat) - - -class SenderChat(_ChatUserBaseFilter): - """Filters messages to allow only those which are from a specified sender chat's chat ID or - username. - - Examples: - * To filter for messages sent to a group by a channel with ID - ``-1234``, use ``MessageHandler(filters.SenderChat(-1234), callback_method)``. - * To filter for messages of anonymous admins in a super group with username - ``@anonymous``, use - ``MessageHandler(filters.SenderChat(username='anonymous'), callback_method)``. - * To filter for messages sent to a group by *any* channel, use - ``MessageHandler(filters.SenderChat.CHANNEL, callback_method)``. - * To filter for messages of anonymous admins in *any* super group, use - ``MessageHandler(filters.SenderChat.SUPERGROUP, callback_method)``. - * To filter for messages forwarded to a discussion group from *any* channel or of anonymous - admins in *any* super group, use ``MessageHandler(filters.SenderChat.ALL, callback)`` - - Note: - Remember, ``sender_chat`` is also set for messages in a channel as the channel itself, - so when your bot is an admin in a channel and the linked discussion group, you would - receive the message twice (once from inside the channel, once inside the discussion - group). Since v13.9, the field :attr:`telegram.Message.is_automatic_forward` will be - :obj:`True` for the discussion group message. - - .. seealso:: :attr:`telegram.ext.filters.IS_AUTOMATIC_FORWARD` - - Warning: - :attr:`chat_ids` will return a *copy* of the saved chat ids as :obj:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_chat_ids`, and - :meth:`remove_chat_ids`. Only update the entire set by ``filter.chat_ids = new_set``, if - you are entirely sure that it is not causing race conditions, as this will complete replace - the current set of allowed chats. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`], optional): - Which sender chat chat ID(s) to allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which sender chat username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender - chat is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Attributes: - chat_ids (set(:obj:`int`)): Which sender chat chat ID(s) to allow through. - allow_empty (:obj:`bool`): Whether updates should be processed, if no sender chat is - specified in :attr:`chat_ids` and :attr:`usernames`. - - Raises: - RuntimeError: If both ``chat_id`` and ``username`` are present. - """ - - __slots__ = () - - class _CHANNEL(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - if message.sender_chat: - return message.sender_chat.type == TGChat.CHANNEL - return False - - class _SUPERGROUP(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - if message.sender_chat: - return message.sender_chat.type == TGChat.SUPERGROUP - return False - - ALL = _SenderChat(name="filters.SenderChat.ALL") - """All messages with a :attr:`telegram.Message.sender_chat`.""" - SUPER_GROUP = _SUPERGROUP(name="filters.SenderChat.SUPER_GROUP") - """Messages whose sender chat is a super group.""" - CHANNEL = _CHANNEL(name="filters.SenderChat.CHANNEL") - """Messages whose sender chat is a channel.""" - - def add_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Add one or more sender chats to the allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which sender chat ID(s) to - allow through. - """ - return super()._add_chat_ids(chat_id) - - def _get_chat_or_user(self, message: Message) -> Optional[TGChat]: - return message.sender_chat - - def remove_chat_ids(self, chat_id: SCT[int]) -> None: - """ - Remove one or more sender chats from allowed chat ids. - - Args: - chat_id(:obj:`int` | Collection[:obj:`int`]): Which sender chat ID(s) to - disallow through. - """ - return super()._remove_chat_ids(chat_id) - - -class StatusUpdate: - """Subset for messages containing a status update. - - Examples: - Use these filters like: ``filters.StatusUpdate.NEW_CHAT_MEMBERS`` etc. Or use just - ``filters.StatusUpdate.ALL`` for all status update messages. - - Caution: - ``filters.StatusUpdate`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _All(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return bool( - # keep this alphabetically sorted for easier maintenance - StatusUpdate.CHAT_BACKGROUND_SET.check_update(update) - or StatusUpdate.CHAT_CREATED.check_update(update) - or StatusUpdate.CHAT_SHARED.check_update(update) - or StatusUpdate.CONNECTED_WEBSITE.check_update(update) - or StatusUpdate.DELETE_CHAT_PHOTO.check_update(update) - or StatusUpdate.FORUM_TOPIC_CLOSED.check_update(update) - or StatusUpdate.FORUM_TOPIC_CREATED.check_update(update) - or StatusUpdate.FORUM_TOPIC_EDITED.check_update(update) - or StatusUpdate.FORUM_TOPIC_REOPENED.check_update(update) - or StatusUpdate.GENERAL_FORUM_TOPIC_HIDDEN.check_update(update) - or StatusUpdate.GENERAL_FORUM_TOPIC_UNHIDDEN.check_update(update) - or StatusUpdate.GIVEAWAY_COMPLETED.check_update(update) - or StatusUpdate.GIVEAWAY_CREATED.check_update(update) - or StatusUpdate.LEFT_CHAT_MEMBER.check_update(update) - or StatusUpdate.MESSAGE_AUTO_DELETE_TIMER_CHANGED.check_update(update) - or StatusUpdate.MIGRATE.check_update(update) - or StatusUpdate.NEW_CHAT_MEMBERS.check_update(update) - or StatusUpdate.NEW_CHAT_PHOTO.check_update(update) - or StatusUpdate.NEW_CHAT_TITLE.check_update(update) - or StatusUpdate.PINNED_MESSAGE.check_update(update) - or StatusUpdate.PROXIMITY_ALERT_TRIGGERED.check_update(update) - or StatusUpdate.REFUNDED_PAYMENT.check_update(update) - or StatusUpdate.USERS_SHARED.check_update(update) - or StatusUpdate.USER_SHARED.check_update(update) - or StatusUpdate.VIDEO_CHAT_ENDED.check_update(update) - or StatusUpdate.VIDEO_CHAT_PARTICIPANTS_INVITED.check_update(update) - or StatusUpdate.VIDEO_CHAT_SCHEDULED.check_update(update) - or StatusUpdate.VIDEO_CHAT_STARTED.check_update(update) - or StatusUpdate.WEB_APP_DATA.check_update(update) - or StatusUpdate.WRITE_ACCESS_ALLOWED.check_update(update) - ) - - ALL = _All(name="filters.StatusUpdate.ALL") - """Messages that contain any of the below.""" - - class _ChatBackgroundSet(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.chat_background_set) - - CHAT_BACKGROUND_SET = _ChatBackgroundSet(name="filters.StatusUpdate.CHAT_BACKGROUND_SET") - """Messages that contain :attr:`telegram.Message.chat_background_set`.""" - - class _ChatCreated(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool( - message.group_chat_created - or message.supergroup_chat_created - or message.channel_chat_created - ) - - CHAT_CREATED = _ChatCreated(name="filters.StatusUpdate.CHAT_CREATED") - """Messages that contain :attr:`telegram.Message.group_chat_created`, - :attr:`telegram.Message.supergroup_chat_created` or - :attr:`telegram.Message.channel_chat_created`.""" - - class _ChatShared(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.chat_shared) - - CHAT_SHARED = _ChatShared(name="filters.StatusUpdate.CHAT_SHARED") - """Messages that contain :attr:`telegram.Message.chat_shared`. - - .. versionadded:: 20.1 - """ - - class _ConnectedWebsite(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.connected_website) - - CONNECTED_WEBSITE = _ConnectedWebsite(name="filters.StatusUpdate.CONNECTED_WEBSITE") - """Messages that contain :attr:`telegram.Message.connected_website`.""" - - class _DeleteChatPhoto(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.delete_chat_photo) - - DELETE_CHAT_PHOTO = _DeleteChatPhoto(name="filters.StatusUpdate.DELETE_CHAT_PHOTO") - """Messages that contain :attr:`telegram.Message.delete_chat_photo`.""" - - class _ForumTopicClosed(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forum_topic_closed) - - FORUM_TOPIC_CLOSED = _ForumTopicClosed(name="filters.StatusUpdate.FORUM_TOPIC_CLOSED") - """Messages that contain :attr:`telegram.Message.forum_topic_closed`. - - .. versionadded:: 20.0 - """ - - class _ForumTopicCreated(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forum_topic_created) - - FORUM_TOPIC_CREATED = _ForumTopicCreated(name="filters.StatusUpdate.FORUM_TOPIC_CREATED") - """Messages that contain :attr:`telegram.Message.forum_topic_created`. - - .. versionadded:: 20.0 - """ - - class _ForumTopicEdited(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forum_topic_edited) - - FORUM_TOPIC_EDITED = _ForumTopicEdited(name="filters.StatusUpdate.FORUM_TOPIC_EDITED") - """Messages that contain :attr:`telegram.Message.forum_topic_edited`. - - .. versionadded:: 20.0 - """ - - class _ForumTopicReopened(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.forum_topic_reopened) - - FORUM_TOPIC_REOPENED = _ForumTopicReopened(name="filters.StatusUpdate.FORUM_TOPIC_REOPENED") - """Messages that contain :attr:`telegram.Message.forum_topic_reopened`. - - .. versionadded:: 20.0 - """ - - class _GeneralForumTopicHidden(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.general_forum_topic_hidden) - - GENERAL_FORUM_TOPIC_HIDDEN = _GeneralForumTopicHidden( - name="filters.StatusUpdate.GENERAL_FORUM_TOPIC_HIDDEN" - ) - """Messages that contain :attr:`telegram.Message.general_forum_topic_hidden`. - - .. versionadded:: 20.0 - """ - - class _GeneralForumTopicUnhidden(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.general_forum_topic_unhidden) - - GENERAL_FORUM_TOPIC_UNHIDDEN = _GeneralForumTopicUnhidden( - name="filters.StatusUpdate.GENERAL_FORUM_TOPIC_UNHIDDEN" - ) - """Messages that contain :attr:`telegram.Message.general_forum_topic_unhidden`. - - .. versionadded:: 20.0 - """ - - class _GiveawayCreated(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.giveaway_created) - - GIVEAWAY_CREATED = _GiveawayCreated(name="filters.StatusUpdate.GIVEAWAY_CREATED") - """Messages that contain :attr:`telegram.Message.giveaway_created`. - - .. versionadded:: 20.8 - """ - - class _GiveawayCompleted(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.giveaway_completed) - - GIVEAWAY_COMPLETED = _GiveawayCompleted(name="filters.StatusUpdate.GIVEAWAY_COMPLETED") - """Messages that contain :attr:`telegram.Message.giveaway_completed`. - .. versionadded:: 20.8 - """ - - class _LeftChatMember(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.left_chat_member) - - LEFT_CHAT_MEMBER = _LeftChatMember(name="filters.StatusUpdate.LEFT_CHAT_MEMBER") - """Messages that contain :attr:`telegram.Message.left_chat_member`.""" - - class _MessageAutoDeleteTimerChanged(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.message_auto_delete_timer_changed) - - MESSAGE_AUTO_DELETE_TIMER_CHANGED = _MessageAutoDeleteTimerChanged( - "filters.StatusUpdate.MESSAGE_AUTO_DELETE_TIMER_CHANGED" - ) - """Messages that contain :attr:`telegram.Message.message_auto_delete_timer_changed` - - .. versionadded:: 13.4 - """ - - class _Migrate(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.migrate_from_chat_id or message.migrate_to_chat_id) - - MIGRATE = _Migrate(name="filters.StatusUpdate.MIGRATE") - """Messages that contain :attr:`telegram.Message.migrate_from_chat_id` or - :attr:`telegram.Message.migrate_to_chat_id`.""" - - class _NewChatMembers(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_members) - - NEW_CHAT_MEMBERS = _NewChatMembers(name="filters.StatusUpdate.NEW_CHAT_MEMBERS") - """Messages that contain :attr:`telegram.Message.new_chat_members`.""" - - class _NewChatPhoto(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_photo) - - NEW_CHAT_PHOTO = _NewChatPhoto(name="filters.StatusUpdate.NEW_CHAT_PHOTO") - """Messages that contain :attr:`telegram.Message.new_chat_photo`.""" - - class _NewChatTitle(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_title) - - NEW_CHAT_TITLE = _NewChatTitle(name="filters.StatusUpdate.NEW_CHAT_TITLE") - """Messages that contain :attr:`telegram.Message.new_chat_title`.""" - - class _PinnedMessage(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.pinned_message) - - PINNED_MESSAGE = _PinnedMessage(name="filters.StatusUpdate.PINNED_MESSAGE") - """Messages that contain :attr:`telegram.Message.pinned_message`.""" - - class _ProximityAlertTriggered(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.proximity_alert_triggered) - - PROXIMITY_ALERT_TRIGGERED = _ProximityAlertTriggered( - "filters.StatusUpdate.PROXIMITY_ALERT_TRIGGERED" - ) - """Messages that contain :attr:`telegram.Message.proximity_alert_triggered`.""" - - class _RefundedPayment(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.refunded_payment) - - REFUNDED_PAYMENT = _RefundedPayment("filters.StatusUpdate.REFUNDED_PAYMENT") - """Messages that contain :attr:`telegram.Message.refunded_payment`. - .. versionadded:: 21.4 - """ - - class _UserShared(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.api_kwargs.get("user_shared")) - - USER_SHARED = _UserShared(name="filters.StatusUpdate.USER_SHARED") - """Messages that contain ``"user_shared"`` in :attr:`telegram.TelegramObject.api_kwargs`. - - Warning: - This will only catch the legacy ``user_shared`` field, not the - new :attr:`telegram.Message.users_shared` attribute! - - .. versionchanged:: 21.0 - Now relies on :attr:`telegram.TelegramObject.api_kwargs` as the native attribute - ``Message.user_shared`` was removed. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Use :attr:`USERS_SHARED` instead. - """ - - class _UsersShared(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.users_shared) - - USERS_SHARED = _UsersShared(name="filters.StatusUpdate.USERS_SHARED") - """Messages that contain :attr:`telegram.Message.users_shared`. - - .. versionadded:: 20.8 - """ - - class _VideoChatEnded(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_chat_ended) - - VIDEO_CHAT_ENDED = _VideoChatEnded(name="filters.StatusUpdate.VIDEO_CHAT_ENDED") - """Messages that contain :attr:`telegram.Message.video_chat_ended`. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This filter was formerly named ``VOICE_CHAT_ENDED`` - """ - - class _VideoChatScheduled(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_chat_scheduled) - - VIDEO_CHAT_SCHEDULED = _VideoChatScheduled(name="filters.StatusUpdate.VIDEO_CHAT_SCHEDULED") - """Messages that contain :attr:`telegram.Message.video_chat_scheduled`. - - .. versionadded:: 13.5 - .. versionchanged:: 20.0 - This filter was formerly named ``VOICE_CHAT_SCHEDULED`` - """ - - class _VideoChatStarted(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_chat_started) - - VIDEO_CHAT_STARTED = _VideoChatStarted(name="filters.StatusUpdate.VIDEO_CHAT_STARTED") - """Messages that contain :attr:`telegram.Message.video_chat_started`. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This filter was formerly named ``VOICE_CHAT_STARTED`` - """ - - class _VideoChatParticipantsInvited(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_chat_participants_invited) - - VIDEO_CHAT_PARTICIPANTS_INVITED = _VideoChatParticipantsInvited( - "filters.StatusUpdate.VIDEO_CHAT_PARTICIPANTS_INVITED" - ) - """Messages that contain :attr:`telegram.Message.video_chat_participants_invited`. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - This filter was formerly named ``VOICE_CHAT_PARTICIPANTS_INVITED`` - """ - - class _WebAppData(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.web_app_data) - - WEB_APP_DATA = _WebAppData(name="filters.StatusUpdate.WEB_APP_DATA") - """Messages that contain :attr:`telegram.Message.web_app_data`. - - .. versionadded:: 20.0 - """ - - class _WriteAccessAllowed(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.write_access_allowed) - - WRITE_ACCESS_ALLOWED = _WriteAccessAllowed(name="filters.StatusUpdate.WRITE_ACCESS_ALLOWED") - """Messages that contain :attr:`telegram.Message.write_access_allowed`. - - .. versionadded:: 20.0 - """ - - -class Sticker: - """Filters messages which contain a sticker. - - Examples: - Use this filter like: ``filters.Sticker.VIDEO``. Or, just use ``filters.Sticker.ALL`` for - any type of sticker. - - Caution: - ``filters.Sticker`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _All(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) - - ALL = _All(name="filters.Sticker.ALL") - """Messages that contain :attr:`telegram.Message.sticker`.""" - - class _Animated(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) and bool(message.sticker.is_animated) # type: ignore - - ANIMATED = _Animated(name="filters.Sticker.ANIMATED") - """Messages that contain :attr:`telegram.Message.sticker` and - :attr:`is animated `. - - .. versionadded:: 20.0 - """ - - class _Static(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) and ( - not bool(message.sticker.is_animated) # type: ignore[union-attr] - and not bool(message.sticker.is_video) # type: ignore[union-attr] - ) - - STATIC = _Static(name="filters.Sticker.STATIC") - """Messages that contain :attr:`telegram.Message.sticker` and is a static sticker, i.e. does - not contain :attr:`telegram.Sticker.is_animated` or :attr:`telegram.Sticker.is_video`. - - .. versionadded:: 20.0 - """ - - class _Video(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) and bool(message.sticker.is_video) # type: ignore - - VIDEO = _Video(name="filters.Sticker.VIDEO") - """Messages that contain :attr:`telegram.Message.sticker` and is a - :attr:`video sticker `. - - .. versionadded:: 20.0 - """ - - class _Premium(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sticker) and bool( - message.sticker.premium_animation # type: ignore - ) - - PREMIUM = _Premium(name="filters.Sticker.PREMIUM") - """Messages that contain :attr:`telegram.Message.sticker` and have a - :attr:`premium animation `. - - .. versionadded:: 20.0 - """ - # neither mask nor emoji can be a message.sticker, so no filters for them - - -class _Story(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.story) - - -STORY = _Story(name="filters.STORY") -"""Messages that contain :attr:`telegram.Message.story`. - -.. versionadded:: 20.5 -""" - - -class SuccessfulPayment(MessageFilter): - """Successful Payment Messages. If a list of invoice payloads is passed, it filters - messages to only allow those whose `invoice_payload` is appearing in the given list. - - Examples: - `MessageHandler(filters.SuccessfulPayment(['Custom-Payload']), callback_method)` - - .. seealso:: - :attr:`telegram.ext.filters.SUCCESSFUL_PAYMENT` - - Args: - invoice_payloads (list[:obj:`str`] | tuple[:obj:`str`], optional): Which - invoice payloads to allow. Only exact matches are allowed. If not - specified, will allow any invoice payload. - - .. versionadded:: 20.8 - """ - - __slots__ = ("invoice_payloads",) - - def __init__(self, invoice_payloads: Optional[Union[list[str], tuple[str, ...]]] = None): - self.invoice_payloads: Optional[Sequence[str]] = invoice_payloads - super().__init__( - name=( - f"filters.SuccessfulPayment({invoice_payloads})" - if invoice_payloads - else "filters.SUCCESSFUL_PAYMENT" - ) - ) - - def filter(self, message: Message) -> bool: - if self.invoice_payloads is None: - return bool(message.successful_payment) - return ( - payment.invoice_payload in self.invoice_payloads - if (payment := message.successful_payment) - else False - ) - - -SUCCESSFUL_PAYMENT = SuccessfulPayment() -"""Messages that contain :attr:`telegram.Message.successful_payment`.""" - - -class Text(MessageFilter): - """Text Messages. If a list of strings is passed, it filters messages to only allow those - whose text is appearing in the given list. - - Examples: - A simple use case for passing a list is to allow only messages that were sent by a - custom :class:`telegram.ReplyKeyboardMarkup`:: - - buttons = ['Start', 'Settings', 'Back'] - markup = ReplyKeyboardMarkup.from_column(buttons) - ... - MessageHandler(filters.Text(buttons), callback_method) - - .. seealso:: - :attr:`telegram.ext.filters.TEXT` - - - Note: - * Dice messages don't have text. If you want to filter either text or dice messages, use - ``filters.TEXT | filters.Dice.ALL``. - * Messages containing a command are accepted by this filter. Use - ``filters.TEXT & (~filters.COMMAND)``, if you want to filter only text messages without - commands. - - Args: - strings (list[:obj:`str`] | tuple[:obj:`str`], optional): Which messages to allow. Only - exact matches are allowed. If not specified, will allow any text message. - """ - - __slots__ = ("strings",) - - def __init__(self, strings: Optional[Union[list[str], tuple[str, ...]]] = None): - self.strings: Optional[Sequence[str]] = strings - super().__init__(name=f"filters.Text({strings})" if strings else "filters.TEXT") - - def filter(self, message: Message) -> bool: - if self.strings is None: - return bool(message.text) - return message.text in self.strings if message.text else False - - -TEXT = Text() -""" -Shortcut for :class:`telegram.ext.filters.Text()`. - -Examples: - To allow any text message, simply use ``MessageHandler(filters.TEXT, callback_method)``. -""" - - -class UpdateType: - """ - Subset for filtering the type of update. - - Examples: - Use these filters like: ``filters.UpdateType.MESSAGE`` or - ``filters.UpdateType.CHANNEL_POSTS`` etc. - - Caution: - ``filters.UpdateType`` itself is *not* a filter, but just a convenience namespace. - """ - - __slots__ = () - - class _ChannelPost(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.channel_post is not None - - CHANNEL_POST = _ChannelPost(name="filters.UpdateType.CHANNEL_POST") - """Updates with :attr:`telegram.Update.channel_post`.""" - - class _ChannelPosts(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.channel_post is not None or update.edited_channel_post is not None - - CHANNEL_POSTS = _ChannelPosts(name="filters.UpdateType.CHANNEL_POSTS") - """Updates with either :attr:`telegram.Update.channel_post` or - :attr:`telegram.Update.edited_channel_post`.""" - - class _Edited(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return ( - update.edited_message is not None - or update.edited_channel_post is not None - or update.edited_business_message is not None - ) - - EDITED = _Edited(name="filters.UpdateType.EDITED") - """Updates with :attr:`telegram.Update.edited_message`, - :attr:`telegram.Update.edited_channel_post`, or - :attr:`telegram.Update.edited_business_message`. - - .. versionadded:: 20.0 - - .. versionchanged:: 21.1 - Added :attr:`telegram.Update.edited_business_message` to the filter. - """ - - class _EditedChannelPost(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.edited_channel_post is not None - - EDITED_CHANNEL_POST = _EditedChannelPost(name="filters.UpdateType.EDITED_CHANNEL_POST") - """Updates with :attr:`telegram.Update.edited_channel_post`.""" - - class _EditedMessage(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.edited_message is not None - - EDITED_MESSAGE = _EditedMessage(name="filters.UpdateType.EDITED_MESSAGE") - """Updates with :attr:`telegram.Update.edited_message`.""" - - class _Message(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.message is not None - - MESSAGE = _Message(name="filters.UpdateType.MESSAGE") - """Updates with :attr:`telegram.Update.message`.""" - - class _Messages(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.message is not None or update.edited_message is not None - - MESSAGES = _Messages(name="filters.UpdateType.MESSAGES") - """Updates with either :attr:`telegram.Update.message` or - :attr:`telegram.Update.edited_message`. - """ - - class _BusinessMessage(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.business_message is not None - - BUSINESS_MESSAGE = _BusinessMessage(name="filters.UpdateType.BUSINESS_MESSAGE") - """Updates with :attr:`telegram.Update.business_message`. - - .. versionadded:: 21.1""" - - class _EditedBusinessMessage(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return update.edited_business_message is not None - - EDITED_BUSINESS_MESSAGE = _EditedBusinessMessage( - name="filters.UpdateType.EDITED_BUSINESS_MESSAGE" - ) - """Updates with :attr:`telegram.Update.edited_business_message`. - - .. versionadded:: 21.1 - """ - - class _BusinessMessages(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return ( - update.business_message is not None or update.edited_business_message is not None - ) - - BUSINESS_MESSAGES = _BusinessMessages(name="filters.UpdateType.BUSINESS_MESSAGES") - """Updates with either :attr:`telegram.Update.business_message` or - :attr:`telegram.Update.edited_business_message`. - - .. versionadded:: 21.1 - """ - - -class User(_ChatUserBaseFilter): - """Filters messages to allow only those which are from specified user ID(s) or - username(s). - - Examples: - ``MessageHandler(filters.User(1234), callback_method)`` - - Args: - user_id(:obj:`int` | Collection[:obj:`int`], optional): Which user ID(s) to - allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user is - specified in :attr:`user_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Raises: - RuntimeError: If ``user_id`` and ``username`` are both present. - - Attributes: - allow_empty (:obj:`bool`): Whether updates should be processed, if no user is specified in - :attr:`user_ids` and :attr:`usernames`. - """ - - __slots__ = () - - def __init__( - self, - user_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - allow_empty: bool = False, - ): - super().__init__(chat_id=user_id, username=username, allow_empty=allow_empty) - self._chat_id_name = "user_id" - - def _get_chat_or_user(self, message: Message) -> Optional[TGUser]: - return message.from_user - - @property - def user_ids(self) -> frozenset[int]: - """ - Which user ID(s) to allow through. - - Warning: - :attr:`user_ids` will give a *copy* of the saved user ids as :obj:`frozenset`. This - is to ensure thread safety. To add/remove a user, you should use :meth:`add_user_ids`, - and :meth:`remove_user_ids`. Only update the entire set by - ``filter.user_ids = new_set``, if you are entirely sure that it is not causing race - conditions, as this will complete replace the current set of allowed users. - - Returns: - frozenset(:obj:`int`) - """ - return self.chat_ids - - @user_ids.setter - def user_ids(self, user_id: SCT[int]) -> None: - self.chat_ids = user_id # type: ignore[assignment] - - def add_user_ids(self, user_id: SCT[int]) -> None: - """ - Add one or more users to the allowed user ids. - - Args: - user_id(:obj:`int` | Collection[:obj:`int`]): Which user ID(s) to allow - through. - """ - return super()._add_chat_ids(user_id) - - def remove_user_ids(self, user_id: SCT[int]) -> None: - """ - Remove one or more users from allowed user ids. - - Args: - user_id(:obj:`int` | Collection[:obj:`int`]): Which user ID(s) to - disallow through. - """ - return super()._remove_chat_ids(user_id) - - -class _User(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.from_user) - - -USER = _User(name="filters.USER") -"""This filter filters *any* message that has a :attr:`telegram.Message.from_user`.""" - - -class _UserAttachment(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return bool(update.effective_user) and bool( - update.effective_user.added_to_attachment_menu # type: ignore - ) - - -USER_ATTACHMENT = _UserAttachment(name="filters.USER_ATTACHMENT") -"""This filter filters *any* message that have a user who added the bot to their -:attr:`attachment menu ` as -:attr:`telegram.Update.effective_user`. - -.. versionadded:: 20.0 -""" - - -class _UserPremium(UpdateFilter): - __slots__ = () - - def filter(self, update: Update) -> bool: - return bool(update.effective_user) and bool( - update.effective_user.is_premium # type: ignore - ) - - -PREMIUM_USER = _UserPremium(name="filters.PREMIUM_USER") -"""This filter filters *any* message from a -:attr:`Telegram Premium user ` as :attr:`telegram.Update.effective_user`. - -.. versionadded:: 20.0 -""" - - -class _Venue(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.venue) - - -VENUE = _Venue(name="filters.VENUE") -"""Messages that contain :attr:`telegram.Message.venue`.""" - - -class ViaBot(_ChatUserBaseFilter): - """Filters messages to allow only those which are from specified via_bot ID(s) or username(s). - - Examples: - ``MessageHandler(filters.ViaBot(1234), callback_method)`` - - .. seealso:: :attr:`~telegram.ext.filters.VIA_BOT` - - Args: - bot_id(:obj:`int` | Collection[:obj:`int`], optional): Which bot ID(s) to - allow through. - username(:obj:`str` | Collection[:obj:`str`], optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be - discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user - is specified in :attr:`bot_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Raises: - RuntimeError: If ``bot_id`` and ``username`` are both present. - - Attributes: - allow_empty (:obj:`bool`): Whether updates should be processed, if no bot is specified in - :attr:`bot_ids` and :attr:`usernames`. - """ - - __slots__ = () - - def __init__( - self, - bot_id: Optional[SCT[int]] = None, - username: Optional[SCT[str]] = None, - allow_empty: bool = False, - ): - super().__init__(chat_id=bot_id, username=username, allow_empty=allow_empty) - self._chat_id_name = "bot_id" - - def _get_chat_or_user(self, message: Message) -> Optional[TGUser]: - return message.via_bot - - @property - def bot_ids(self) -> frozenset[int]: - """ - Which bot ID(s) to allow through. - - Warning: - :attr:`bot_ids` will give a *copy* of the saved bot ids as :obj:`frozenset`. This - is to ensure thread safety. To add/remove a bot, you should use :meth:`add_bot_ids`, - and :meth:`remove_bot_ids`. Only update the entire set by ``filter.bot_ids = new_set``, - if you are entirely sure that it is not causing race conditions, as this will complete - replace the current set of allowed bots. - - Returns: - frozenset(:obj:`int`) - """ - return self.chat_ids - - @bot_ids.setter - def bot_ids(self, bot_id: SCT[int]) -> None: - self.chat_ids = bot_id # type: ignore[assignment] - - def add_bot_ids(self, bot_id: SCT[int]) -> None: - """ - Add one or more bots to the allowed bot ids. - - Args: - bot_id(:obj:`int` | Collection[:obj:`int`]): Which bot ID(s) to allow - through. - """ - return super()._add_chat_ids(bot_id) - - def remove_bot_ids(self, bot_id: SCT[int]) -> None: - """ - Remove one or more bots from allowed bot ids. - - Args: - bot_id(:obj:`int` | Collection[:obj:`int`], optional): Which bot ID(s) to - disallow through. - """ - return super()._remove_chat_ids(bot_id) - - -class _ViaBot(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.via_bot) - - -VIA_BOT = _ViaBot(name="filters.VIA_BOT") -"""This filter filters for message that were sent via *any* bot. - -.. seealso:: :class:`~telegram.ext.filters.ViaBot`""" - - -class _Video(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video) - - -VIDEO = _Video(name="filters.VIDEO") -"""Messages that contain :attr:`telegram.Message.video`.""" - - -class _VideoNote(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.video_note) - - -VIDEO_NOTE = _VideoNote(name="filters.VIDEO_NOTE") -"""Messages that contain :attr:`telegram.Message.video_note`.""" - - -class _Voice(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.voice) - - -VOICE = _Voice("filters.VOICE") -"""Messages that contain :attr:`telegram.Message.voice`.""" - - -class _ReplyToStory(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.reply_to_story) - - -REPLY_TO_STORY = _ReplyToStory(name="filters.REPLY_TO_STORY") -"""Messages that contain :attr:`telegram.Message.reply_to_story`.""" - - -class _BoostAdded(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.boost_added) - - -BOOST_ADDED = _BoostAdded(name="filters.BOOST_ADDED") -"""Messages that contain :attr:`telegram.Message.boost_added`.""" - - -class _SenderBoostCount(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - return bool(message.sender_boost_count) - - -SENDER_BOOST_COUNT = _SenderBoostCount(name="filters.SENDER_BOOST_COUNT") -"""Messages that contain :attr:`telegram.Message.sender_boost_count`.""" diff --git a/venv/lib/python3.11/site-packages/telegram/helpers.py b/venv/lib/python3.11/site-packages/telegram/helpers.py deleted file mode 100755 index 81dd4b6..0000000 --- a/venv/lib/python3.11/site-packages/telegram/helpers.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains convenience helper functions. - -.. versionchanged:: 20.0 - Previously, the contents of this module were available through the (no longer existing) - module ``telegram.utils.helpers``. -""" - -__all__ = ( - "create_deep_linked_url", - "effective_message_type", - "escape_markdown", - "mention_html", - "mention_markdown", -) - -import re -from html import escape -from typing import TYPE_CHECKING, Optional, Union - -from telegram._utils.types import MarkdownVersion -from telegram.constants import MessageLimit, MessageType - -if TYPE_CHECKING: - from telegram import Message, Update - - -def escape_markdown( - text: str, version: MarkdownVersion = 1, entity_type: Optional[str] = None -) -> str: - """Helper function to escape telegram markup symbols. - - .. versionchanged:: 20.3 - Custom emoji entity escaping is now supported. - - Args: - text (:obj:`str`): The text. - version (:obj:`int` | :obj:`str`): Use to specify the version of telegrams Markdown. - Either ``1`` or ``2``. Defaults to ``1``. - entity_type (:obj:`str`, optional): For the entity types - :tg-const:`telegram.MessageEntity.PRE`, :tg-const:`telegram.MessageEntity.CODE` and - the link part of :tg-const:`telegram.MessageEntity.TEXT_LINK` and - :tg-const:`telegram.MessageEntity.CUSTOM_EMOJI`, only certain characters need to be - escaped in :tg-const:`telegram.constants.ParseMode.MARKDOWN_V2`. See the `official API - documentation `_ for details. - Only valid in combination with ``version=2``, will be ignored else. - """ - if int(version) == 1: - escape_chars = r"_*`[" - elif int(version) == 2: - if entity_type in ["pre", "code"]: - escape_chars = r"\`" - elif entity_type in ["text_link", "custom_emoji"]: - escape_chars = r"\)" - else: - escape_chars = r"\_*[]()~`>#+-=|{}.!" - else: - raise ValueError("Markdown version must be either 1 or 2!") - - return re.sub(f"([{re.escape(escape_chars)}])", r"\\\1", text) - - -def mention_html(user_id: Union[int, str], name: str) -> str: - """ - Helper function to create a user mention as HTML tag. - - Args: - user_id (:obj:`int`): The user's id which you want to mention. - name (:obj:`str`): The name the mention is showing. - - Returns: - :obj:`str`: The inline mention for the user as HTML. - """ - return f'{escape(name)}' - - -def mention_markdown(user_id: Union[int, str], name: str, version: MarkdownVersion = 1) -> str: - """ - Helper function to create a user mention in Markdown syntax. - - Args: - user_id (:obj:`int`): The user's id which you want to mention. - name (:obj:`str`): The name the mention is showing. - version (:obj:`int` | :obj:`str`): Use to specify the version of Telegram's Markdown. - Either ``1`` or ``2``. Defaults to ``1``. - - Returns: - :obj:`str`: The inline mention for the user as Markdown. - """ - tg_link = f"tg://user?id={user_id}" - if version == 1: - return f"[{name}]({tg_link})" - return f"[{escape_markdown(name, version=version)}]({tg_link})" - - -def effective_message_type(entity: Union["Message", "Update"]) -> Optional[str]: - """ - Extracts the type of message as a string identifier from a :class:`telegram.Message` or a - :class:`telegram.Update`. - - Args: - entity (:class:`telegram.Update` | :class:`telegram.Message`): The ``update`` or - ``message`` to extract from. - - Returns: - :obj:`str` | :obj:`None`: One of :class:`telegram.constants.MessageType` if the entity - contains a message that matches one of those types. :obj:`None` otherwise. - - """ - # Importing on file-level yields cyclic Import Errors - from telegram import Message, Update # pylint: disable=import-outside-toplevel - - if isinstance(entity, Message): - message = entity - elif isinstance(entity, Update): - if not entity.effective_message: - return None - message = entity.effective_message - else: - raise TypeError(f"The entity is neither Message nor Update (got: {type(entity)})") - - for message_type in MessageType: - if message[message_type]: - return message_type - - return None - - -def create_deep_linked_url( - bot_username: str, payload: Optional[str] = None, group: bool = False -) -> str: - """ - Creates a deep-linked URL for this :paramref:`~create_deep_linked_url.bot_username` with the - specified :paramref:`~create_deep_linked_url.payload`. See - https://core.telegram.org/bots/features#deep-linking to learn more. - - The :paramref:`~create_deep_linked_url.payload` may consist of the following characters: - ``A-Z, a-z, 0-9, _, -`` - - Note: - Works well in conjunction with - ``CommandHandler("start", callback, filters=filters.Regex('payload'))`` - - Examples: - * ``create_deep_linked_url(bot.get_me().username, "some-params")`` - * :any:`Deep Linking ` - - Args: - bot_username (:obj:`str`): The username to link to. - payload (:obj:`str`, optional): Parameters to encode in the created URL. - group (:obj:`bool`, optional): If :obj:`True` the user is prompted to select a group to - add the bot to. If :obj:`False`, opens a one-on-one conversation with the bot. - Defaults to :obj:`False`. - - Returns: - :obj:`str`: An URL to start the bot with specific parameters. - - Raises: - :exc:`ValueError`: If the length of the :paramref:`payload` exceeds \ - :tg-const:`telegram.constants.MessageLimit.DEEP_LINK_LENGTH` characters, - contains invalid characters, or if the :paramref:`bot_username` is less than 4 - characters. - """ - if bot_username is None or len(bot_username) <= 3: - raise ValueError("You must provide a valid bot_username.") - - base_url = f"https://t.me/{bot_username}" - if not payload: - return base_url - - if len(payload) > MessageLimit.DEEP_LINK_LENGTH: - raise ValueError( - f"The deep-linking payload must not exceed {MessageLimit.DEEP_LINK_LENGTH} characters." - ) - - if not re.match(r"^[A-Za-z0-9_-]+$", payload): - raise ValueError( - "Only the following characters are allowed for deep-linked " - "URLs: A-Z, a-z, 0-9, _ and -" - ) - - key = "startgroup" if group else "start" - - return f"{base_url}?{key}={payload}" diff --git a/venv/lib/python3.11/site-packages/telegram/py.typed b/venv/lib/python3.11/site-packages/telegram/py.typed deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/request/__init__.py b/venv/lib/python3.11/site-packages/telegram/request/__init__.py deleted file mode 100755 index 87040d7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# !/usr/bin/env python -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains classes that handle the networking backend of ``python-telegram-bot``.""" - -from ._baserequest import BaseRequest -from ._httpxrequest import HTTPXRequest -from ._requestdata import RequestData - -__all__ = ("BaseRequest", "HTTPXRequest", "RequestData") diff --git a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/request/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 29230bce01407ba1cc479c37101d241ef17eff8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 533 zcmY*V%Sr<=6iqsPh_-%17K(Jy26dw#F2schif9)yF4D{-c1APFn54c|euNnlxa_+e~d1*A}5v=#e=ZnoULZ3x3U8M>5Sp)Ed1PYPBqNH$E z3QM@afeNy6SRUcBs$|u$3b+#1MD+wUYxifJBy}V+qOT;0jrKg%j>L*PCmrz#_axz3 zz@<+l(bC@-dztDUiFkY|wIJr4bi4VTPmFGPsbtUctQ8sG?Y6%#ysC+Z3p?D&V|mq= z&O=$>>vWDz|LcVb+~uA(0~jN zgInH{j!rGo$q33=s#DKcJHPv#+Zuo5wq1lFg?o1Z={vv}e=i{%;Q`_wXn8OjZ)jyO T8*j4&;D5|-Jk*M9>!A1t>`tFc diff --git a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_baserequest.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_baserequest.cpython-311.pyc deleted file mode 100755 index 003daa121dfa1eb5a4f7d24a1f71c011324ad71a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20242 zcmeHPTWlNGnI7IGUUi`;S(YtnEZLT*3+32JoGMOQ$&wu>vFzHildvhs5ocu4COO)f zp=BvlYNSS2T@+Yvks{i*X|)A5Ns$!j(_$ZXfwoV5qznS#4q(8*Vi((&1p_xg(3jos zKQluPDLHYIX1fJE8l5@!^Pk&)JOAOkp^%@$^KWnd@Tzj2?g!%oM&TLn_i}?eYJ=yMfcXn@lFAE1V zJ=uNneas)q?9cYb`>W)H;=We>*>XNTfLEMIG8 zI2(;enZGSFk{ykYIyfgM1;utT{6WV%PL6vY|Hcy^LrO#%M@pn2CFbN#b7JQ$P7F(K zF}&9*!by&+6IS3IH)_Mb@x+ga&Wl{MYi)LZDXsEZSd^O1nZ>5m)m-W%>XUA0 zXN8<_MN*LLe{O#M{6$UB@+v~1c{Cs`2&rrHtIJZf*;7-OUYt+Notv9wVQEpwXSB;gCNEJ#S0pWwk*^rd2Im3AY%V2> z>D-m5Q};f9@!Z@@I;EkhnagK#%XtlD+$(~T!#9vfT$dCT?IjXXukN1~#0y48_29`R zK|7niq6nHK>R$A3F+_FT5Yi)}Wsn-sR*x3;7Y6$OX2>YZysbAuy{#u>V zfkjs>wAdnc-|{r{Za~^sg$p|!aD8z&1{Z_k-W@F++%W<@U&<&9F1CsLZh7K|q{HHV zX%KVVkCoHAV@`(ZX035{z8u(wrKmKx=(NpAo7lHwq(;OhU{YS`!>SX$3JhzZKt2uZ zrz`@+SvVBPgBLOxc}3-ySG6TMH?EmTV0=N=syNm{s}!LvN&Ga@rp}*<`FT7iftwd3 zKAm08NLdLji2U`mz>Dd{MM*)J7YOsFWu8zipGhw$f|8ch7(bP(6=Eobmlshzus=f^ ztnzGL)oQs2)*2niN`P1-+92}Fio7f-8rAD(1<&MEO~|DrwZ2k5Wk8!(0j7YmCTv7# zfRaH{7-dk$_?0CSY3 zG0D8Zr?7;;N)Y$?DCrpr}%UYECQ*s~K4kjb2q(cy(Z{ zs^u%`6zvVx8;Na^YtkxPdXs{tDU(TSTgA++6tmIR7#akH#Q3S!K-CZOO8Q!QGC8HB zmeLy5R$h_#bAb7JT3X>x*rT6Kj#XisG)hh9(-~1x`1626QgZwWGh*C~cs5y`R+GmN zz%_`N+oMNfM_6q?=hixR!w%Qi2KeD6OiU%QttW$D2KVqj>R5(Y(m9e7+(gf4o+U3u=dx4xxXe73joCo#Fkfee+@^ib=la} zSS|h*$AjUw0x_lpZn?IDUVC{Vxkfngblr!d>|8g6N_3% z(JrwbTF-39JPVJpV?NJ*5goL)*QP&XVbi1$YF+^zu_mx#RYT@dqJSmpX7j3y!>`21 zA;C{2*lFn~qwwfH8hl0});b&Kghdyq43##gB+RvT{B8Dcvfq`zCl|fF4|?yT1XqVy zXn8@_;O@7V%fINf@ktmZM*`-yB=+L}? z@a!Z5#|;ue>88|IkE$SRqOBF9>(v1iWiVd^LQX<2(R2foh_O=h3yjr6Mq=Vt(qQix zPO5g9+B8tvoUEOxv6xIoMJIvNQeg53ixC$_bFv^2GBb%f1mGC|oV+5TS7S6?i+Q4- zb@iJa2G7UluG#?x4uGyI9tcLZEIzF#cD%eBUY`VmIGJ1oTY*Ue$zZ`bOgK>VJf{8u z>#MeyAXj(nG8oDT7PNszjm;IbFORiu`~I@0{52IL#n(;lW1edrD0&YlM-kkyeHfad zj0T!9QN{~rsvIXkSLM7yJohe}fj>*E{LYaRs;eM2rwpL_#*QdMh^)uiHJbAGNV`u! z83^Jgdhy3VfA*p#FY|{Xa7cpkWx-GAa4ljVe+zfMjTGfLIW*$BE3ag9OdBKg2@z@+ zG7fFiTtEVv5pf~U~* zf%6^I^M181uvadNy;^SuiLtY7R%=|L`5nZ+Urk&07QCXnCa!|Wc!UHhJqyhp_B=-1 zU}}IJY;q;Pgq@Z_28uILFbQA`Nigo*ND^}Dilo>!+^*P(p>;!6G%yU-pvkr{bS?3g zAW0aM;UgQr4pGmA#>{%^Hv9jF z!D9enK}k?DL-9*Po05qXYsQ#EuFR6GyQ8lHNIz3H^QxS>CTUOe>6jE_8haYH+V;mB z8LP^Orll6O=ETt77;~_rh0ir758#2U@uzPChW)~`umf;&N%IfCgiVlW0!Wn4E;IEU zs3%*&I~u?wsd=zQOgLkU+dhz=V=?d6!e=jLJ7xO9qX_NX7exfNQN#!>fOp5v7Oo5F zjIe<7raw0xs1EWjDgj~+na-?=%uMW5)y7s!>ux#~`+2kS6_94V$)In_Bm#_~P@X0q zosKBaz?mamjEb`=97MGxENZi&K=Q`1P?!P{(87ALW z_n5(=x=B=7YqPUP6!Q-#sosENN_`g`T=)JD_l(`yGgfZvD0l2F?>$6s&ro^)C_I%` zu6z6=&fD$(JvkN58-B2}(Nqa@oqIowjNXZizISRna;y|Nw&5cweD7v=i5TDkgN1AY z1lHq)hcQym!SnEp6xb-#@_w}@I~xUN$SwQ?NtkOW#IGBY9~P(vT`JQZ3Q*HxQG!cJ zBLXafjj{O4Wp!4h1wJDihlug7zYLaTIoec5LqCPf4qq|^O6K!Iwgfa!{w<`+)t?x;s zA>TpD!Z-ucT{N&7Dp5jX)TMhgTYL36l?jbb$;?L!Sw0RL7|~teu2$Q*TCD@7 zGM=|x_4SBNA2ip;z^u!=?qLUN)WaQ5!KVKyG=JdRp#kz+8lYFv_jUhzAUAEPbrw60p^i0fVtYBePgCk6_^A35K4*6WH2!8e?ue?9nmaK&LAxoJJMdakxu z{(?W{yy3jYv`k8q7&LvJ9NNw~3xSJt(AR3^wtowO`Zm`?h0qqA2<&*oP(#j^LW|-o zwB#IO%X;erOSLwXYAduU^M$qtw9(d(yS>n^v}%JjU<&Q^Io@zQu&#!j>)}Eebse(R z72Z)-s~9e{{fK+pxrSASUis_ByTdAbjjeRlMv6@HDKzvHkkyy&v~t$fSzQ;4&g&d% ztQrGi&wN&mRU@h@Jjbjy9-?%0B~?q4-qn0Qv+ey>PP25oeLWXimK|b8F!3tOkGfQ1&m9c^Gr%-g7 zO4@quD6<-}Qkec|h=kjrF@6Yy2_H#I#iBL134Tk4CAkw?hesMyYf>Lx-DFMiBaNvw zc7KGf?vcjy3+wu-c*q+5M{>?1IfpFi9%Q)yE!s{aDkk9=Cv2uEA02BMM@CSmGTLGu z0a*yoM$<0rVpnC6LS}$avx`uON5aW`kg9z7f^jCc=7tU3@wH*n+$QUeb&|EyHS^4i zPF2=^5))-h0c)I9T2?1WP1@C@b)#UZtx3aw^aw(xm4ju^N3U?Pd5^(xl}1p?eeT?gM=O+QcfviYmk8 z5KF5-#^iM8xfhff^0;tML}7zU5)LXjUYeV_ zH2>VW3uof9Gs+%H4NOnXBreQ;{nG5kd4>3Q+z2^0ck0D6C+8Jn$c+rAr{-s0ntCPL zVUyLFVE>>40%Hh#OM;qUY69I&yrSN0ZYkXb!!$i)Z6L#N;T$#BoP}u)-L%1VDo*)2 zITzrl1e%4{ZC|DmV0whL{r1IfZHa_=Cee%qq~6DlGqnP*Iym3aqW3ZTTWR4s4-_L` z+j_Nh=xZCkd%@0%tHsyrQ5dMliRtPd>*)`iR@(Sa5z)^hKL`-=VNe(QpRcRPH(6h2?P z{7NzS3hWR+skkU7JQ$K-*Y}>;oGAu|@ZMqW)=A@Q#KFDS(X%mk4+k^d6L-2Ne%ZX; z{Zy&@sg2ORuE7txhVFC?y%*ZU?~|Uk-Gl$G&ek$_GZ@?fY3@@yN{ff!Wf5*_ z_GG!|;7?;ejJ?;p-E+LubA024a%&Iei{0(wxAtv!jhDK{i*4igf*r*@@!wvBgLgX^ z-#C3Q(E5YPQis{KyWxGCr?ao-WV??sF+-0hafN-ea&Rl*s+jvktB<$lu|nSR>! zo57ChCtbgJ(gVLDBC*bJ%Yz8Q+V}qx&RY+(rMBBj*A!c#qh5iu?(lJTHP%%^UF<11 z>V?{i927%jmSsLr0v%a*YJ@4xXRE5lvSR2fI#Clg_WMlbKrs$ZBh+d>qN~20f)h$3 z_qy|SXH97Y6Qlhoe!eQbnun&u9)K3qS%BDxecjyzLQ2!sO9iH3pecmHw#^W>ce|9Z zn9srNnhrf~}gcnKDeFlI51g(12xNK3-?w5(WnVyLp6a=OJBnPRu06t>Kg=1+}3 zWnOC#jniiVk%W-NQN0ZXe;&5bk%H*J1MI7);HS-?5*&O?|gLHd|j8vITQ`)#GSt~fn4;)el z*7lfJC>vRfxu{QXGUiGl^(1bE&Ywy=rMqbX=pMELbpK^C@HM!a=ERHVPM@B=p!+~F z4Lf|s4n&QutNV<~#DuCys86M>i%ByGBk>1oeRjeKex%{1%6Et~zJ`pjUq8ro?tg3U z`*Z(zqBQu#FITrCQ>DlhPP(0L-;CpK$DTJQH`Ci4!=;YlVsIEX?0d<4eTK+e)x8_+ z_%PUeC)iu;oB36GJ9xenJYNi+zZ>o^@?Y5wPnN=yzj76WCmH#GJ^Kui50zMrpLIOR z{gZ#{i0jwf=+vm|*P|Zz>$L2E)HqTnJYlyf75*Ez;nOVyV-I0XT4T;X$62{~gUK+Z zCc9rVg1AmPt53%GGn!?z{b#TVv=m}>hJ=jWwo;g?ESWTvWl2~B!cPh_@;*|TN#Y|T z!>UE`7gpB%2@JCysm#9cEYvXzMC%`^%pR%C{%Dn%21{J&8wOp$eQ{6=yRpDG4P_dm zGzR+zH47~B53_S3i#H@aiDhoOi+!r4DX6ix#?6nY_hB^>Djj{(5~s)Dj$T1b{VkE2 z%H^lvHEQ=PqE3a*MdzZU%FFoD)j;FtMxdt&CK7a0ihi*Iq2@$FlvD6Pr=wce7i5A>!+1 zt4txuZOUVm?6vMA;kQP>P-@KlLU#!ZDZRzInPkv>c2S01zEg;$QudKUr`rl0_bYTF zuDdg7Rny%IxGbSLp{ zyOR~C!{fadd-~>!w-0Rwx8_UTBc(iwR$3(N`=E`Yk_?lodKVx z?;d3D$G1YIeX&w_qT)de>^u=SUTPn%G*i&aweQ{REwv3*d=&I^{+3FBd|bWL#Wl55 zoUNXL&84mUk7a6Xpyqt!Lh`MbS%%60*W@dC_E0yN;-%_RuI^e&Q!U@Cq^9v$u00>( zkS_o@CyteeA1_CrD32b8r_%bkXRyM-xfg1ycqq`s?djiqt<*JIX{Ml;g84V)ijP8m zuAATTy!ow4fI>m8XJG5lkNYbj3bj}{S)Fa1zjforW@K~e$9>R1w2qg2u}VATqt=*1 z00wSdsyHbk<1pX@WL4loV;-2^z+u2qfB{F)G*ifHLF1#4--0GUp`Zl~tE2_cR9Y#X zs$)*Ib&3!jjRVuZ?(iI~aOASqSrAITNTr#1*|@M_^0BbrYA?WoK?}4H3$|FWwX$HF zmDy+|Owe_(6xN{8tm(dvQ3_X_U7i`o)@+5N?|Vze*X~kx!na;EGFFb5i^9L7TTxH2 zg8NfJ)+q`YeIlQ&OBAg2h(fgvQK;4*3e~zpA?nSBdV6+bt>o*ebWjvE$eh}mv|?B^ zv!IGTrsN3)e2bh69Q^Q)@p~HdYab-T>Tdd-07KR7A$+GQgyHli_#v$`G|I4{LWteK zSA@g#{Z(~*BCn-0Dl{YPXO-BcSp%o8Q3=v4>3bS8)9)=&^<+e~GZk1HiK-#FcQ%$a zpd_TpaH!thm|?~E0VI{F{`K}+vU#6W2~*h>YPzMG$aFtUHE$^SNmOQP#BdV`liTmbl24MNrs~vkoOt3ZV*Oj@_7&^jGS^?Mf6LrgiVyeR z<4zUp-!k_^vHmS{v10vO=8hEW-!k`jaksb3MT_?Fm_r{CJSlQit>-0w+%JlmOWM%vMe*rXm|L6b! diff --git a/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_httpxrequest.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/request/__pycache__/_httpxrequest.cpython-311.pyc deleted file mode 100755 index 860fd7480dbbc9f5c9e5cffab432850de37e207a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14366 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 Qf!|$sdmEn4Axv5S52fmSb^rhX diff --git a/venv/lib/python3.11/site-packages/telegram/request/_baserequest.py b/venv/lib/python3.11/site-packages/telegram/request/_baserequest.py deleted file mode 100755 index 3872918..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/_baserequest.py +++ /dev/null @@ -1,457 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an abstract class to make POST and GET requests.""" -import abc -import json -from contextlib import AbstractAsyncContextManager -from http import HTTPStatus -from types import TracebackType -from typing import Final, Optional, TypeVar, Union, final - -from telegram._utils.defaultvalue import DEFAULT_NONE as _DEFAULT_NONE -from telegram._utils.defaultvalue import DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.strings import TextEncoding -from telegram._utils.types import JSONDict, ODVInput -from telegram._utils.warnings import warn -from telegram._version import __version__ as ptb_ver -from telegram.error import ( - BadRequest, - ChatMigrated, - Conflict, - Forbidden, - InvalidToken, - NetworkError, - RetryAfter, - TelegramError, -) -from telegram.request._requestdata import RequestData -from telegram.warnings import PTBDeprecationWarning - -RT = TypeVar("RT", bound="BaseRequest") - -_LOGGER = get_logger(__name__, class_name="BaseRequest") - - -class BaseRequest( - AbstractAsyncContextManager["BaseRequest"], - abc.ABC, -): - """Abstract interface class that allows python-telegram-bot to make requests to the Bot API. - Can be implemented via different asyncio HTTP libraries. An implementation of this class - must implement all abstract methods and properties. - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with request_object: - # code - - is roughly equivalent to - - .. code:: python - - try: - await request_object.initialize() - # code - finally: - await request_object.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - Tip: - JSON encoding and decoding is done with the standard library's :mod:`json` by default. - To use a custom library for this, you can override :meth:`parse_json_payload` and implement - custom logic to encode the keys of :attr:`telegram.request.RequestData.parameters`. - - .. seealso:: :wiki:`Architecture Overview `, - :wiki:`Builder Pattern ` - - .. versionadded:: 20.0 - """ - - __slots__ = () - - USER_AGENT: Final[str] = f"python-telegram-bot v{ptb_ver} (https://python-telegram-bot.org)" - """:obj:`str`: A description that can be used as user agent for requests made to the Bot API. - """ - DEFAULT_NONE: Final[DefaultValue[None]] = _DEFAULT_NONE - """:class:`object`: A special object that indicates that an argument of a function was not - explicitly passed. Used for the timeout parameters of :meth:`post` and :meth:`do_request`. - - Example: - When calling ``request.post(url)``, ``request`` should use the default timeouts set on - initialization. When calling ``request.post(url, connect_timeout=5, read_timeout=None)``, - ``request`` should use ``5`` for the connect timeout and :obj:`None` for the read timeout. - - Use ``if parameter is (not) BaseRequest.DEFAULT_NONE:`` to check if the parameter was set. - """ - - async def __aenter__(self: RT) -> RT: - """|async_context_manager| :meth:`initializes ` the Request. - - Returns: - The initialized Request instance. - - Raises: - :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. - """ - try: - await self.initialize() - except Exception: - await self.shutdown() - raise - return self - - async def __aexit__( - self, - exc_type: Optional[type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - """|async_context_manager| :meth:`shuts down ` the Request.""" - # Make sure not to return `True` so that exceptions are not suppressed - # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ - await self.shutdown() - - @property - def read_timeout(self) -> Optional[float]: - """This property must return the default read timeout in seconds used by this class. - More precisely, the returned value should be the one used when - :paramref:`post.read_timeout` of :meth:post` is not passed/equal to :attr:`DEFAULT_NONE`. - - .. versionadded:: 20.7 - - Warning: - For now this property does not need to be implemented by subclasses and will raise - :exc:`NotImplementedError` if accessed without being overridden. However, in future - versions, this property will be abstract and must be implemented by subclasses. - - Returns: - :obj:`float` | :obj:`None`: The read timeout in seconds. - """ - raise NotImplementedError - - @abc.abstractmethod - async def initialize(self) -> None: - """Initialize resources used by this class. Must be implemented by a subclass.""" - - @abc.abstractmethod - async def shutdown(self) -> None: - """Stop & clear resources used by this class. Must be implemented by a subclass.""" - - @final - async def post( - self, - url: str, - request_data: Optional[RequestData] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - ) -> Union[JSONDict, list[JSONDict], bool]: - """Makes a request to the Bot API handles the return code and parses the answer. - - Warning: - This method will be called by the methods of :class:`telegram.Bot` and should *not* be - called manually. - - Args: - url (:obj:`str`): The URL to request. - request_data (:class:`telegram.request.RequestData`, optional): An object containing - information about parameters and files to upload for the request. - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file) instead of the time - specified during creating of this object. Defaults to :attr:`DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed instead of the time specified during creating of this object. Defaults - to :attr:`DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - - Returns: - The JSON response of the Bot API. - - """ - result = await self._request_wrapper( - url=url, - method="POST", - request_data=request_data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - json_data = self.parse_json_payload(result) - # For successful requests, the results are in the 'result' entry - # see https://core.telegram.org/bots/api#making-requests - return json_data["result"] - - @final - async def retrieve( - self, - url: str, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - ) -> bytes: - """Retrieve the contents of a file by its URL. - - Warning: - This method will be called by the methods of :class:`telegram.Bot` and should *not* be - called manually. - - Args: - url (:obj:`str`): The web location we want to retrieve. - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file) instead of the time - specified during creating of this object. Defaults to :attr:`DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed instead of the time specified during creating of this object. Defaults - to :attr:`DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - - Returns: - :obj:`bytes`: The files contents. - - """ - return await self._request_wrapper( - url=url, - method="GET", - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - - async def _request_wrapper( - self, - url: str, - method: str, - request_data: Optional[RequestData] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - ) -> bytes: - """Wraps the real implementation request method. - - Performs the following tasks: - * Handle the various HTTP response codes. - * Parse the Telegram server response. - - Args: - url (:obj:`str`): The URL to request. - method (:obj:`str`): HTTP method (i.e. 'POST', 'GET', etc.). - request_data (:class:`telegram.request.RequestData`, optional): An object containing - information about parameters and files to upload for the request. - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file) instead of the time - specified during creating of this object. Defaults to :attr:`DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed instead of the time specified during creating of this object. Defaults - to :attr:`DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - - Returns: - bytes: The payload part of the HTTP server response. - - Raises: - TelegramError - - """ - # Import needs to be here since HTTPXRequest is a subclass of BaseRequest - from telegram.request import HTTPXRequest # pylint: disable=import-outside-toplevel - - # 20 is the documented default value for all the media related bot methods and custom - # implementations of BaseRequest may explicitly rely on that. Hence, we follow the - # standard deprecation policy and deprecate starting with version 20.7. - # For our own implementation HTTPXRequest, we can handle that ourselves, so we skip the - # warning in that case. - has_files = request_data and request_data.multipart_data - if ( - has_files - and not isinstance(self, HTTPXRequest) - and isinstance(write_timeout, DefaultValue) - ): - warn( - PTBDeprecationWarning( - "20.7", - f"The `write_timeout` parameter passed to {self.__class__.__name__}.do_request" - " will default to `BaseRequest.DEFAULT_NONE` instead of 20 in future versions " - "for *all* methods of the `Bot` class, including methods sending media.", - ), - stacklevel=3, - ) - write_timeout = 20 - - try: - code, payload = await self.do_request( - url=url, - method=method, - request_data=request_data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - except TelegramError: - raise - except Exception as exc: - raise NetworkError(f"Unknown error in HTTP implementation: {exc!r}") from exc - - if HTTPStatus.OK <= code <= 299: - # 200-299 range are HTTP success statuses - return payload - - response_data = self.parse_json_payload(payload) - - description = response_data.get("description") - message = description if description else "Unknown HTTPError" - - # In some special cases, we can raise more informative exceptions: - # see https://core.telegram.org/bots/api#responseparameters and - # https://core.telegram.org/bots/api#making-requests - # TGs response also has the fields 'ok' and 'error_code'. - # However, we rather rely on the HTTP status code for now. - parameters = response_data.get("parameters") - if parameters: - migrate_to_chat_id = parameters.get("migrate_to_chat_id") - if migrate_to_chat_id: - raise ChatMigrated(migrate_to_chat_id) - retry_after = parameters.get("retry_after") - if retry_after: - raise RetryAfter(retry_after) - - message += f"\nThe server response contained unknown parameters: {parameters}" - - if code == HTTPStatus.FORBIDDEN: # 403 - raise Forbidden(message) - if code in (HTTPStatus.NOT_FOUND, HTTPStatus.UNAUTHORIZED): # 404 and 401 - # TG returns 404 Not found for - # 1) malformed tokens - # 2) correct tokens but non-existing method, e.g. api.tg.org/botTOKEN/unkonwnMethod - # 2) is relevant only for Bot.do_api_request, where we have special handing for it. - # TG returns 401 Unauthorized for correctly formatted tokens that are not valid - raise InvalidToken(message) - if code == HTTPStatus.BAD_REQUEST: # 400 - raise BadRequest(message) - if code == HTTPStatus.CONFLICT: # 409 - raise Conflict(message) - if code == HTTPStatus.BAD_GATEWAY: # 502 - raise NetworkError(description or "Bad Gateway") - raise NetworkError(f"{message} ({code})") - - @staticmethod - def parse_json_payload(payload: bytes) -> JSONDict: - """Parse the JSON returned from Telegram. - - Tip: - By default, this method uses the standard library's :func:`json.loads` and - ``errors="replace"`` in :meth:`bytes.decode`. - You can override it to customize either of these behaviors. - - Args: - payload (:obj:`bytes`): The UTF-8 encoded JSON payload as returned by Telegram. - - Returns: - dict: A JSON parsed as Python dict with results. - - Raises: - TelegramError: If loading the JSON data failed - """ - decoded_s = payload.decode(TextEncoding.UTF_8, "replace") - try: - return json.loads(decoded_s) - except ValueError as exc: - _LOGGER.exception('Can not load invalid JSON data: "%s"', decoded_s) - raise TelegramError("Invalid server response") from exc - - @abc.abstractmethod - async def do_request( - self, - url: str, - method: str, - request_data: Optional[RequestData] = None, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - ) -> tuple[int, bytes]: - """Makes a request to the Bot API. Must be implemented by a subclass. - - Warning: - This method will be called by :meth:`post` and :meth:`retrieve`. It should *not* be - called manually. - - Args: - url (:obj:`str`): The URL to request. - method (:obj:`str`): HTTP method (i.e. ``'POST'``, ``'GET'``, etc.). - request_data (:class:`telegram.request.RequestData`, optional): An object containing - information about parameters and files to upload for the request. - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file) instead of the time - specified during creating of this object. Defaults to :attr:`DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed instead of the time specified during creating of this object. Defaults - to :attr:`DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available instead - of the time specified during creating of this object. Defaults to - :attr:`DEFAULT_NONE`. - - Returns: - tuple[:obj:`int`, :obj:`bytes`]: The HTTP return code & the payload part of the server - response. - """ diff --git a/venv/lib/python3.11/site-packages/telegram/request/_httpxrequest.py b/venv/lib/python3.11/site-packages/telegram/request/_httpxrequest.py deleted file mode 100755 index b31efbf..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/_httpxrequest.py +++ /dev/null @@ -1,319 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains methods to make POST and GET requests using the httpx library.""" -from collections.abc import Collection -from typing import Any, Optional, Union - -import httpx - -from telegram._utils.defaultvalue import DefaultValue -from telegram._utils.logging import get_logger -from telegram._utils.types import HTTPVersion, ODVInput, SocketOpt -from telegram._utils.warnings import warn -from telegram.error import NetworkError, TimedOut -from telegram.request._baserequest import BaseRequest -from telegram.request._requestdata import RequestData -from telegram.warnings import PTBDeprecationWarning - -# Note to future devs: -# Proxies are currently only tested manually. The httpx development docs have a nice guide on that: -# https://www.python-httpx.org/contributing/#development-proxy-setup (also saved on archive.org) -# That also works with socks5. Just pass `--mode socks5` to mitmproxy - -_LOGGER = get_logger(__name__, "HTTPXRequest") - - -class HTTPXRequest(BaseRequest): - """Implementation of :class:`~telegram.request.BaseRequest` using the library - `httpx `_. - - .. versionadded:: 20.0 - - Args: - connection_pool_size (:obj:`int`, optional): Number of connections to keep in the - connection pool. Defaults to ``1``. - - Note: - Independent of the value, one additional connection will be reserved for - :meth:`telegram.Bot.get_updates`. - proxy_url (:obj:`str`, optional): Legacy name for :paramref:`proxy`, kept for backward - compatibility. Defaults to :obj:`None`. - - .. deprecated:: 20.7 - read_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a response from Telegram's server. - This value is used unless a different value is passed to :meth:`do_request`. - Defaults to ``5``. - write_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a write operation to complete (in terms of - a network socket; i.e. POSTing a request or uploading a file). - This value is used unless a different value is passed to :meth:`do_request`. - Defaults to ``5``. - - Hint: - This timeout is used for all requests except for those that upload media/files. - For the latter, :paramref:`media_write_timeout` is used. - connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the - maximum amount of time (in seconds) to wait for a connection attempt to a server - to succeed. This value is used unless a different value is passed to - :meth:`do_request`. Defaults to ``5``. - pool_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum - amount of time (in seconds) to wait for a connection to become available. - This value is used unless a different value is passed to :meth:`do_request`. - Defaults to ``1``. - - Warning: - With a finite pool timeout, you must expect :exc:`telegram.error.TimedOut` - exceptions to be thrown when more requests are made simultaneously than there are - connections in the connection pool! - http_version (:obj:`str`, optional): If ``"2"`` or ``"2.0"``, HTTP/2 will be used instead - of HTTP/1.1. Defaults to ``"1.1"``. - - .. versionadded:: 20.1 - .. versionchanged:: 20.2 - Reset the default version to 1.1. - - .. versionchanged:: 20.5 - Accept ``"2"`` as a valid value. - socket_options (Collection[:obj:`tuple`], optional): Socket options to be passed to the - underlying `library \ - `_. - - Note: - The values accepted by this parameter depend on the operating system. - This is a low-level parameter and should only be used if you are familiar with - these concepts. - - .. versionadded:: 20.7 - proxy (:obj:`str` | ``httpx.Proxy`` | ``httpx.URL``, optional): The URL to a proxy server, - a ``httpx.Proxy`` object or a ``httpx.URL`` object. For example - ``'http://127.0.0.1:3128'`` or ``'socks5://127.0.0.1:3128'``. Defaults to :obj:`None`. - - Note: - * The proxy URL can also be set via the environment variables ``HTTPS_PROXY`` or - ``ALL_PROXY``. See `the docs of httpx`_ for more info. - * HTTPS proxies can be configured by passing a ``httpx.Proxy`` object with - a corresponding ``ssl_context``. - * For Socks5 support, additional dependencies are required. Make sure to install - PTB via :command:`pip install "python-telegram-bot[socks]"` in this case. - * Socks5 proxies can not be set via environment variables. - - .. _the docs of httpx: https://www.python-httpx.org/environment_variables/#proxies - - .. versionadded:: 20.7 - media_write_timeout (:obj:`float` | :obj:`None`, optional): Like :paramref:`write_timeout`, - but used only for requests that upload media/files. This value is used unless a - different value is passed to :paramref:`do_request.write_timeout` of - :meth:`do_request`. Defaults to ``20`` seconds. - - .. versionadded:: 21.0 - httpx_kwargs (dict[:obj:`str`, Any], optional): Additional keyword arguments to be passed - to the `httpx.AsyncClient `_ - constructor. - - Warning: - This parameter is intended for advanced users that want to fine-tune the behavior - of the underlying ``httpx`` client. The values passed here will override all the - defaults set by ``python-telegram-bot`` and all other parameters passed to - :class:`HTTPXRequest`. The only exception is the :paramref:`media_write_timeout` - parameter, which is not passed to the client constructor. - No runtime warnings will be issued about parameters that are overridden in this - way. - - .. versionadded:: 21.6 - - """ - - __slots__ = ("_client", "_client_kwargs", "_http_version", "_media_write_timeout") - - def __init__( - self, - connection_pool_size: int = 1, - proxy_url: Optional[Union[str, httpx.Proxy, httpx.URL]] = None, - read_timeout: Optional[float] = 5.0, - write_timeout: Optional[float] = 5.0, - connect_timeout: Optional[float] = 5.0, - pool_timeout: Optional[float] = 1.0, - http_version: HTTPVersion = "1.1", - socket_options: Optional[Collection[SocketOpt]] = None, - proxy: Optional[Union[str, httpx.Proxy, httpx.URL]] = None, - media_write_timeout: Optional[float] = 20.0, - httpx_kwargs: Optional[dict[str, Any]] = None, - ): - if proxy_url is not None and proxy is not None: - raise ValueError("The parameters `proxy_url` and `proxy` are mutually exclusive.") - - if proxy_url is not None: - proxy = proxy_url - warn( - PTBDeprecationWarning( - "20.7", "The parameter `proxy_url` is deprecated. Use `proxy` instead." - ), - stacklevel=2, - ) - - self._http_version = http_version - self._media_write_timeout = media_write_timeout - timeout = httpx.Timeout( - connect=connect_timeout, - read=read_timeout, - write=write_timeout, - pool=pool_timeout, - ) - limits = httpx.Limits( - max_connections=connection_pool_size, - max_keepalive_connections=connection_pool_size, - ) - - if http_version not in ("1.1", "2", "2.0"): - raise ValueError("`http_version` must be either '1.1', '2.0' or '2'.") - - http1 = http_version == "1.1" - http_kwargs = {"http1": http1, "http2": not http1} - transport = ( - httpx.AsyncHTTPTransport( - socket_options=socket_options, - ) - if socket_options - else None - ) - self._client_kwargs = { - "timeout": timeout, - "proxy": proxy, - "limits": limits, - "transport": transport, - **http_kwargs, - **(httpx_kwargs or {}), - } - - try: - self._client = self._build_client() - except ImportError as exc: - if "httpx[http2]" not in str(exc) and "httpx[socks]" not in str(exc): - raise - - if "httpx[socks]" in str(exc): - raise RuntimeError( - "To use Socks5 proxies, PTB must be installed via `pip install " - '"python-telegram-bot[socks]"`.' - ) from exc - raise RuntimeError( - "To use HTTP/2, PTB must be installed via `pip install " - '"python-telegram-bot[http2]"`.' - ) from exc - - @property - def http_version(self) -> str: - """ - :obj:`str`: Used HTTP version, see :paramref:`http_version`. - - .. versionadded:: 20.2 - """ - return self._http_version - - @property - def read_timeout(self) -> Optional[float]: - """See :attr:`BaseRequest.read_timeout`. - - Returns: - :obj:`float` | :obj:`None`: The default read timeout in seconds as passed to - :paramref:`HTTPXRequest.read_timeout`. - """ - return self._client.timeout.read - - def _build_client(self) -> httpx.AsyncClient: - return httpx.AsyncClient(**self._client_kwargs) - - async def initialize(self) -> None: - """See :meth:`BaseRequest.initialize`.""" - if self._client.is_closed: - self._client = self._build_client() - - async def shutdown(self) -> None: - """See :meth:`BaseRequest.shutdown`.""" - if self._client.is_closed: - _LOGGER.debug("This HTTPXRequest is already shut down. Returning.") - return - - await self._client.aclose() - - async def do_request( - self, - url: str, - method: str, - request_data: Optional[RequestData] = None, - read_timeout: ODVInput[float] = BaseRequest.DEFAULT_NONE, - write_timeout: ODVInput[float] = BaseRequest.DEFAULT_NONE, - connect_timeout: ODVInput[float] = BaseRequest.DEFAULT_NONE, - pool_timeout: ODVInput[float] = BaseRequest.DEFAULT_NONE, - ) -> tuple[int, bytes]: - """See :meth:`BaseRequest.do_request`.""" - if self._client.is_closed: - raise RuntimeError("This HTTPXRequest is not initialized!") - - files = request_data.multipart_data if request_data else None - data = request_data.json_parameters if request_data else None - - # If user did not specify timeouts (for e.g. in a bot method), use the default ones when we - # created this instance. - if isinstance(read_timeout, DefaultValue): - read_timeout = self._client.timeout.read - if isinstance(connect_timeout, DefaultValue): - connect_timeout = self._client.timeout.connect - if isinstance(pool_timeout, DefaultValue): - pool_timeout = self._client.timeout.pool - - if isinstance(write_timeout, DefaultValue): - write_timeout = self._client.timeout.write if not files else self._media_write_timeout - - timeout = httpx.Timeout( - connect=connect_timeout, - read=read_timeout, - write=write_timeout, - pool=pool_timeout, - ) - - try: - res = await self._client.request( - method=method, - url=url, - headers={"User-Agent": self.USER_AGENT}, - timeout=timeout, - files=files, - data=data, - ) - except httpx.TimeoutException as err: - if isinstance(err, httpx.PoolTimeout): - raise TimedOut( - message=( - "Pool timeout: All connections in the connection pool are occupied. " - "Request was *not* sent to Telegram. Consider adjusting the connection " - "pool size or the pool timeout." - ) - ) from err - raise TimedOut from err - except httpx.HTTPError as err: - # HTTPError must come last as its the base httpx exception class - # TODO p4: do something smart here; for now just raise NetworkError - - # We include the class name for easier debugging. Especially useful if the error - # message of `err` is empty. - raise NetworkError(f"httpx.{err.__class__.__name__}: {err}") from err - - return res.status_code, res.content diff --git a/venv/lib/python3.11/site-packages/telegram/request/_requestdata.py b/venv/lib/python3.11/site-packages/telegram/request/_requestdata.py deleted file mode 100755 index b8da33c..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/_requestdata.py +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains a class that holds the parameters of a request to the Bot API.""" -import json -from typing import Any, Optional, Union, final -from urllib.parse import urlencode - -from telegram._utils.strings import TextEncoding -from telegram._utils.types import UploadFileDict -from telegram.request._requestparameter import RequestParameter - - -@final -class RequestData: - """Instances of this class collect the data needed for one request to the Bot API, including - all parameters and files to be sent along with the request. - - .. versionadded:: 20.0 - - Warning: - How exactly instances of this are created should be considered an implementation detail - and not part of PTBs public API. Users should exclusively rely on the documented - attributes, properties and methods. - - Attributes: - contains_files (:obj:`bool`): Whether this object contains files to be uploaded via - ``multipart/form-data``. - """ - - __slots__ = ("_parameters", "contains_files") - - def __init__(self, parameters: Optional[list[RequestParameter]] = None): - self._parameters: list[RequestParameter] = parameters or [] - self.contains_files: bool = any(param.input_files for param in self._parameters) - - @property - def parameters(self) -> dict[str, Union[str, int, list[Any], dict[Any, Any]]]: - """Gives the parameters as mapping of parameter name to the parameter value, which can be - a single object of type :obj:`int`, :obj:`float`, :obj:`str` or :obj:`bool` or any - (possibly nested) composition of lists, tuples and dictionaries, where each entry, key - and value is of one of the mentioned types. - - Returns: - dict[:obj:`str`, Union[:obj:`str`, :obj:`int`, list[any], dict[any, any]]] - """ - return { - param.name: param.value # type: ignore[misc] - for param in self._parameters - if param.value is not None - } - - @property - def json_parameters(self) -> dict[str, str]: - """Gives the parameters as mapping of parameter name to the respective JSON encoded - value. - - Tip: - By default, this property uses the standard library's :func:`json.dumps`. - To use a custom library for JSON encoding, you can directly encode the keys of - :attr:`parameters` - note that string valued keys should not be JSON encoded. - - Returns: - dict[:obj:`str`, :obj:`str`] - """ - return { - param.name: param.json_value - for param in self._parameters - if param.json_value is not None - } - - def url_encoded_parameters(self, encode_kwargs: Optional[dict[str, Any]] = None) -> str: - """Encodes the parameters with :func:`urllib.parse.urlencode`. - - Args: - encode_kwargs (dict[:obj:`str`, any], optional): Additional keyword arguments to pass - along to :func:`urllib.parse.urlencode`. - - Returns: - :obj:`str` - """ - if encode_kwargs: - return urlencode(self.json_parameters, **encode_kwargs) - return urlencode(self.json_parameters) - - def parametrized_url(self, url: str, encode_kwargs: Optional[dict[str, Any]] = None) -> str: - """Shortcut for attaching the return value of :meth:`url_encoded_parameters` to the - :paramref:`url`. - - Args: - url (:obj:`str`): The URL the parameters will be attached to. - encode_kwargs (dict[:obj:`str`, any], optional): Additional keyword arguments to pass - along to :func:`urllib.parse.urlencode`. - - Returns: - :obj:`str` - """ - url_parameters = self.url_encoded_parameters(encode_kwargs=encode_kwargs) - return f"{url}?{url_parameters}" - - @property - def json_payload(self) -> bytes: - """The :attr:`parameters` as UTF-8 encoded JSON payload. - - Tip: - By default, this property uses the standard library's :func:`json.dumps`. - To use a custom library for JSON encoding, you can directly encode the keys of - :attr:`parameters` - note that string valued keys should not be JSON encoded. - - Returns: - :obj:`bytes` - """ - return json.dumps(self.json_parameters).encode(TextEncoding.UTF_8) - - @property - def multipart_data(self) -> UploadFileDict: - """Gives the files contained in this object as mapping of part name to encoded content. - - .. versionchanged:: 21.5 - Content may now be a file handle. - """ - multipart_data: UploadFileDict = {} - for param in self._parameters: - m_data = param.multipart_data - if m_data: - multipart_data.update(m_data) - return multipart_data diff --git a/venv/lib/python3.11/site-packages/telegram/request/_requestparameter.py b/venv/lib/python3.11/site-packages/telegram/request/_requestparameter.py deleted file mode 100755 index 51f9b61..0000000 --- a/venv/lib/python3.11/site-packages/telegram/request/_requestparameter.py +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains a class that describes a single parameter of a request to the Bot API.""" -import datetime as dtm -import json -from collections.abc import Sequence -from dataclasses import dataclass -from typing import Optional, final - -from telegram._files.inputfile import InputFile -from telegram._files.inputmedia import InputMedia, InputPaidMedia -from telegram._files.inputsticker import InputSticker -from telegram._telegramobject import TelegramObject -from telegram._utils.datetime import to_timestamp -from telegram._utils.enum import StringEnum -from telegram._utils.types import UploadFileDict - - -@final -@dataclass(repr=True, eq=False, order=False, frozen=True) -class RequestParameter: - """Instances of this class represent a single parameter to be sent along with a request to - the Bot API. - - .. versionadded:: 20.0 - - Warning: - This class intended is to be used internally by the library and *not* by the user. Changes - to this class are not considered breaking changes and may not be documented in the - changelog. - - Args: - name (:obj:`str`): The name of the parameter. - value (:obj:`object` | :obj:`None`): The value of the parameter. Must be JSON-dumpable. - input_files (list[:class:`telegram.InputFile`], optional): A list of files that should be - uploaded along with this parameter. - - Attributes: - name (:obj:`str`): The name of the parameter. - value (:obj:`object` | :obj:`None`): The value of the parameter. - input_files (list[:class:`telegram.InputFile` | :obj:`None`): A list of files that should - be uploaded along with this parameter. - """ - - __slots__ = ("input_files", "name", "value") - - name: str - value: object - input_files: Optional[list[InputFile]] - - @property - def json_value(self) -> Optional[str]: - """The JSON dumped :attr:`value` or :obj:`None` if :attr:`value` is :obj:`None`. - The latter can currently only happen if :attr:`input_files` has exactly one element that - must not be uploaded via an attach:// URI. - """ - if isinstance(self.value, str): - return self.value - if self.value is None: - return None - return json.dumps(self.value) - - @property - def multipart_data(self) -> Optional[UploadFileDict]: - """A dict with the file data to upload, if any. - - .. versionchanged:: 21.5 - Content may now be a file handle. - """ - if not self.input_files: - return None - return { - (input_file.attach_name or self.name): input_file.field_tuple - for input_file in self.input_files - } - - @staticmethod - def _value_and_input_files_from_input( # pylint: disable=too-many-return-statements - value: object, - ) -> tuple[object, list[InputFile]]: - """Converts `value` into something that we can json-dump. Returns two values: - 1. the JSON-dumpable value. May be `None` in case the value is an InputFile which must - not be uploaded via an attach:// URI - 2. A list of InputFiles that should be uploaded for this value - - Note that we handle files differently depending on whether attaching them via an URI of the - form attach:// is documented to be allowed or not. - There was some confusion whether this worked for all files, so that we stick to the - documented ways for now. - See https://github.com/tdlib/telegram-bot-api/issues/167 and - https://github.com/tdlib/telegram-bot-api/issues/259 - - This method only does some special casing for our own helper class StringEnum, but not - for general enums. This is because: - * tg.constants currently only uses IntEnum as second enum type and json dumping that - is no problem - * if a user passes a custom enum, it's unlikely that we can actually properly handle it - even with some special casing. - """ - if isinstance(value, dtm.datetime): - return to_timestamp(value), [] - if isinstance(value, StringEnum): - return value.value, [] - if isinstance(value, InputFile): - if value.attach_uri: - return value.attach_uri, [value] - return None, [value] - - if isinstance(value, (InputMedia, InputPaidMedia)) and isinstance(value.media, InputFile): - # We call to_dict and change the returned dict instead of overriding - # value.media in case the same value is reused for another request - data = value.to_dict() - if value.media.attach_uri: - data["media"] = value.media.attach_uri - else: - data.pop("media", None) - - thumbnail = data.get("thumbnail", None) - if isinstance(thumbnail, InputFile): - if thumbnail.attach_uri: - data["thumbnail"] = thumbnail.attach_uri - else: - data.pop("thumbnail", None) - return data, [value.media, thumbnail] - - return data, [value.media] - if isinstance(value, InputSticker) and isinstance(value.sticker, InputFile): - # We call to_dict and change the returned dict instead of overriding - # value.sticker in case the same value is reused for another request - data = value.to_dict() - data["sticker"] = value.sticker.attach_uri - return data, [value.sticker] - - if isinstance(value, TelegramObject): - # Needs to be last, because InputMedia is a subclass of TelegramObject - return value.to_dict(), [] - return value, [] - - @classmethod - def from_input(cls, key: str, value: object) -> "RequestParameter": - """Builds an instance of this class for a given key-value pair that represents the raw - input as passed along from a method of :class:`telegram.Bot`. - """ - if not isinstance(value, (str, bytes)) and isinstance(value, Sequence): - param_values = [] - input_files = [] - for obj in value: - param_value, input_file = cls._value_and_input_files_from_input(obj) - if param_value is not None: - param_values.append(param_value) - input_files.extend(input_file) - return RequestParameter( - name=key, value=param_values, input_files=input_files if input_files else None - ) - - param_value, input_files = cls._value_and_input_files_from_input(value) - return RequestParameter( - name=key, value=param_value, input_files=input_files if input_files else None - ) diff --git a/venv/lib/python3.11/site-packages/telegram/warnings.py b/venv/lib/python3.11/site-packages/telegram/warnings.py deleted file mode 100755 index d475eeb..0000000 --- a/venv/lib/python3.11/site-packages/telegram/warnings.py +++ /dev/null @@ -1,87 +0,0 @@ -#! /usr/bin/env python -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains classes used for warnings issued by this library. - -.. versionadded:: 20.0 -""" - -__all__ = ["PTBDeprecationWarning", "PTBRuntimeWarning", "PTBUserWarning"] - - -class PTBUserWarning(UserWarning): - """ - Custom user warning class used for warnings in this library. - - .. seealso:: :wiki:`Exceptions, Warnings and Logging ` - - .. versionadded:: 20.0 - """ - - __slots__ = () - - -class PTBRuntimeWarning(PTBUserWarning, RuntimeWarning): - """ - Custom runtime warning class used for warnings in this library. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - -# https://www.python.org/dev/peps/pep-0565/ recommends using a custom warning class derived from -# DeprecationWarning. We also subclass from PTBUserWarning so users can easily 'switch off' -# warnings -class PTBDeprecationWarning(PTBUserWarning, DeprecationWarning): - """ - Custom warning class for deprecations in this library. - - .. versionchanged:: 20.0 - Renamed TelegramDeprecationWarning to PTBDeprecationWarning. - - Args: - version (:obj:`str`): The version in which the feature was deprecated. - - .. versionadded:: 21.2 - message (:obj:`str`): The message to display. - - .. versionadded:: 21.2 - - Attributes: - version (:obj:`str`): The version in which the feature was deprecated. - - .. versionadded:: 21.2 - message (:obj:`str`): The message to display. - - .. versionadded:: 21.2 - """ - - __slots__ = ("message", "version") - - def __init__(self, version: str, message: str) -> None: - self.version: str = version - self.message: str = message - - def __str__(self) -> str: - """Returns a string representation of the warning, using :attr:`message` and - :attr:`version`. - - .. versionadded:: 21.2 - """ - return f"Deprecated since version {self.version}: {self.message}" diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/INSTALLER b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/INSTALLER deleted file mode 100755 index a1b589e..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/METADATA b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/METADATA deleted file mode 100755 index 97fd818..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/METADATA +++ /dev/null @@ -1,73 +0,0 @@ -Metadata-Version: 2.4 -Name: typing_extensions -Version: 4.16.0 -Summary: Backported and Experimental Type Hints for Python 3.9+ -Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing -Author-email: "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -License-Expression: PSF-2.0 -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Console -Classifier: Intended Audience :: Developers -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: 3.15 -Classifier: Topic :: Software Development -License-File: LICENSE -Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues -Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md -Project-URL: Documentation, https://typing-extensions.readthedocs.io/ -Project-URL: Home, https://github.com/python/typing_extensions -Project-URL: Q & A, https://github.com/python/typing/discussions -Project-URL: Repository, https://github.com/python/typing_extensions - -# Typing Extensions - -[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing) - -[Documentation](https://typing-extensions.readthedocs.io/en/latest/#) – -[PyPI](https://pypi.org/project/typing-extensions/) - -## Overview - -The `typing_extensions` module serves two related purposes: - -- Enable use of new type system features on older Python versions. For example, - `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows - users on previous Python versions to use it too. -- Enable experimentation with new type system PEPs before they are accepted and - added to the `typing` module. - -`typing_extensions` is treated specially by static type checkers such as -mypy and pyright. Objects defined in `typing_extensions` are treated the same -way as equivalent forms in `typing`. - -`typing_extensions` uses -[Semantic Versioning](https://semver.org/). The -major version will be incremented only for backwards-incompatible changes. -Therefore, it's safe to depend -on `typing_extensions` like this: `typing_extensions ~=x.y`, -where `x.y` is the first version that includes all features you need. -[This](https://packaging.python.org/en/latest/specifications/version-specifiers/#compatible-release) -is equivalent to `typing_extensions >=x.y, <(x+1)`. Do not depend on `~= x.y.z` -unless you really know what you're doing; that defeats the purpose of -semantic versioning. - -## Included items - -See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a -complete listing of module contents. - -## Contributing - -See [CONTRIBUTING.md](https://github.com/python/typing_extensions/blob/main/CONTRIBUTING.md) -for how to contribute to `typing_extensions`. - diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/RECORD b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/RECORD deleted file mode 100755 index 4b531ef..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/RECORD +++ /dev/null @@ -1,7 +0,0 @@ -__pycache__/typing_extensions.cpython-311.pyc,, -typing_extensions-4.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -typing_extensions-4.16.0.dist-info/METADATA,sha256=sFCEyh1Qh5hlF42f_5-r6rYb37HzYb-96VQh_8j5vkY,3310 -typing_extensions-4.16.0.dist-info/RECORD,, -typing_extensions-4.16.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -typing_extensions-4.16.0.dist-info/licenses/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 -typing_extensions.py,sha256=QEDKGh7L7gDROFwSqTCE0cW9RvC3dPB-WufpHE9V5pY,165012 diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/WHEEL b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/WHEEL deleted file mode 100755 index d8b9936..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/licenses/LICENSE b/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/licenses/LICENSE deleted file mode 100755 index f26bcf4..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions-4.16.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,279 +0,0 @@ -A. HISTORY OF THE SOFTWARE -========================== - -Python was created in the early 1990s by Guido van Rossum at Stichting -Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands -as a successor of a language called ABC. Guido remains Python's -principal author, although it includes many contributions from others. - -In 1995, Guido continued his work on Python at the Corporation for -National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) -in Reston, Virginia where he released several versions of the -software. - -In May 2000, Guido and the Python core development team moved to -BeOpen.com to form the BeOpen PythonLabs team. In October of the same -year, the PythonLabs team moved to Digital Creations, which became -Zope Corporation. In 2001, the Python Software Foundation (PSF, see -https://www.python.org/psf/) was formed, a non-profit organization -created specifically to own Python-related Intellectual Property. -Zope Corporation was a sponsoring member of the PSF. - -All Python releases are Open Source (see https://opensource.org for -the Open Source Definition). Historically, most, but not all, Python -releases have also been GPL-compatible; the table below summarizes -the various releases. - - Release Derived Year Owner GPL- - from compatible? (1) - - 0.9.0 thru 1.2 1991-1995 CWI yes - 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes - 1.6 1.5.2 2000 CNRI no - 2.0 1.6 2000 BeOpen.com no - 1.6.1 1.6 2001 CNRI yes (2) - 2.1 2.0+1.6.1 2001 PSF no - 2.0.1 2.0+1.6.1 2001 PSF yes - 2.1.1 2.1+2.0.1 2001 PSF yes - 2.1.2 2.1.1 2002 PSF yes - 2.1.3 2.1.2 2002 PSF yes - 2.2 and above 2.1.1 2001-now PSF yes - -Footnotes: - -(1) GPL-compatible doesn't mean that we're distributing Python under - the GPL. All Python licenses, unlike the GPL, let you distribute - a modified version without making your changes open source. The - GPL-compatible licenses make it possible to combine Python with - other software that is released under the GPL; the others don't. - -(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, - because its license has a choice of law clause. According to - CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 - is "not incompatible" with the GPL. - -Thanks to the many outside volunteers who have worked under Guido's -direction to make these releases possible. - - -B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON -=============================================================== - -Python software and documentation are licensed under the -Python Software Foundation License Version 2. - -Starting with Python 3.8.6, examples, recipes, and other code in -the documentation are dual licensed under the PSF License Version 2 -and the Zero-Clause BSD license. - -Some software incorporated into Python is under different licenses. -The licenses are listed with code falling under that license. - - -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby -grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, -analyze, test, perform and/or display publicly, prepare derivative works, -distribute, and otherwise use Python alone or in any derivative version, -provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative version -prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 -------------------------------------------- - -BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 - -1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an -office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the -Individual or Organization ("Licensee") accessing and otherwise using -this software in source or binary form and its associated -documentation ("the Software"). - -2. Subject to the terms and conditions of this BeOpen Python License -Agreement, BeOpen hereby grants Licensee a non-exclusive, -royalty-free, world-wide license to reproduce, analyze, test, perform -and/or display publicly, prepare derivative works, distribute, and -otherwise use the Software alone or in any derivative version, -provided, however, that the BeOpen Python License is retained in the -Software, alone or in any derivative version prepared by Licensee. - -3. BeOpen is making the Software available to Licensee on an "AS IS" -basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE -SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS -AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -5. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -6. This License Agreement shall be governed by and interpreted in all -respects by the law of the State of California, excluding conflict of -law provisions. Nothing in this License Agreement shall be deemed to -create any relationship of agency, partnership, or joint venture -between BeOpen and Licensee. This License Agreement does not grant -permission to use BeOpen trademarks or trade names in a trademark -sense to endorse or promote products or services of Licensee, or any -third party. As an exception, the "BeOpen Python" logos available at -http://www.pythonlabs.com/logos.html may be used according to the -permissions granted on that web page. - -7. By copying, installing or otherwise using the software, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 ---------------------------------------- - -1. This LICENSE AGREEMENT is between the Corporation for National -Research Initiatives, having an office at 1895 Preston White Drive, -Reston, VA 20191 ("CNRI"), and the Individual or Organization -("Licensee") accessing and otherwise using Python 1.6.1 software in -source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, CNRI -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 1.6.1 -alone or in any derivative version, provided, however, that CNRI's -License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) -1995-2001 Corporation for National Research Initiatives; All Rights -Reserved" are retained in Python 1.6.1 alone or in any derivative -version prepared by Licensee. Alternately, in lieu of CNRI's License -Agreement, Licensee may substitute the following text (omitting the -quotes): "Python 1.6.1 is made available subject to the terms and -conditions in CNRI's License Agreement. This Agreement together with -Python 1.6.1 may be located on the internet using the following -unique, persistent identifier (known as a handle): 1895.22/1013. This -Agreement may also be obtained from a proxy server on the internet -using the following URL: http://hdl.handle.net/1895.22/1013". - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 1.6.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 1.6.1. - -4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" -basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. This License Agreement shall be governed by the federal -intellectual property law of the United States, including without -limitation the federal copyright law, and, to the extent such -U.S. federal law does not apply, by the law of the Commonwealth of -Virginia, excluding Virginia's conflict of law provisions. -Notwithstanding the foregoing, with regard to derivative works based -on Python 1.6.1 that incorporate non-separable material that was -previously distributed under the GNU General Public License (GPL), the -law of the Commonwealth of Virginia shall govern this License -Agreement only as to issues arising under or with respect to -Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this -License Agreement shall be deemed to create any relationship of -agency, partnership, or joint venture between CNRI and Licensee. This -License Agreement does not grant permission to use CNRI trademarks or -trade name in a trademark sense to endorse or promote products or -services of Licensee, or any third party. - -8. By clicking on the "ACCEPT" button where indicated, or by copying, -installing or otherwise using Python 1.6.1, Licensee agrees to be -bound by the terms and conditions of this License Agreement. - - ACCEPT - - -CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 --------------------------------------------------- - -Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, -The Netherlands. All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION ----------------------------------------------------------------------- - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. diff --git a/venv/lib/python3.11/site-packages/typing_extensions.py b/venv/lib/python3.11/site-packages/typing_extensions.py deleted file mode 100755 index ced7837..0000000 --- a/venv/lib/python3.11/site-packages/typing_extensions.py +++ /dev/null @@ -1,4422 +0,0 @@ -import abc -import builtins -import collections -import collections.abc -import contextlib -import enum -import functools -import inspect -import io -import keyword -import operator -import sys -import types as _types -import typing -import warnings - -# Breakpoint: https://github.com/python/cpython/pull/119891 -if sys.version_info >= (3, 14): - import annotationlib - -__all__ = [ - # Super-special typing primitives. - 'Any', - 'ClassVar', - 'Concatenate', - 'Final', - 'LiteralString', - 'ParamSpec', - 'ParamSpecArgs', - 'ParamSpecKwargs', - 'Self', - 'Type', - 'TypeVar', - 'TypeVarTuple', - 'Unpack', - - # ABCs (from collections.abc). - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', - 'Coroutine', - 'AsyncGenerator', - 'AsyncContextManager', - 'Buffer', - 'ChainMap', - - # Concrete collection types. - 'ContextManager', - 'Counter', - 'Deque', - 'DefaultDict', - 'NamedTuple', - 'OrderedDict', - 'TypedDict', - - # Structural checks, a.k.a. protocols. - 'SupportsAbs', - 'SupportsBytes', - 'SupportsComplex', - 'SupportsFloat', - 'SupportsIndex', - 'SupportsInt', - 'SupportsRound', - 'Reader', - 'Writer', - - # One-off things. - 'Annotated', - 'assert_never', - 'assert_type', - 'clear_overloads', - 'dataclass_transform', - 'deprecated', - 'disjoint_base', - 'Doc', - 'evaluate_forward_ref', - 'get_overloads', - 'final', - 'Format', - 'get_annotations', - 'get_args', - 'get_origin', - 'get_original_bases', - 'get_protocol_members', - 'get_type_hints', - 'IntVar', - 'is_protocol', - 'is_typeddict', - 'Literal', - 'NewType', - 'overload', - 'override', - 'Protocol', - 'sentinel', - 'Sentinel', - 'reveal_type', - 'runtime', - 'runtime_checkable', - 'Text', - 'TypeAlias', - 'TypeAliasType', - 'TypeForm', - 'TypeGuard', - 'TypeIs', - 'TYPE_CHECKING', - 'type_repr', - 'Never', - 'NoReturn', - 'ReadOnly', - 'Required', - 'NotRequired', - 'NoDefault', - 'NoExtraItems', - - # Pure aliases, have always been in typing - 'AbstractSet', - 'AnyStr', - 'BinaryIO', - 'Callable', - 'Collection', - 'Container', - 'Dict', - 'ForwardRef', - 'FrozenSet', - 'Generator', - 'Generic', - 'Hashable', - 'IO', - 'ItemsView', - 'Iterable', - 'Iterator', - 'KeysView', - 'List', - 'Mapping', - 'MappingView', - 'Match', - 'MutableMapping', - 'MutableSequence', - 'MutableSet', - 'Optional', - 'Pattern', - 'Reversible', - 'Sequence', - 'Set', - 'Sized', - 'TextIO', - 'Tuple', - 'Union', - 'ValuesView', - 'cast', - 'no_type_check', -] - -# for backward compatibility -PEP_560 = True -GenericMeta = type -# Breakpoint: https://github.com/python/cpython/pull/116129 -_PEP_696_IMPLEMENTED = sys.version_info >= (3, 13, 0, "beta") - -# Added with bpo-45166 to 3.10.1+ and some 3.9 versions -_FORWARD_REF_HAS_CLASS = "__forward_is_class__" in typing.ForwardRef.__slots__ - - -def _caller(depth=1, default='__main__'): - try: - return sys._getframemodulename(depth + 1) or default - except AttributeError: # For platforms without _getframemodulename() - pass - try: - return sys._getframe(depth + 1).f_globals.get('__name__', default) - except (AttributeError, ValueError): # For platforms without _getframe() - pass - return None - - -# Placeholder for sentinel methods, because sentinels can not have their own sentinels -_sentinel_placeholder = object() - -if hasattr(builtins, "sentinel"): # 3.15+ - sentinel = builtins.sentinel -else: - class sentinel: - """Create a unique sentinel object. - - *name* should be the name of the variable to which the return value - shall be assigned. - """ - - def __init__( - self, - __name: str = _sentinel_placeholder, - __repr: typing.Optional[str] = _sentinel_placeholder, - /, - *, - repr: typing.Optional[str] = None, - name: str = _sentinel_placeholder, - ) -> None: - if name is not _sentinel_placeholder: - warnings.warn( - "Passing 'name' as a keyword argument is deprecated; " - "pass it positionally instead.", - DeprecationWarning, - stacklevel=2, - ) - __name = name - if __name is _sentinel_placeholder: - raise TypeError("First parameter 'name' is required") - if __repr is not _sentinel_placeholder: - warnings.warn( - "Passing 'repr' as a positional argument is deprecated; " - "pass it by keyword instead.", - DeprecationWarning, - stacklevel=2, - ) - repr = __repr - - self._name = __name - self._repr = repr if repr is not None else __name - - # For pickling as a singleton: - self.__module__ = _caller() - - def __init_subclass__(cls): - warnings.warn( - "Subclassing sentinel is deprecated " - "and will be disallowed in Python 3.15", - DeprecationWarning, - stacklevel=2, - ) - super().__init_subclass__() - - def __setattr__(self, attr: str, value: object) -> None: - if attr not in {"_name", "_repr", "__module__"}: - warnings.warn( - f"Setting attribute {attr!r} on sentinel objects is deprecated " - "and will be disallowed in Python 3.15.", - DeprecationWarning, - stacklevel=2, - ) - super().__setattr__(attr, value) - - @property - def __name__(self) -> str: - return self._name - - @__name__.setter - def __name__(self, value: str) -> None: - self._name = value - - def __repr__(self) -> str: - return self._repr - - if sys.version_info < (3, 11): - # The presence of this method convinces typing._type_check - # that Sentinels are types. - def __call__(self, *args, **kwargs): - raise TypeError(f"{type(self).__name__!r} object is not callable") - - # Breakpoint: https://github.com/python/cpython/pull/21515 - if sys.version_info >= (3, 10): - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - def __reduce__(self) -> str: - """Reduce this sentinel to a singleton.""" - return self.__name__ # Module is taken from the __module__ attribute - -Sentinel = sentinel - -_marker = sentinel("sentinel") - - -# The functions below are modified copies of typing internal helpers. -# They are needed by _ProtocolMeta and they provide support for PEP 646. - -# Breakpoint: https://github.com/python/cpython/pull/27342 -if sys.version_info >= (3, 10): - def _should_collect_from_parameters(t): - return isinstance( - t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) - ) -else: - def _should_collect_from_parameters(t): - return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) - - -NoReturn = typing.NoReturn - -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) -T = typing.TypeVar('T') # Any type. -KT = typing.TypeVar('KT') # Key type. -VT = typing.TypeVar('VT') # Value type. -T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. -T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. - - -# Breakpoint: https://github.com/python/cpython/pull/31841 -if sys.version_info >= (3, 11): - from typing import Any -else: - - class _AnyMeta(type): - def __instancecheck__(self, obj): - if self is Any: - raise TypeError("typing_extensions.Any cannot be used with isinstance()") - return super().__instancecheck__(obj) - - def __repr__(self): - if self is Any: - return "typing_extensions.Any" - return super().__repr__() - - class Any(metaclass=_AnyMeta): - """Special type indicating an unconstrained type. - - Any is compatible with every type. - - Any assumed to have all methods. - - All values assumed to be instances of Any. - Note that all the above statements are true from the point of view of - static type checkers. At runtime, Any should not be used with instance - checks. - """ - def __new__(cls, *args, **kwargs): - if cls is Any: - raise TypeError("Any cannot be instantiated") - return super().__new__(cls, *args, **kwargs) - - -ClassVar = typing.ClassVar - -# Vendored from cpython typing._SpecialFrom -# Having a separate class means that instances will not be rejected by -# typing._type_check. -class _SpecialForm(typing._Final, _root=True): - __slots__ = ('_name', '__doc__', '_getitem') - - def __init__(self, getitem): - self._getitem = getitem - self._name = getitem.__name__ - self.__doc__ = getitem.__doc__ - - def __getattr__(self, item): - if item in {'__name__', '__qualname__'}: - return self._name - - raise AttributeError(item) - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass {self!r}") - - def __repr__(self): - return f'typing_extensions.{self._name}' - - def __reduce__(self): - return self._name - - def __call__(self, *args, **kwds): - raise TypeError(f"Cannot instantiate {self!r}") - - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - def __instancecheck__(self, obj): - raise TypeError(f"{self} cannot be used with isinstance()") - - def __subclasscheck__(self, cls): - raise TypeError(f"{self} cannot be used with issubclass()") - - @typing._tp_cache - def __getitem__(self, parameters): - return self._getitem(self, parameters) - - -# Note that inheriting from this class means that the object will be -# rejected by typing._type_check, so do not use it if the special form -# is arguably valid as a type by itself. -class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - -Final = typing.Final - -# Breakpoint: https://github.com/python/cpython/pull/30530 -if sys.version_info >= (3, 11): - final = typing.final -else: - # @final exists in 3.8+, but we backport it for all versions - # before 3.11 to keep support for the __final__ attribute. - # See https://bugs.python.org/issue46342 - def final(f): - """This decorator can be used to indicate to type checkers that - the decorated method cannot be overridden, and decorated class - cannot be subclassed. For example: - - class Base: - @final - def done(self) -> None: - ... - class Sub(Base): - def done(self) -> None: # Error reported by type checker - ... - @final - class Leaf: - ... - class Other(Leaf): # Error reported by type checker - ... - - There is no runtime checking of these properties. The decorator - sets the ``__final__`` attribute to ``True`` on the decorated object - to allow runtime introspection. - """ - try: - f.__final__ = True - except (AttributeError, TypeError): - # Skip the attribute silently if it is not writable. - # AttributeError happens if the object has __slots__ or a - # read-only property, TypeError if it's a builtin class. - pass - return f - - -if hasattr(typing, "disjoint_base"): # 3.15 - disjoint_base = typing.disjoint_base -else: - def disjoint_base(cls): - """This decorator marks a class as a disjoint base. - - Child classes of a disjoint base cannot inherit from other disjoint bases that are - not parent classes of the disjoint base. - - For example: - - @disjoint_base - class Disjoint1: pass - - @disjoint_base - class Disjoint2: pass - - class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error - - Type checkers can use knowledge of disjoint bases to detect unreachable code - and determine when two types can overlap. - - See PEP 800.""" - cls.__disjoint_base__ = True - return cls - - -def IntVar(name): - return typing.TypeVar(name) - - -# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8 -# Breakpoint: https://github.com/python/cpython/pull/29334 -if sys.version_info >= (3, 10, 1): - Literal = typing.Literal -else: - def _flatten_literal_params(parameters): - """An internal helper for Literal creation: flatten Literals among parameters""" - params = [] - for p in parameters: - if isinstance(p, _LiteralGenericAlias): - params.extend(p.__args__) - else: - params.append(p) - return tuple(params) - - def _value_and_type_iter(params): - for p in params: - yield p, type(p) - - class _LiteralGenericAlias(typing._GenericAlias, _root=True): - def __eq__(self, other): - if not isinstance(other, _LiteralGenericAlias): - return NotImplemented - these_args_deduped = set(_value_and_type_iter(self.__args__)) - other_args_deduped = set(_value_and_type_iter(other.__args__)) - return these_args_deduped == other_args_deduped - - def __hash__(self): - return hash(frozenset(_value_and_type_iter(self.__args__))) - - class _LiteralForm(_ExtensionsSpecialForm, _root=True): - def __init__(self, doc: str): - self._name = 'Literal' - self._doc = self.__doc__ = doc - - def __getitem__(self, parameters): - if not isinstance(parameters, tuple): - parameters = (parameters,) - - parameters = _flatten_literal_params(parameters) - - val_type_pairs = list(_value_and_type_iter(parameters)) - try: - deduped_pairs = set(val_type_pairs) - except TypeError: - # unhashable parameters - pass - else: - # similar logic to typing._deduplicate on Python 3.9+ - if len(deduped_pairs) < len(val_type_pairs): - new_parameters = [] - for pair in val_type_pairs: - if pair in deduped_pairs: - new_parameters.append(pair[0]) - deduped_pairs.remove(pair) - assert not deduped_pairs, deduped_pairs - parameters = tuple(new_parameters) - - return _LiteralGenericAlias(self, parameters) - - Literal = _LiteralForm(doc="""\ - A type that can be used to indicate to type checkers - that the corresponding value has a value literally equivalent - to the provided parameter. For example: - - var: Literal[4] = 4 - - The type checker understands that 'var' is literally equal to - the value 4 and no other value. - - Literal[...] cannot be subclassed. There is no runtime - checking verifying that the parameter is actually a value - instead of a type.""") - - -_overload_dummy = typing._overload_dummy - - -if hasattr(typing, "get_overloads"): # 3.11+ - overload = typing.overload - get_overloads = typing.get_overloads - clear_overloads = typing.clear_overloads -else: - # {module: {qualname: {firstlineno: func}}} - _overload_registry = collections.defaultdict( - functools.partial(collections.defaultdict, dict) - ) - - def overload(func): - """Decorator for overloaded functions/methods. - - In a stub file, place two or more stub definitions for the same - function in a row, each decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - - In a non-stub file (i.e. a regular .py file), do the same but - follow it with an implementation. The implementation should *not* - be decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - def utf8(value): - # implementation goes here - - The overloads for a function can be retrieved at runtime using the - get_overloads() function. - """ - # classmethod and staticmethod - f = getattr(func, "__func__", func) - try: - _overload_registry[f.__module__][f.__qualname__][ - f.__code__.co_firstlineno - ] = func - except AttributeError: - # Not a normal function; ignore. - pass - return _overload_dummy - - def get_overloads(func): - """Return all defined overloads for *func* as a sequence.""" - # classmethod and staticmethod - f = getattr(func, "__func__", func) - if f.__module__ not in _overload_registry: - return [] - mod_dict = _overload_registry[f.__module__] - if f.__qualname__ not in mod_dict: - return [] - return list(mod_dict[f.__qualname__].values()) - - def clear_overloads(): - """Clear all overloads in the registry.""" - _overload_registry.clear() - - -# This is not a real generic class. Don't use outside annotations. -Type = typing.Type - -# Various ABCs mimicking those in collections.abc. -# A few are simply re-exported for completeness. -Awaitable = typing.Awaitable -Coroutine = typing.Coroutine -AsyncIterable = typing.AsyncIterable -AsyncIterator = typing.AsyncIterator -Deque = typing.Deque -DefaultDict = typing.DefaultDict -OrderedDict = typing.OrderedDict -Counter = typing.Counter -ChainMap = typing.ChainMap -Text = typing.Text -TYPE_CHECKING = typing.TYPE_CHECKING - - -# Breakpoint: https://github.com/python/cpython/pull/118681 -if sys.version_info >= (3, 13, 0, "beta"): - from typing import AsyncContextManager, AsyncGenerator, ContextManager, Generator -else: - def _is_dunder(attr): - return attr.startswith('__') and attr.endswith('__') - - - class _SpecialGenericAlias(typing._SpecialGenericAlias, _root=True): - def __init__(self, origin, nparams, *, defaults, inst=True, name=None): - assert nparams > 0, "`nparams` must be a positive integer" - assert defaults, "Must always specify a non-empty sequence for `defaults`" - super().__init__(origin, nparams, inst=inst, name=name) - self._defaults = defaults - - def __setattr__(self, attr, val): - allowed_attrs = {'_name', '_inst', '_nparams', '_defaults'} - if _is_dunder(attr) or attr in allowed_attrs: - object.__setattr__(self, attr, val) - else: - setattr(self.__origin__, attr, val) - - @typing._tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - msg = "Parameters to generic types must be types." - params = tuple(typing._type_check(p, msg) for p in params) - if ( - len(params) < self._nparams - and len(params) + len(self._defaults) >= self._nparams - ): - params = (*params, *self._defaults[len(params) - self._nparams:]) - actual_len = len(params) - - if actual_len != self._nparams: - expected = f"at least {self._nparams - len(self._defaults)}" - raise TypeError( - f"Too {'many' if actual_len > self._nparams else 'few'}" - f" arguments for {self};" - f" actual {actual_len}, expected {expected}" - ) - return self.copy_with(params) - - _NoneType = type(None) - Generator = _SpecialGenericAlias( - collections.abc.Generator, 3, defaults=(_NoneType, _NoneType) - ) - AsyncGenerator = _SpecialGenericAlias( - collections.abc.AsyncGenerator, 2, defaults=(_NoneType,) - ) - ContextManager = _SpecialGenericAlias( - contextlib.AbstractContextManager, - 2, - name="ContextManager", - defaults=(typing.Optional[bool],) - ) - AsyncContextManager = _SpecialGenericAlias( - contextlib.AbstractAsyncContextManager, - 2, - name="AsyncContextManager", - defaults=(typing.Optional[bool],) - ) - - -_PROTO_ALLOWLIST = { - 'collections.abc': [ - 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection', - 'Reversible', 'Buffer', - ], - 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], - 'io': ['Reader', 'Writer'], - 'typing_extensions': ['Buffer'], - 'os': ['PathLike'], -} - - -_EXCLUDED_ATTRS = frozenset(typing.EXCLUDED_ATTRIBUTES) | { - "__match_args__", "__protocol_attrs__", "__non_callable_proto_members__", - "__final__", -} - - -def _get_protocol_attrs(cls): - attrs = set() - for base in cls.__mro__[:-1]: # without object - if base.__name__ in {'Protocol', 'Generic'}: - continue - annotations = getattr(base, '__annotations__', {}) - for attr in (*base.__dict__, *annotations): - if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS): - attrs.add(attr) - return attrs - - -# `__match_args__` attribute was removed from protocol members in 3.13, -# we want to backport this change to older Python versions. -# 3.14 additionally added `io.Reader`, `io.Writer` and `os.PathLike` to -# the list of allowed protocol allowlist. -# https://github.com/python/cpython/issues/127647 -if sys.version_info >= (3, 14): - Protocol = typing.Protocol -else: - def _allow_reckless_class_checks(depth=2): - """Allow instance and class checks for special stdlib modules. - The abc and functools modules indiscriminately call isinstance() and - issubclass() on the whole MRO of a user class, which may contain protocols. - """ - return _caller(depth) in {'abc', 'functools', None} - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - def _type_check_issubclass_arg_1(arg): - """Raise TypeError if `arg` is not an instance of `type` - in `issubclass(arg, )`. - - In most cases, this is verified by type.__subclasscheck__. - Checking it again unnecessarily would slow down issubclass() checks, - so, we don't perform this check unless we absolutely have to. - - For various error paths, however, - we want to ensure that *this* error message is shown to the user - where relevant, rather than a typing.py-specific error message. - """ - if not isinstance(arg, type): - # Same error message as for issubclass(1, int). - raise TypeError('issubclass() arg 1 must be a class') - - # Inheriting from typing._ProtocolMeta isn't actually desirable, - # but is necessary to allow typing.Protocol and typing_extensions.Protocol - # to mix without getting TypeErrors about "metaclass conflict" - class _ProtocolMeta(type(typing.Protocol)): - # This metaclass is somewhat unfortunate, - # but is necessary for several reasons... - # - # NOTE: DO NOT call super() in any methods in this class - # That would call the methods on typing._ProtocolMeta on Python <=3.11 - # and those are slow - def __new__(mcls, name, bases, namespace, **kwargs): - if name == "Protocol" and len(bases) < 2: - pass - elif {Protocol, typing.Protocol} & set(bases): - for base in bases: - if not ( - base in {object, typing.Generic, Protocol, typing.Protocol} - or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, []) - or is_protocol(base) - ): - raise TypeError( - f"Protocols can only inherit from other protocols, " - f"got {base!r}" - ) - return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs) - - def __init__(cls, *args, **kwargs): - abc.ABCMeta.__init__(cls, *args, **kwargs) - if getattr(cls, "_is_protocol", False): - cls.__protocol_attrs__ = _get_protocol_attrs(cls) - - def __subclasscheck__(cls, other): - if cls is Protocol: - return type.__subclasscheck__(cls, other) - if ( - getattr(cls, '_is_protocol', False) - and not _allow_reckless_class_checks() - ): - if not getattr(cls, '_is_runtime_protocol', False): - _type_check_issubclass_arg_1(other) - raise TypeError( - "Instance and class checks can only be used with " - "@runtime_checkable protocols" - ) - if ( - # this attribute is set by @runtime_checkable: - cls.__non_callable_proto_members__ - and cls.__dict__.get("__subclasshook__") is _proto_hook - ): - _type_check_issubclass_arg_1(other) - non_method_attrs = sorted(cls.__non_callable_proto_members__) - raise TypeError( - "Protocols with non-method members don't support issubclass()." - f" Non-method members: {str(non_method_attrs)[1:-1]}." - ) - return abc.ABCMeta.__subclasscheck__(cls, other) - - def __instancecheck__(cls, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if cls is Protocol: - return type.__instancecheck__(cls, instance) - if not getattr(cls, "_is_protocol", False): - # i.e., it's a concrete subclass of a protocol - return abc.ABCMeta.__instancecheck__(cls, instance) - - if ( - not getattr(cls, '_is_runtime_protocol', False) and - not _allow_reckless_class_checks() - ): - raise TypeError("Instance and class checks can only be used with" - " @runtime_checkable protocols") - - if abc.ABCMeta.__instancecheck__(cls, instance): - return True - - for attr in cls.__protocol_attrs__: - try: - val = inspect.getattr_static(instance, attr) - except AttributeError: - break - # this attribute is set by @runtime_checkable: - if val is None and attr not in cls.__non_callable_proto_members__: - break - else: - return True - - return False - - def __eq__(cls, other): - # Hack so that typing.Generic.__class_getitem__ - # treats typing_extensions.Protocol - # as equivalent to typing.Protocol - if abc.ABCMeta.__eq__(cls, other) is True: - return True - return cls is Protocol and other is typing.Protocol - - # This has to be defined, or the abc-module cache - # complains about classes with this metaclass being unhashable, - # if we define only __eq__! - def __hash__(cls) -> int: - return type.__hash__(cls) - - @classmethod - def _proto_hook(cls, other): - if not cls.__dict__.get('_is_protocol', False): - return NotImplemented - - for attr in cls.__protocol_attrs__: - for base in other.__mro__: - # Check if the members appears in the class dictionary... - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - - # ...or in annotations, if it is a sub-protocol. - annotations = getattr(base, '__annotations__', {}) - if ( - isinstance(annotations, collections.abc.Mapping) - and attr in annotations - and is_protocol(other) - ): - break - else: - return NotImplemented - return True - - class Protocol(typing.Generic, metaclass=_ProtocolMeta): - __doc__ = typing.Protocol.__doc__ - __slots__ = () - _is_protocol = True - _is_runtime_protocol = False - - def __init_subclass__(cls, *args, **kwargs): - super().__init_subclass__(*args, **kwargs) - - # Determine if this is a protocol or a concrete subclass. - if not cls.__dict__.get('_is_protocol', False): - cls._is_protocol = any(b is Protocol for b in cls.__bases__) - - # Set (or override) the protocol subclass hook. - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - # Prohibit instantiation for protocol classes - if cls._is_protocol and cls.__init__ is Protocol.__init__: - cls.__init__ = _no_init - - -# Breakpoint: https://github.com/python/cpython/pull/113401 -if sys.version_info >= (3, 13): - runtime_checkable = typing.runtime_checkable -else: - def runtime_checkable(cls): - """Mark a protocol class as a runtime protocol. - - Such protocol can be used with isinstance() and issubclass(). - Raise TypeError if applied to a non-protocol class. - This allows a simple-minded structural check very similar to - one trick ponies in collections.abc such as Iterable. - - For example:: - - @runtime_checkable - class Closable(Protocol): - def close(self): ... - - assert isinstance(open('/some/file'), Closable) - - Warning: this will check only the presence of the required methods, - not their type signatures! - """ - if not issubclass(cls, typing.Generic) or not getattr(cls, '_is_protocol', False): - raise TypeError(f'@runtime_checkable can be only applied to protocol classes,' - f' got {cls!r}') - cls._is_runtime_protocol = True - - # typing.Protocol classes on <=3.11 break if we execute this block, - # because typing.Protocol classes on <=3.11 don't have a - # `__protocol_attrs__` attribute, and this block relies on the - # `__protocol_attrs__` attribute. Meanwhile, typing.Protocol classes on 3.12.2+ - # break if we *don't* execute this block, because *they* assume that all - # protocol classes have a `__non_callable_proto_members__` attribute - # (which this block sets) - if isinstance(cls, _ProtocolMeta) or sys.version_info >= (3, 12, 2): - # PEP 544 prohibits using issubclass() - # with protocols that have non-method members. - # See gh-113320 for why we compute this attribute here, - # rather than in `_ProtocolMeta.__init__` - cls.__non_callable_proto_members__ = set() - for attr in cls.__protocol_attrs__: - try: - is_callable = callable(getattr(cls, attr, None)) - except Exception as e: - raise TypeError( - f"Failed to determine whether protocol member {attr!r} " - "is a method member" - ) from e - else: - if not is_callable: - cls.__non_callable_proto_members__.add(attr) - - return cls - - -# The "runtime" alias exists for backwards compatibility. -runtime = runtime_checkable - - -# Our version of runtime-checkable protocols is faster on Python <=3.11 -# Breakpoint: https://github.com/python/cpython/pull/112717 -if sys.version_info >= (3, 12): - SupportsInt = typing.SupportsInt - SupportsFloat = typing.SupportsFloat - SupportsComplex = typing.SupportsComplex - SupportsBytes = typing.SupportsBytes - SupportsIndex = typing.SupportsIndex - SupportsAbs = typing.SupportsAbs - SupportsRound = typing.SupportsRound -else: - @runtime_checkable - class SupportsInt(Protocol): - """An ABC with one abstract method __int__.""" - __slots__ = () - - @abc.abstractmethod - def __int__(self) -> int: - pass - - @runtime_checkable - class SupportsFloat(Protocol): - """An ABC with one abstract method __float__.""" - __slots__ = () - - @abc.abstractmethod - def __float__(self) -> float: - pass - - @runtime_checkable - class SupportsComplex(Protocol): - """An ABC with one abstract method __complex__.""" - __slots__ = () - - @abc.abstractmethod - def __complex__(self) -> complex: - pass - - @runtime_checkable - class SupportsBytes(Protocol): - """An ABC with one abstract method __bytes__.""" - __slots__ = () - - @abc.abstractmethod - def __bytes__(self) -> bytes: - pass - - @runtime_checkable - class SupportsIndex(Protocol): - __slots__ = () - - @abc.abstractmethod - def __index__(self) -> int: - pass - - @runtime_checkable - class SupportsAbs(Protocol[T_co]): - """ - An ABC with one abstract method __abs__ that is covariant in its return type. - """ - __slots__ = () - - @abc.abstractmethod - def __abs__(self) -> T_co: - pass - - @runtime_checkable - class SupportsRound(Protocol[T_co]): - """ - An ABC with one abstract method __round__ that is covariant in its return type. - """ - __slots__ = () - - @abc.abstractmethod - def __round__(self, ndigits: int = 0) -> T_co: - pass - - -if hasattr(io, "Reader") and hasattr(io, "Writer"): - Reader = io.Reader - Writer = io.Writer -else: - @runtime_checkable - class Reader(Protocol[T_co]): - """Protocol for simple I/O reader instances. - - This protocol only supports blocking I/O. - """ - - __slots__ = () - - @abc.abstractmethod - def read(self, size: int = ..., /) -> T_co: - """Read data from the input stream and return it. - - If *size* is specified, at most *size* items (bytes/characters) will be - read. - """ - - @runtime_checkable - class Writer(Protocol[T_contra]): - """Protocol for simple I/O writer instances. - - This protocol only supports blocking I/O. - """ - - __slots__ = () - - @abc.abstractmethod - def write(self, data: T_contra, /) -> int: - """Write *data* to the output stream and return the number of items written.""" # noqa: E501 - - -_NEEDS_SINGLETONMETA = ( - not hasattr(typing, "NoDefault") or not hasattr(typing, "NoExtraItems") -) - -if _NEEDS_SINGLETONMETA: - class SingletonMeta(type): - def __setattr__(cls, attr, value): - # TypeError is consistent with the behavior of NoneType - raise TypeError( - f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}" - ) - - -if hasattr(typing, "NoDefault"): - NoDefault = typing.NoDefault -else: - class NoDefaultType(metaclass=SingletonMeta): - """The type of the NoDefault singleton.""" - - __slots__ = () - - def __new__(cls): - return globals().get("NoDefault") or object.__new__(cls) - - def __repr__(self): - return "typing_extensions.NoDefault" - - def __reduce__(self): - return "NoDefault" - - NoDefault = NoDefaultType() - del NoDefaultType - -if hasattr(typing, "NoExtraItems"): - NoExtraItems = typing.NoExtraItems -else: - class NoExtraItemsType(metaclass=SingletonMeta): - """The type of the NoExtraItems singleton.""" - - __slots__ = () - - def __new__(cls): - return globals().get("NoExtraItems") or object.__new__(cls) - - def __repr__(self): - return "typing_extensions.NoExtraItems" - - def __reduce__(self): - return "NoExtraItems" - - NoExtraItems = NoExtraItemsType() - del NoExtraItemsType - -if _NEEDS_SINGLETONMETA: - del SingletonMeta - - -# Update this to something like >=3.13.0b1 if and when -# PEP 764 is implemented in CPython -_PEP_764_IMPLEMENTED = False - -if _PEP_764_IMPLEMENTED: - # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" - # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 - # The standard library TypedDict below Python 3.11 does not store runtime - # information about optional and required keys when using Required or NotRequired. - # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. - # Aaaand on 3.12 we add __orig_bases__ to TypedDict - # to enable better runtime introspection. - # On 3.13 we deprecate some odd ways of creating TypedDicts. - # Also on 3.13, PEP 705 adds the ReadOnly[] qualifier. - # PEP 728 (Python 3.15+) adds the `extra_items` and `closed` keywords. - # PEP 764 (still pending) allows the `TypedDict` special form to be subscripted. - TypedDict = typing.TypedDict - _TypedDictMeta = typing._TypedDictMeta - is_typeddict = typing.is_typeddict -else: - # 3.10.0 and later - _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters - - def _get_typeddict_qualifiers(annotation_type): - while True: - annotation_origin = get_origin(annotation_type) - if annotation_origin is Annotated: - annotation_args = get_args(annotation_type) - if annotation_args: - annotation_type = annotation_args[0] - else: - break - elif annotation_origin is Required: - yield Required - annotation_type, = get_args(annotation_type) - elif annotation_origin is NotRequired: - yield NotRequired - annotation_type, = get_args(annotation_type) - elif annotation_origin is ReadOnly: - yield ReadOnly - annotation_type, = get_args(annotation_type) - else: - break - - class _TypedDictMeta(type): - - def __new__(cls, name, bases, ns, *, total=True, closed=None, - extra_items=NoExtraItems): - """Create new typed dict class object. - - This method is called when TypedDict is subclassed, - or when TypedDict is instantiated. This way - TypedDict supports all three syntax forms described in its docstring. - Subclasses and instances of TypedDict return actual dictionaries. - """ - for base in bases: - if type(base) is not _TypedDictMeta and base is not typing.Generic: - raise TypeError('cannot inherit from both a TypedDict type ' - 'and a non-TypedDict base class') - if closed is not None and extra_items is not NoExtraItems: - raise TypeError(f"Cannot combine closed={closed!r} and extra_items") - - if any(issubclass(b, typing.Generic) for b in bases): - generic_base = (typing.Generic,) - else: - generic_base = () - - ns_annotations = ns.pop('__annotations__', None) - - # typing.py generally doesn't let you inherit from plain Generic, unless - # the name of the class happens to be "Protocol" - tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns) - tp_dict.__name__ = name - if tp_dict.__qualname__ == "Protocol": - tp_dict.__qualname__ = name - - if not hasattr(tp_dict, '__orig_bases__'): - tp_dict.__orig_bases__ = bases - - annotations = {} - own_annotate = None - if ns_annotations is not None: - own_annotations = ns_annotations - elif sys.version_info >= (3, 14): - if hasattr(annotationlib, "get_annotate_from_class_namespace"): - own_annotate = annotationlib.get_annotate_from_class_namespace(ns) - else: - # 3.14.0a7 and earlier - own_annotate = ns.get("__annotate__") - if own_annotate is not None: - own_annotations = annotationlib.call_annotate_function( - own_annotate, Format.FORWARDREF, owner=tp_dict - ) - else: - own_annotations = {} - else: - own_annotations = {} - msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" - if _TAKES_MODULE: - own_checked_annotations = { - n: typing._type_check(tp, msg, module=tp_dict.__module__) - for n, tp in own_annotations.items() - } - else: - own_checked_annotations = { - n: typing._type_check(tp, msg) - for n, tp in own_annotations.items() - } - required_keys = set() - optional_keys = set() - readonly_keys = set() - mutable_keys = set() - extra_items_type = extra_items - - for base in bases: - base_dict = base.__dict__ - - if sys.version_info <= (3, 14): - annotations.update(base_dict.get('__annotations__', {})) - base_required = base_dict.get('__required_keys__', set()) - required_keys |= base_required - optional_keys -= base_required - - base_optional = base_dict.get('__optional_keys__', set()) - required_keys -= base_optional - optional_keys |= base_optional - - readonly_keys.update(base_dict.get('__readonly_keys__', ())) - mutable_keys.update(base_dict.get('__mutable_keys__', ())) - - # This was specified in an earlier version of PEP 728. Support - # is retained for backwards compatibility, but only for Python - # 3.13 and lower. - if (closed and sys.version_info < (3, 14) - and "__extra_items__" in own_checked_annotations): - annotation_type = own_checked_annotations.pop("__extra_items__") - qualifiers = set(_get_typeddict_qualifiers(annotation_type)) - if Required in qualifiers: - raise TypeError( - "Special key __extra_items__ does not support " - "Required" - ) - if NotRequired in qualifiers: - raise TypeError( - "Special key __extra_items__ does not support " - "NotRequired" - ) - extra_items_type = annotation_type - - annotations.update(own_checked_annotations) - for annotation_key, annotation_type in own_checked_annotations.items(): - qualifiers = set(_get_typeddict_qualifiers(annotation_type)) - - if Required in qualifiers: - is_required = True - elif NotRequired in qualifiers: - is_required = False - else: - is_required = total - - if is_required: - required_keys.add(annotation_key) - optional_keys.discard(annotation_key) - else: - optional_keys.add(annotation_key) - required_keys.discard(annotation_key) - - if ReadOnly in qualifiers: - mutable_keys.discard(annotation_key) - readonly_keys.add(annotation_key) - else: - mutable_keys.add(annotation_key) - readonly_keys.discard(annotation_key) - - # Breakpoint: https://github.com/python/cpython/pull/119891 - if sys.version_info >= (3, 14): - def __annotate__(format): - annos = {} - for base in bases: - if base is Generic: - continue - base_annotate = base.__annotate__ - if base_annotate is None: - continue - base_annos = annotationlib.call_annotate_function( - base_annotate, format, owner=base) - annos.update(base_annos) - if own_annotate is not None: - own = annotationlib.call_annotate_function( - own_annotate, format, owner=tp_dict) - if format != Format.STRING: - own = { - n: typing._type_check(tp, msg, module=tp_dict.__module__) - for n, tp in own.items() - } - elif format == Format.STRING: - own = annotationlib.annotations_to_string(own_annotations) - elif format in (Format.FORWARDREF, Format.VALUE): - own = own_checked_annotations - else: - raise NotImplementedError(format) - annos.update(own) - return annos - - tp_dict.__annotate__ = __annotate__ - else: - tp_dict.__annotations__ = annotations - tp_dict.__required_keys__ = frozenset(required_keys) - tp_dict.__optional_keys__ = frozenset(optional_keys) - tp_dict.__readonly_keys__ = frozenset(readonly_keys) - tp_dict.__mutable_keys__ = frozenset(mutable_keys) - tp_dict.__total__ = total - tp_dict.__closed__ = closed - tp_dict.__extra_items__ = extra_items_type - return tp_dict - - __call__ = dict # static method - - def __subclasscheck__(cls, other): - # Typed dicts are only for static structural subtyping. - raise TypeError('TypedDict does not support instance and class checks') - - __instancecheck__ = __subclasscheck__ - - _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) - - def _create_typeddict( - typename, - fields, - /, - *, - typing_is_inline, - total, - closed, - extra_items, - **kwargs, - ): - if fields is _marker or fields is None: - if fields is _marker: - deprecated_thing = ( - "Failing to pass a value for the 'fields' parameter" - ) - else: - deprecated_thing = "Passing `None` as the 'fields' parameter" - - example = f"`{typename} = TypedDict({typename!r}, {{}})`" - deprecation_msg = ( - f"{deprecated_thing} is deprecated and will be disallowed in " - "Python 3.15. To create a TypedDict class with 0 fields " - "using the functional syntax, pass an empty dictionary, e.g. " - ) + example + "." - warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) - # Support a field called "closed" - if closed is not False and closed is not True and closed is not None: - kwargs["closed"] = closed - closed = None - # Or "extra_items" - if extra_items is not NoExtraItems: - kwargs["extra_items"] = extra_items - extra_items = NoExtraItems - fields = kwargs - elif kwargs: - raise TypeError("TypedDict takes either a dict or keyword arguments," - " but not both") - if kwargs: - # Breakpoint: https://github.com/python/cpython/pull/104891 - if sys.version_info >= (3, 13): - raise TypeError("TypedDict takes no keyword arguments") - warnings.warn( - "The kwargs-based syntax for TypedDict definitions is deprecated " - "in Python 3.11, will be removed in Python 3.13, and may not be " - "understood by third-party type checkers.", - DeprecationWarning, - stacklevel=2, - ) - - ns = {'__annotations__': dict(fields)} - module = _caller(depth=4 if typing_is_inline else 2) - if module is not None: - # Setting correct module is necessary to make typed dict classes - # pickleable. - ns['__module__'] = module - - td = _TypedDictMeta(typename, (), ns, total=total, closed=closed, - extra_items=extra_items) - td.__orig_bases__ = (TypedDict,) - return td - - class _TypedDictSpecialForm(_SpecialForm, _root=True): - def __call__( - self, - typename, - fields=_marker, - /, - *, - total=True, - closed=None, - extra_items=NoExtraItems, - **kwargs - ): - return _create_typeddict( - typename, - fields, - typing_is_inline=False, - total=total, - closed=closed, - extra_items=extra_items, - **kwargs, - ) - - def __mro_entries__(self, bases): - return (_TypedDict,) - - @_TypedDictSpecialForm - def TypedDict(self, args): - """A simple typed namespace. At runtime it is equivalent to a plain dict. - - TypedDict creates a dictionary type such that a type checker will expect all - instances to have a certain set of keys, where each key is - associated with a value of a consistent type. This expectation - is not checked at runtime. - - Usage:: - - class Point2D(TypedDict): - x: int - y: int - label: str - - a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK - b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check - - assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') - - The type info can be accessed via the Point2D.__annotations__ dict, and - the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. - TypedDict supports an additional equivalent form:: - - Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) - - By default, all keys must be present in a TypedDict. It is possible - to override this by specifying totality:: - - class Point2D(TypedDict, total=False): - x: int - y: int - - This means that a Point2D TypedDict can have any of the keys omitted. A type - checker is only expected to support a literal False or True as the value of - the total argument. True is the default, and makes all items defined in the - class body be required. - - The Required and NotRequired special forms can also be used to mark - individual keys as being required or not required:: - - class Point2D(TypedDict): - x: int # the "x" key must always be present (Required is the default) - y: NotRequired[int] # the "y" key can be omitted - - See PEP 655 for more details on Required and NotRequired. - """ - # This runs when creating inline TypedDicts: - if not isinstance(args, dict): - raise TypeError( - "TypedDict[...] should be used with a single dict argument" - ) - - return _create_typeddict( - "", - args, - typing_is_inline=True, - total=True, - closed=True, - extra_items=NoExtraItems, - ) - - _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) - - def is_typeddict(tp): - """Check if an annotation is a TypedDict class - - For example:: - class Film(TypedDict): - title: str - year: int - - is_typeddict(Film) # => True - is_typeddict(Union[list, str]) # => False - """ - return isinstance(tp, _TYPEDDICT_TYPES) - - -if hasattr(typing, "assert_type"): - assert_type = typing.assert_type - -else: - def assert_type(val, typ, /): - """Assert (to the type checker) that the value is of the given type. - - When the type checker encounters a call to assert_type(), it - emits an error if the value is not of the specified type:: - - def greet(name: str) -> None: - assert_type(name, str) # ok - assert_type(name, int) # type checker error - - At runtime this returns the first argument unchanged and otherwise - does nothing. - """ - return val - - -if hasattr(typing, "ReadOnly"): # 3.13+ - get_type_hints = typing.get_type_hints -else: # <=3.13 - # replaces _strip_annotations() - def _strip_extras(t): - """Strips Annotated, Required and NotRequired from a given type.""" - if isinstance(t, typing._AnnotatedAlias): - return _strip_extras(t.__origin__) - if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired, ReadOnly): - return _strip_extras(t.__args__[0]) - if isinstance(t, typing._GenericAlias): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return t.copy_with(stripped_args) - if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return _types.GenericAlias(t.__origin__, stripped_args) - if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return functools.reduce(operator.or_, stripped_args) - - return t - - def get_type_hints(obj, globalns=None, localns=None, include_extras=False): - """Return type hints for an object. - - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, adds Optional[t] if a - default value equal to None is set and recursively replaces all - 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' - (unless 'include_extras=True'). - - The argument may be a module, class, method, or function. The annotations - are returned as a dictionary. For classes, annotations include also - inherited members. - - TypeError is raised if the argument is not of a type that can contain - annotations, and an empty dictionary is returned if no annotations are - present. - - BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The - search order is locals first, then globals. - - - If no dict arguments are passed, an attempt is made to use the - globals from obj (or the respective module's globals for classes), - and these are also used as the locals. If the object does not appear - to have globals, an empty dictionary is used. - - - If one dict argument is passed, it is used for both globals and - locals. - - - If two dict arguments are passed, they specify globals and - locals, respectively. - """ - hint = typing.get_type_hints( - obj, globalns=globalns, localns=localns, include_extras=True - ) - # Breakpoint: https://github.com/python/cpython/pull/30304 - if sys.version_info < (3, 11): - _clean_optional(obj, hint, globalns, localns) - if include_extras: - return hint - return {k: _strip_extras(t) for k, t in hint.items()} - - _NoneType = type(None) - - def _could_be_inserted_optional(t): - """detects Union[..., None] pattern""" - if not isinstance(t, typing._UnionGenericAlias): - return False - # Assume if last argument is not None they are user defined - if t.__args__[-1] is not _NoneType: - return False - return True - - # < 3.11 - def _clean_optional(obj, hints, globalns=None, localns=None): - # reverts injected Union[..., None] cases from typing.get_type_hints - # when a None default value is used. - # see https://github.com/python/typing_extensions/issues/310 - if not hints or isinstance(obj, type): - return - defaults = typing._get_defaults(obj) # avoid accessing __annotations___ - if not defaults: - return - original_hints = obj.__annotations__ - for name, value in hints.items(): - # Not a Union[..., None] or replacement conditions not fullfilled - if (not _could_be_inserted_optional(value) - or name not in defaults - or defaults[name] is not None - ): - continue - original_value = original_hints[name] - # value=NoneType should have caused a skip above but check for safety - if original_value is None: - original_value = _NoneType - # Forward reference - if isinstance(original_value, str): - if globalns is None: - if isinstance(obj, _types.ModuleType): - globalns = obj.__dict__ - else: - nsobj = obj - # Find globalns for the unwrapped object. - while hasattr(nsobj, '__wrapped__'): - nsobj = nsobj.__wrapped__ - globalns = getattr(nsobj, '__globals__', {}) - if localns is None: - localns = globalns - elif localns is None: - localns = globalns - - original_value = ForwardRef( - original_value, - is_argument=not isinstance(obj, _types.ModuleType) - ) - original_evaluated = typing._eval_type(original_value, globalns, localns) - # Compare if values differ. Note that even if equal - # value might be cached by typing._tp_cache contrary to original_evaluated - if original_evaluated != value or ( - # 3.10: ForwardRefs of UnionType might be turned into _UnionGenericAlias - hasattr(_types, "UnionType") - and isinstance(original_evaluated, _types.UnionType) - and not isinstance(value, _types.UnionType) - ): - hints[name] = original_evaluated - -# Python 3.9 has get_origin() and get_args() but those implementations don't support -# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. -# Breakpoint: https://github.com/python/cpython/pull/25298 -if sys.version_info >= (3, 10): - get_origin = typing.get_origin - get_args = typing.get_args -# 3.9 -else: - def get_origin(tp): - """Get the unsubscripted version of a type. - - This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar - and Annotated. Return None for unsupported types. Examples:: - - get_origin(Literal[42]) is Literal - get_origin(int) is None - get_origin(ClassVar[int]) is ClassVar - get_origin(Generic) is Generic - get_origin(Generic[T]) is Generic - get_origin(Union[T, int]) is Union - get_origin(List[Tuple[T, T]][int]) == list - get_origin(P.args) is P - """ - if isinstance(tp, typing._AnnotatedAlias): - return Annotated - if isinstance(tp, (typing._BaseGenericAlias, _types.GenericAlias, - ParamSpecArgs, ParamSpecKwargs)): - return tp.__origin__ - if tp is typing.Generic: - return typing.Generic - return None - - def get_args(tp): - """Get type arguments with all substitutions performed. - - For unions, basic simplifications used by Union constructor are performed. - Examples:: - get_args(Dict[str, int]) == (str, int) - get_args(int) == () - get_args(Union[int, Union[T, int], str][int]) == (int, str) - get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) - get_args(Callable[[], T][int]) == ([], int) - """ - if isinstance(tp, typing._AnnotatedAlias): - return (tp.__origin__, *tp.__metadata__) - if isinstance(tp, (typing._GenericAlias, _types.GenericAlias)): - res = tp.__args__ - if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: - res = (list(res[:-1]), res[-1]) - return res - return () - - -# 3.10+ -if hasattr(typing, 'TypeAlias'): - TypeAlias = typing.TypeAlias -# 3.9 -else: - @_ExtensionsSpecialForm - def TypeAlias(self, parameters): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example above. - """ - raise TypeError(f"{self} is not subscriptable") - - -def _set_default(type_param, default): - type_param.has_default = lambda: default is not NoDefault - type_param.__default__ = default - - -def _set_module(typevarlike): - # for pickling: - def_mod = _caller(depth=2) - if def_mod != 'typing_extensions': - typevarlike.__module__ = def_mod - - -class _DefaultMixin: - """Mixin for TypeVarLike defaults.""" - - __slots__ = () - __init__ = _set_default - - -# Classes using this metaclass must provide a _backported_typevarlike ClassVar -class _TypeVarLikeMeta(type): - def __instancecheck__(cls, __instance: Any) -> bool: - return isinstance(__instance, cls._backported_typevarlike) - - -if _PEP_696_IMPLEMENTED: - from typing import TypeVar -else: - # Add default and infer_variance parameters from PEP 696 and 695 - class TypeVar(metaclass=_TypeVarLikeMeta): - """Type variable.""" - - _backported_typevarlike = typing.TypeVar - - def __new__(cls, name, *constraints, bound=None, - covariant=False, contravariant=False, - default=NoDefault, infer_variance=False): - if hasattr(typing, "TypeAliasType"): - # PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar - typevar = typing.TypeVar(name, *constraints, bound=bound, - covariant=covariant, contravariant=contravariant, - infer_variance=infer_variance) - else: - typevar = typing.TypeVar(name, *constraints, bound=bound, - covariant=covariant, contravariant=contravariant) - if infer_variance and (covariant or contravariant): - raise ValueError("Variance cannot be specified with infer_variance.") - typevar.__infer_variance__ = infer_variance - - _set_default(typevar, default) - _set_module(typevar) - - def _tvar_prepare_subst(alias, args): - if ( - typevar.has_default() - and alias.__parameters__.index(typevar) == len(args) - ): - args += (typevar.__default__,) - return args - - typevar.__typing_prepare_subst__ = _tvar_prepare_subst - return typevar - - def __init_subclass__(cls) -> None: - raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type") - - -# Python 3.10+ has PEP 612 -if hasattr(typing, 'ParamSpecArgs'): - ParamSpecArgs = typing.ParamSpecArgs - ParamSpecKwargs = typing.ParamSpecKwargs -# 3.9 -else: - class _Immutable: - """Mixin to indicate that object should not be copied.""" - __slots__ = () - - def __copy__(self): - return self - - def __deepcopy__(self, memo): - return self - - class ParamSpecArgs(_Immutable): - """The args for a ParamSpec object. - - Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. - - ParamSpecArgs objects have a reference back to their ParamSpec: - - P.args.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.args" - - def __eq__(self, other): - if not isinstance(other, ParamSpecArgs): - return NotImplemented - return self.__origin__ == other.__origin__ - - class ParamSpecKwargs(_Immutable): - """The kwargs for a ParamSpec object. - - Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. - - ParamSpecKwargs objects have a reference back to their ParamSpec: - - P.kwargs.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.kwargs" - - def __eq__(self, other): - if not isinstance(other, ParamSpecKwargs): - return NotImplemented - return self.__origin__ == other.__origin__ - - -if _PEP_696_IMPLEMENTED: - from typing import ParamSpec - -# 3.10+ -elif hasattr(typing, 'ParamSpec'): - - # Add default parameter - PEP 696 - class ParamSpec(metaclass=_TypeVarLikeMeta): - """Parameter specification.""" - - _backported_typevarlike = typing.ParamSpec - - def __new__(cls, name, *, bound=None, - covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - if hasattr(typing, "TypeAliasType"): - # PEP 695 implemented, can pass infer_variance to typing.TypeVar - paramspec = typing.ParamSpec(name, bound=bound, - covariant=covariant, - contravariant=contravariant, - infer_variance=infer_variance) - else: - paramspec = typing.ParamSpec(name, bound=bound, - covariant=covariant, - contravariant=contravariant) - paramspec.__infer_variance__ = bool(infer_variance) - - _set_default(paramspec, default) - _set_module(paramspec) - - def _paramspec_prepare_subst(alias, args): - params = alias.__parameters__ - i = params.index(paramspec) - if i == len(args) and paramspec.has_default(): - args = [*args, paramspec.__default__] - if i >= len(args): - raise TypeError(f"Too few arguments for {alias}") - # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. - if len(params) == 1 and not typing._is_param_expr(args[0]): - assert i == 0 - args = (args,) - # Convert lists to tuples to help other libraries cache the results. - elif isinstance(args[i], list): - args = (*args[:i], tuple(args[i]), *args[i + 1:]) - return args - - paramspec.__typing_prepare_subst__ = _paramspec_prepare_subst - return paramspec - - def __init_subclass__(cls) -> None: - raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") - -# 3.9 -else: - - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class ParamSpec(list, _DefaultMixin): - """Parameter specification variable. - - Usage:: - - P = ParamSpec('P') - - Parameter specification variables exist primarily for the benefit of static - type checkers. They are used to forward the parameter types of one - callable to another callable, a pattern commonly found in higher order - functions and decorators. They are only valid when used in ``Concatenate``, - or s the first argument to ``Callable``. In Python 3.10 and higher, - they are also supported in user-defined Generics at runtime. - See class Generic for more information on generic types. An - example for annotating a decorator:: - - T = TypeVar('T') - P = ParamSpec('P') - - def add_logging(f: Callable[P, T]) -> Callable[P, T]: - '''A type-safe decorator to add logging to a function.''' - def inner(*args: P.args, **kwargs: P.kwargs) -> T: - logging.info(f'{f.__name__} was called') - return f(*args, **kwargs) - return inner - - @add_logging - def add_two(x: float, y: float) -> float: - '''Add two numbers together.''' - return x + y - - Parameter specification variables defined with covariant=True or - contravariant=True can be used to declare covariant or contravariant - generic types. These keyword arguments are valid, but their actual semantics - are yet to be decided. See PEP 612 for details. - - Parameter specification variables can be introspected. e.g.: - - P.__name__ == 'T' - P.__bound__ == None - P.__covariant__ == False - P.__contravariant__ == False - - Note that only parameter specification variables defined in global scope can - be pickled. - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - @property - def args(self): - return ParamSpecArgs(self) - - @property - def kwargs(self): - return ParamSpecKwargs(self) - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - list.__init__(self, [self]) - self.__name__ = name - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - self.__infer_variance__ = bool(infer_variance) - self.__bound__ = bound - _DefaultMixin.__init__(self, default) - - # for pickling: - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __repr__(self): - if self.__infer_variance__: - prefix = '' - elif self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - # Hack to get typing._type_check to pass. - def __call__(self, *args, **kwargs): - pass - - def __init_subclass__(cls) -> None: - raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") - - -# 3.9 -if not hasattr(typing, 'Concatenate'): - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - - # 3.9.0-1 - if not hasattr(typing, '_type_convert'): - def _type_convert(arg, module=None, *, allow_special_forms=False): - """For converting None to type(None), and strings to ForwardRef.""" - if arg is None: - return type(None) - if isinstance(arg, str): - if sys.version_info <= (3, 9, 6): - return ForwardRef(arg) - if sys.version_info <= (3, 9, 7): - return ForwardRef(arg, module=module) - return ForwardRef(arg, module=module, is_class=allow_special_forms) - return arg - else: - _type_convert = typing._type_convert - - class _ConcatenateGenericAlias(list): - - # Trick Generic into looking into this for __parameters__. - __class__ = typing._GenericAlias - - def __init__(self, origin, args): - # Cannot use `super().__init__` here because of the `__class__` assignment - # in the class body (https://github.com/python/typing_extensions/issues/661) - list.__init__(self, args) - self.__origin__ = origin - self.__args__ = args - - def __repr__(self): - _type_repr = typing._type_repr - return (f'{_type_repr(self.__origin__)}' - f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') - - def __hash__(self): - return hash((self.__origin__, self.__args__)) - - # Hack to get typing._type_check to pass in Generic. - def __call__(self, *args, **kwargs): - pass - - @property - def __parameters__(self): - return tuple( - tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) - ) - - # 3.9 used by __getitem__ below - def copy_with(self, params): - if isinstance(params[-1], _ConcatenateGenericAlias): - params = (*params[:-1], *params[-1].__args__) - elif isinstance(params[-1], (list, tuple)): - return (*params[:-1], *params[-1]) - elif (not (params[-1] is ... or isinstance(params[-1], ParamSpec))): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - return self.__class__(self.__origin__, params) - - # 3.9; accessed during GenericAlias.__getitem__ when substituting - def __getitem__(self, args): - if self.__origin__ in (Generic, Protocol): - # Can't subscript Generic[...] or Protocol[...]. - raise TypeError(f"Cannot subscript already-subscripted {self}") - if not self.__parameters__: - raise TypeError(f"{self} is not a generic class") - - if not isinstance(args, tuple): - args = (args,) - args = _unpack_args(*(_type_convert(p) for p in args)) - params = self.__parameters__ - for param in params: - prepare = getattr(param, "__typing_prepare_subst__", None) - if prepare is not None: - args = prepare(self, args) - # 3.9 & typing.ParamSpec - elif isinstance(param, ParamSpec): - i = params.index(param) - if ( - i == len(args) - and getattr(param, '__default__', NoDefault) is not NoDefault - ): - args = [*args, param.__default__] - if i >= len(args): - raise TypeError(f"Too few arguments for {self}") - # Special case for Z[[int, str, bool]] == Z[int, str, bool] - if len(params) == 1 and not _is_param_expr(args[0]): - assert i == 0 - args = (args,) - elif ( - isinstance(args[i], list) - # 3.9 - # This class inherits from list do not convert - and not isinstance(args[i], _ConcatenateGenericAlias) - ): - args = (*args[:i], tuple(args[i]), *args[i + 1:]) - - alen = len(args) - plen = len(params) - if alen != plen: - raise TypeError( - f"Too {'many' if alen > plen else 'few'} arguments for {self};" - f" actual {alen}, expected {plen}" - ) - - subst = dict(zip(self.__parameters__, args)) - # determine new args - new_args = [] - for arg in self.__args__: - if isinstance(arg, type): - new_args.append(arg) - continue - if isinstance(arg, TypeVar): - arg = subst[arg] - if ( - (isinstance(arg, typing._GenericAlias) and _is_unpack(arg)) - or ( - hasattr(_types, "GenericAlias") - and isinstance(arg, _types.GenericAlias) - and getattr(arg, "__unpacked__", False) - ) - ): - raise TypeError(f"{arg} is not valid as type argument") - - elif isinstance(arg, - typing._GenericAlias - if not hasattr(_types, "GenericAlias") else - (typing._GenericAlias, _types.GenericAlias) - ): - subparams = arg.__parameters__ - if subparams: - subargs = tuple(subst[x] for x in subparams) - arg = arg[subargs] - new_args.append(arg) - return self.copy_with(tuple(new_args)) - -# 3.10+ -else: - _ConcatenateGenericAlias = typing._ConcatenateGenericAlias - - # 3.10 - if sys.version_info < (3, 11): - - class _ConcatenateGenericAlias(typing._ConcatenateGenericAlias, _root=True): - # needed for checks in collections.abc.Callable to accept this class - __module__ = "typing" - - def copy_with(self, params): - if isinstance(params[-1], (list, tuple)): - return (*params[:-1], *params[-1]) - if isinstance(params[-1], typing._ConcatenateGenericAlias): - params = (*params[:-1], *params[-1].__args__) - elif not (params[-1] is ... or isinstance(params[-1], ParamSpec)): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - return super(typing._ConcatenateGenericAlias, self).copy_with(params) - - def __getitem__(self, args): - value = super().__getitem__(args) - if isinstance(value, tuple) and any(_is_unpack(t) for t in value): - return tuple(_unpack_args(*(n for n in value))) - return value - - -# 3.9.2 -class _EllipsisDummy: ... - - -# <=3.10 -def _create_concatenate_alias(origin, parameters): - if parameters[-1] is ... and sys.version_info < (3, 9, 2): - # Hack: Arguments must be types, replace it with one. - parameters = (*parameters[:-1], _EllipsisDummy) - if sys.version_info >= (3, 10, 3): - concatenate = _ConcatenateGenericAlias(origin, parameters, - _typevar_types=(TypeVar, ParamSpec), - _paramspec_tvars=True) - else: - concatenate = _ConcatenateGenericAlias(origin, parameters) - if parameters[-1] is not _EllipsisDummy: - return concatenate - # Remove dummy again - concatenate.__args__ = tuple(p if p is not _EllipsisDummy else ... - for p in concatenate.__args__) - if sys.version_info < (3, 10): - # backport needs __args__ adjustment only - return concatenate - concatenate.__parameters__ = tuple(p for p in concatenate.__parameters__ - if p is not _EllipsisDummy) - return concatenate - - -# <=3.10 -@typing._tp_cache -def _concatenate_getitem(self, parameters): - if parameters == (): - raise TypeError("Cannot take a Concatenate of no types.") - if not isinstance(parameters, tuple): - parameters = (parameters,) - if not (parameters[-1] is ... or isinstance(parameters[-1], ParamSpec)): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable or ellipsis.") - msg = "Concatenate[arg, ...]: each arg must be a type." - parameters = (*(typing._type_check(p, msg) for p in parameters[:-1]), - parameters[-1]) - return _create_concatenate_alias(self, parameters) - - -# 3.11+; Concatenate does not accept ellipsis in 3.10 -# Breakpoint: https://github.com/python/cpython/pull/30969 -if sys.version_info >= (3, 11): - Concatenate = typing.Concatenate -# <=3.10 -else: - @_ExtensionsSpecialForm - def Concatenate(self, parameters): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - return _concatenate_getitem(self, parameters) - - -# 3.10+ -if hasattr(typing, 'TypeGuard'): - TypeGuard = typing.TypeGuard -# 3.9 -else: - @_ExtensionsSpecialForm - def TypeGuard(self, parameters): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - -# 3.13+ -if hasattr(typing, 'TypeIs'): - TypeIs = typing.TypeIs -# <=3.12 -else: - @_ExtensionsSpecialForm - def TypeIs(self, parameters): - """Special typing form used to annotate the return type of a user-defined - type narrower function. ``TypeIs`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeIs`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeIs[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeIs`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the intersection of the type inside ``TypeIs`` and the argument's - previously known type. - - For example:: - - def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]: - return hasattr(val, '__await__') - - def f(val: Union[int, Awaitable[int]]) -> int: - if is_awaitable(val): - assert_type(val, Awaitable[int]) - else: - assert_type(val, int) - - ``TypeIs`` also works with type variables. For more information, see - PEP 742 (Narrowing types with TypeIs). - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - -# 3.15+? -if hasattr(typing, 'TypeForm'): - TypeForm = typing.TypeForm -# <=3.14 -else: - class _TypeFormForm(_ExtensionsSpecialForm, _root=True): - # TypeForm(X) is equivalent to X but indicates to the type checker - # that the object is a TypeForm. - def __call__(self, obj, /): - return obj - - @_TypeFormForm - def TypeForm(self, parameters): - """A special form representing the value that results from the evaluation - of a type expression. This value encodes the information supplied in the - type expression, and it represents the type described by that type expression. - - When used in a type expression, TypeForm describes a set of type form objects. - It accepts a single type argument, which must be a valid type expression. - ``TypeForm[T]`` describes the set of all type form objects that represent - the type T or types that are assignable to T. - - Usage: - - def cast[T](typ: TypeForm[T], value: Any) -> T: ... - - reveal_type(cast(int, "x")) # int - - See PEP 747 for more information. - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - - - -if hasattr(typing, "LiteralString"): # 3.11+ - LiteralString = typing.LiteralString -else: - @_SpecialForm - def LiteralString(self, params): - """Represents an arbitrary literal string. - - Example:: - - from typing_extensions import LiteralString - - def query(sql: LiteralString) -> ...: - ... - - query("SELECT * FROM table") # ok - query(f"SELECT * FROM {input()}") # not ok - - See PEP 675 for details. - - """ - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, "Self"): # 3.11+ - Self = typing.Self -else: - @_SpecialForm - def Self(self, params): - """Used to spell the type of "self" in classes. - - Example:: - - from typing import Self - - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self - - """ - - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, "Never"): # 3.11+ - Never = typing.Never -else: - @_SpecialForm - def Never(self, params): - """The bottom type, a type that has no members. - - This can be used to define a function that should never be - called, or a function that never returns:: - - from typing_extensions import Never - - def never_call_me(arg: Never) -> None: - pass - - def int_or_str(arg: int | str) -> None: - never_call_me(arg) # type checker error - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - never_call_me(arg) # ok, arg is of type Never - - """ - - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, 'Required'): # 3.11+ - Required = typing.Required - NotRequired = typing.NotRequired -else: # <=3.10 - @_ExtensionsSpecialForm - def Required(self, parameters): - """A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - @_ExtensionsSpecialForm - def NotRequired(self, parameters): - """A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - -if hasattr(typing, 'ReadOnly'): - ReadOnly = typing.ReadOnly -else: # <=3.12 - @_ExtensionsSpecialForm - def ReadOnly(self, parameters): - """A special typing construct to mark an item of a TypedDict as read-only. - - For example: - - class Movie(TypedDict): - title: ReadOnly[str] - year: int - - def mutate_movie(m: Movie) -> None: - m["year"] = 1992 # allowed - m["title"] = "The Matrix" # typechecker error - - There is no runtime checking for this property. - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - -_UNPACK_DOC = """\ -Type unpack operator. - -The type unpack operator takes the child types from some container type, -such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For -example: - - # For some generic class `Foo`: - Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] - - Ts = TypeVarTuple('Ts') - # Specifies that `Bar` is generic in an arbitrary number of types. - # (Think of `Ts` as a tuple of an arbitrary number of individual - # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the - # `Generic[]`.) - class Bar(Generic[Unpack[Ts]]): ... - Bar[int] # Valid - Bar[int, str] # Also valid - -From Python 3.11, this can also be done using the `*` operator: - - Foo[*tuple[int, str]] - class Bar(Generic[*Ts]): ... - -The operator can also be used along with a `TypedDict` to annotate -`**kwargs` in a function signature. For instance: - - class Movie(TypedDict): - name: str - year: int - - # This function expects two keyword arguments - *name* of type `str` and - # *year* of type `int`. - def foo(**kwargs: Unpack[Movie]): ... - -Note that there is only some runtime checking of this operator. Not -everything the runtime allows may be accepted by static type checkers. - -For more information, see PEP 646 and PEP 692. -""" - - -# PEP 692 changed the repr of Unpack[] -# Breakpoint: https://github.com/python/cpython/pull/104048 -if sys.version_info >= (3, 12): - Unpack = typing.Unpack - - def _is_unpack(obj): - return get_origin(obj) is Unpack - -else: # <=3.11 - class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True): - def __init__(self, getitem): - super().__init__(getitem) - self.__doc__ = _UNPACK_DOC - - class _UnpackAlias(typing._GenericAlias, _root=True): - if sys.version_info < (3, 11): - # needed for compatibility with Generic[Unpack[Ts]] - __class__ = typing.TypeVar - - @property - def __typing_unpacked_tuple_args__(self): - assert self.__origin__ is Unpack - assert len(self.__args__) == 1 - arg, = self.__args__ - if isinstance(arg, (typing._GenericAlias, _types.GenericAlias)): - if arg.__origin__ is not tuple: - raise TypeError("Unpack[...] must be used with a tuple type") - return arg.__args__ - return None - - @property - def __typing_is_unpacked_typevartuple__(self): - assert self.__origin__ is Unpack - assert len(self.__args__) == 1 - return isinstance(self.__args__[0], TypeVarTuple) - - def __getitem__(self, args): - if self.__typing_is_unpacked_typevartuple__: - return args - # Cannot use `super().__getitem__` here because of the `__class__` assignment - # in the class body on Python <=3.11 - # (https://github.com/python/typing_extensions/issues/661) - return typing._GenericAlias.__getitem__(self, args) - - @_UnpackSpecialForm - def Unpack(self, parameters): - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return _UnpackAlias(self, (item,)) - - def _is_unpack(obj): - return isinstance(obj, _UnpackAlias) - - -def _unpack_args(*args): - newargs = [] - for arg in args: - subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) - if subargs is not None and (not (subargs and subargs[-1] is ...)): - newargs.extend(subargs) - else: - newargs.append(arg) - return newargs - - -if sys.version_info >= (3, 15): - from typing import TypeVarTuple - -elif hasattr(typing, "TypeVarTuple"): # 3.11+ - - # Add default parameter - PEP 696 and bound/variance parameters - class TypeVarTuple(metaclass=_TypeVarLikeMeta): - """Type variable tuple.""" - - _backported_typevarlike = typing.TypeVarTuple - - def __new__(cls, name, *, bound=None, - covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - - if _PEP_696_IMPLEMENTED: - # can pass default argument - tvt = typing.TypeVarTuple(name, default=default) - else: - tvt = typing.TypeVarTuple(name) - _set_default(tvt, default) - - tvt.__bound__ = bound - tvt.__covariant__ = bool(covariant) - tvt.__contravariant__ = bool(contravariant) - tvt.__infer_variance__ = bool(infer_variance) - - _set_module(tvt) - - def _typevartuple_prepare_subst(alias, args): - params = alias.__parameters__ - typevartuple_index = params.index(tvt) - for param in params[typevartuple_index + 1:]: - if isinstance(param, TypeVarTuple): - raise TypeError( - f"More than one TypeVarTuple parameter in {alias}" - ) - - alen = len(args) - plen = len(params) - left = typevartuple_index - right = plen - typevartuple_index - 1 - var_tuple_index = None - fillarg = None - for k, arg in enumerate(args): - if not isinstance(arg, type): - subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) - if subargs and len(subargs) == 2 and subargs[-1] is ...: - if var_tuple_index is not None: - raise TypeError( - "More than one unpacked " - "arbitrary-length tuple argument" - ) - var_tuple_index = k - fillarg = subargs[0] - if var_tuple_index is not None: - left = min(left, var_tuple_index) - right = min(right, alen - var_tuple_index - 1) - elif left + right > alen: - raise TypeError(f"Too few arguments for {alias};" - f" actual {alen}, expected at least {plen - 1}") - if left == alen - right and tvt.has_default(): - replacement = _unpack_args(tvt.__default__) - else: - replacement = args[left: alen - right] - - return ( - *args[:left], - *([fillarg] * (typevartuple_index - left)), - replacement, - *([fillarg] * (plen - right - left - typevartuple_index - 1)), - *args[alen - right:], - ) - - tvt.__typing_prepare_subst__ = _typevartuple_prepare_subst - return tvt - - def __init_subclass__(self, *args, **kwds): - raise TypeError("Cannot subclass special typing classes") - -else: # <=3.10 - class TypeVarTuple(_DefaultMixin): - """Type variable tuple. - - Usage:: - - Ts = TypeVarTuple('Ts') - - In the same way that a normal type variable is a stand-in for a single - type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* - type such as ``Tuple[int, str]``. - - Type variable tuples can be used in ``Generic`` declarations. - Consider the following example:: - - class Array(Generic[*Ts]): ... - - The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, - where ``T1`` and ``T2`` are type variables. To use these type variables - as type parameters of ``Array``, we must *unpack* the type variable tuple using - the star operator: ``*Ts``. The signature of ``Array`` then behaves - as if we had simply written ``class Array(Generic[T1, T2]): ...``. - In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows - us to parameterise the class with an *arbitrary* number of type parameters. - - Type variable tuples can be used anywhere a normal ``TypeVar`` can. - This includes class definitions, as shown above, as well as function - signatures and variable annotations:: - - class Array(Generic[*Ts]): - - def __init__(self, shape: Tuple[*Ts]): - self._shape: Tuple[*Ts] = shape - - def get_shape(self) -> Tuple[*Ts]: - return self._shape - - shape = (Height(480), Width(640)) - x: Array[Height, Width] = Array(shape) - y = abs(x) # Inferred type is Array[Height, Width] - z = x + x # ... is Array[Height, Width] - x.get_shape() # ... is tuple[Height, Width] - - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - def __iter__(self): - yield self.__unpacked__ - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False, - infer_variance=False, default=NoDefault): - self.__name__ = name - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - self.__infer_variance__ = bool(infer_variance) - self.__bound__ = bound - _DefaultMixin.__init__(self, default) - - # for pickling: - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - self.__unpacked__ = Unpack[self] - - def __repr__(self): - if self.__infer_variance__: - prefix = '' - elif self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - def __init_subclass__(self, *args, **kwds): - if '_root' not in kwds: - raise TypeError("Cannot subclass special typing classes") - - -if hasattr(typing, "reveal_type"): # 3.11+ - reveal_type = typing.reveal_type -else: # <=3.10 - def reveal_type(obj: T, /) -> T: - """Reveal the inferred type of a variable. - - When a static type checker encounters a call to ``reveal_type()``, - it will emit the inferred type of the argument:: - - x: int = 1 - reveal_type(x) - - Running a static type checker (e.g., ``mypy``) on this example - will produce output similar to 'Revealed type is "builtins.int"'. - - At runtime, the function prints the runtime type of the - argument and returns it unchanged. - - """ - print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr) - return obj - - -if hasattr(typing, "_ASSERT_NEVER_REPR_MAX_LENGTH"): # 3.11+ - _ASSERT_NEVER_REPR_MAX_LENGTH = typing._ASSERT_NEVER_REPR_MAX_LENGTH -else: # <=3.10 - _ASSERT_NEVER_REPR_MAX_LENGTH = 100 - - -if hasattr(typing, "assert_never"): # 3.11+ - assert_never = typing.assert_never -else: # <=3.10 - def assert_never(arg: Never, /) -> Never: - """Assert to the type checker that a line of code is unreachable. - - Example:: - - def int_or_str(arg: int | str) -> None: - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - assert_never(arg) - - If a type checker finds that a call to assert_never() is - reachable, it will emit an error. - - At runtime, this throws an exception when called. - - """ - value = repr(arg) - if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH: - value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...' - raise AssertionError(f"Expected code to be unreachable, but got: {value}") - - -# dataclass_transform exists in 3.11 but lacks the frozen_default parameter -# Breakpoint: https://github.com/python/cpython/pull/99958 -if sys.version_info >= (3, 12): # 3.12+ - dataclass_transform = typing.dataclass_transform -else: # <=3.11 - def dataclass_transform( - *, - eq_default: bool = True, - order_default: bool = False, - kw_only_default: bool = False, - frozen_default: bool = False, - field_specifiers: typing.Tuple[ - typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], - ... - ] = (), - **kwargs: typing.Any, - ) -> typing.Callable[[T], T]: - """Decorator that marks a function, class, or metaclass as providing - dataclass-like behavior. - - Example: - - from typing_extensions import dataclass_transform - - _T = TypeVar("_T") - - # Used on a decorator function - @dataclass_transform() - def create_model(cls: type[_T]) -> type[_T]: - ... - return cls - - @create_model - class CustomerModel: - id: int - name: str - - # Used on a base class - @dataclass_transform() - class ModelBase: ... - - class CustomerModel(ModelBase): - id: int - name: str - - # Used on a metaclass - @dataclass_transform() - class ModelMeta(type): ... - - class ModelBase(metaclass=ModelMeta): ... - - class CustomerModel(ModelBase): - id: int - name: str - - Each of the ``CustomerModel`` classes defined in this example will now - behave similarly to a dataclass created with the ``@dataclasses.dataclass`` - decorator. For example, the type checker will synthesize an ``__init__`` - method. - - The arguments to this decorator can be used to customize this behavior: - - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be - True or False if it is omitted by the caller. - - ``order_default`` indicates whether the ``order`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``kw_only_default`` indicates whether the ``kw_only`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``frozen_default`` indicates whether the ``frozen`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``field_specifiers`` specifies a static list of supported classes - or functions that describe fields, similar to ``dataclasses.field()``. - - At runtime, this decorator records its arguments in the - ``__dataclass_transform__`` attribute on the decorated object. - - See PEP 681 for details. - - """ - def decorator(cls_or_fn): - cls_or_fn.__dataclass_transform__ = { - "eq_default": eq_default, - "order_default": order_default, - "kw_only_default": kw_only_default, - "frozen_default": frozen_default, - "field_specifiers": field_specifiers, - "kwargs": kwargs, - } - return cls_or_fn - return decorator - - -if hasattr(typing, "override"): # 3.12+ - override = typing.override -else: # <=3.11 - _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) - - def override(arg: _F, /) -> _F: - """Indicate that a method is intended to override a method in a base class. - - Usage: - - class Base: - def method(self) -> None: - pass - - class Child(Base): - @override - def method(self) -> None: - super().method() - - When this decorator is applied to a method, the type checker will - validate that it overrides a method with the same name on a base class. - This helps prevent bugs that may occur when a base class is changed - without an equivalent change to a child class. - - There is no runtime checking of these properties. The decorator - sets the ``__override__`` attribute to ``True`` on the decorated object - to allow runtime introspection. - - See PEP 698 for details. - - """ - try: - arg.__override__ = True - except (AttributeError, TypeError): - # Skip the attribute silently if it is not writable. - # AttributeError happens if the object has __slots__ or a - # read-only property, TypeError if it's a builtin class. - pass - return arg - - -# Python 3.13.8+ and 3.14.1+ contain a fix for the wrapped __init_subclass__ -# Breakpoint: https://github.com/python/cpython/pull/138210 -if ((3, 13, 8) <= sys.version_info < (3, 14)) or sys.version_info >= (3, 14, 1): - deprecated = warnings.deprecated -else: - _T = typing.TypeVar("_T") - - class deprecated: - """Indicate that a class, function or overload is deprecated. - - When this decorator is applied to an object, the type checker - will generate a diagnostic on usage of the deprecated object. - - Usage: - - @deprecated("Use B instead") - class A: - pass - - @deprecated("Use g instead") - def f(): - pass - - @overload - @deprecated("int support is deprecated") - def g(x: int) -> int: ... - @overload - def g(x: str) -> int: ... - - The warning specified by *category* will be emitted at runtime - on use of deprecated objects. For functions, that happens on calls; - for classes, on instantiation and on creation of subclasses. - If the *category* is ``None``, no warning is emitted at runtime. - The *stacklevel* determines where the - warning is emitted. If it is ``1`` (the default), the warning - is emitted at the direct caller of the deprecated object; if it - is higher, it is emitted further up the stack. - Static type checker behavior is not affected by the *category* - and *stacklevel* arguments. - - The deprecation message passed to the decorator is saved in the - ``__deprecated__`` attribute on the decorated object. - If applied to an overload, the decorator - must be after the ``@overload`` decorator for the attribute to - exist on the overload as returned by ``get_overloads()``. - - See PEP 702 for details. - - """ - def __init__( - self, - message: str, - /, - *, - category: typing.Optional[typing.Type[Warning]] = DeprecationWarning, - stacklevel: int = 1, - ) -> None: - if not isinstance(message, str): - raise TypeError( - "Expected an object of type str for 'message', not " - f"{type(message).__name__!r}" - ) - self.message = message - self.category = category - self.stacklevel = stacklevel - - def __call__(self, arg: _T, /) -> _T: - # Make sure the inner functions created below don't - # retain a reference to self. - msg = self.message - category = self.category - stacklevel = self.stacklevel - if category is None: - arg.__deprecated__ = msg - return arg - elif isinstance(arg, type): - import functools - from types import MethodType - - original_new = arg.__new__ - - @functools.wraps(original_new) - def __new__(cls, /, *args, **kwargs): - if cls is arg: - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - if original_new is not object.__new__: - return original_new(cls, *args, **kwargs) - # Mirrors a similar check in object.__new__. - elif cls.__init__ is object.__init__ and (args or kwargs): - raise TypeError(f"{cls.__name__}() takes no arguments") - else: - return original_new(cls) - - arg.__new__ = staticmethod(__new__) - - if "__init_subclass__" in arg.__dict__: - # __init_subclass__ is directly present on the decorated class. - # Synthesize a wrapper that calls this method directly. - original_init_subclass = arg.__init_subclass__ - # We need slightly different behavior if __init_subclass__ - # is a bound method (likely if it was implemented in Python). - # Otherwise, it likely means it's a builtin such as - # object's implementation of __init_subclass__. - if isinstance(original_init_subclass, MethodType): - original_init_subclass = original_init_subclass.__func__ - - @functools.wraps(original_init_subclass) - def __init_subclass__(*args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return original_init_subclass(*args, **kwargs) - else: - def __init_subclass__(cls, *args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return super(arg, cls).__init_subclass__(*args, **kwargs) - - arg.__init_subclass__ = classmethod(__init_subclass__) - - arg.__deprecated__ = __new__.__deprecated__ = msg - __init_subclass__.__deprecated__ = msg - return arg - elif callable(arg): - import functools - import inspect - - @functools.wraps(arg) - def wrapper(*args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel + 1) - return arg(*args, **kwargs) - - if inspect.iscoroutinefunction(arg): - # Breakpoint: https://github.com/python/cpython/pull/99247 - if sys.version_info >= (3, 12): - wrapper = inspect.markcoroutinefunction(wrapper) - else: - import asyncio.coroutines - - wrapper._is_coroutine = asyncio.coroutines._is_coroutine - - arg.__deprecated__ = wrapper.__deprecated__ = msg - return wrapper - else: - raise TypeError( - "@deprecated decorator with non-None category must be applied to " - f"a class or callable, not {arg!r}" - ) - -# Breakpoint: https://github.com/python/cpython/pull/23702 -if sys.version_info < (3, 10): - def _is_param_expr(arg): - return arg is ... or isinstance( - arg, (tuple, list, ParamSpec, _ConcatenateGenericAlias) - ) -else: - def _is_param_expr(arg): - return arg is ... or isinstance( - arg, - ( - tuple, - list, - ParamSpec, - _ConcatenateGenericAlias, - typing._ConcatenateGenericAlias, - ), - ) - - -# We have to do some monkey patching to deal with the dual nature of -# Unpack/TypeVarTuple: -# - We want Unpack to be a kind of TypeVar so it gets accepted in -# Generic[Unpack[Ts]] -# - We want it to *not* be treated as a TypeVar for the purposes of -# counting generic parameters, so that when we subscript a generic, -# the runtime doesn't try to substitute the Unpack with the subscripted type. -if not hasattr(typing, "TypeVarTuple"): - def _check_generic(cls, parameters, elen=_marker): - """Check correct count for parameters of a generic cls (internal helper). - - This gives a nice error message in case of count mismatch. - """ - # If substituting a single ParamSpec with multiple arguments - # we do not check the count - if (inspect.isclass(cls) and issubclass(cls, typing.Generic) - and len(cls.__parameters__) == 1 - and isinstance(cls.__parameters__[0], ParamSpec) - and parameters - and not _is_param_expr(parameters[0]) - ): - # Generic modifies parameters variable, but here we cannot do this - return - - if not elen: - raise TypeError(f"{cls} is not a generic class") - if elen is _marker: - if not hasattr(cls, "__parameters__") or not cls.__parameters__: - raise TypeError(f"{cls} is not a generic class") - elen = len(cls.__parameters__) - alen = len(parameters) - if alen != elen: - expect_val = elen - if hasattr(cls, "__parameters__"): - parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] - num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) - if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): - return - - # deal with TypeVarLike defaults - # required TypeVarLikes cannot appear after a defaulted one. - if alen < elen: - # since we validate TypeVarLike default in _collect_type_vars - # or _collect_parameters we can safely check parameters[alen] - if ( - getattr(parameters[alen], '__default__', NoDefault) - is not NoDefault - ): - return - - num_default_tv = sum(getattr(p, '__default__', NoDefault) - is not NoDefault for p in parameters) - - elen -= num_default_tv - - expect_val = f"at least {elen}" - - # Breakpoint: https://github.com/python/cpython/pull/27515 - things = "arguments" if sys.version_info >= (3, 10) else "parameters" - raise TypeError(f"Too {'many' if alen > elen else 'few'} {things}" - f" for {cls}; actual {alen}, expected {expect_val}") -else: - # Python 3.11+ - - def _check_generic(cls, parameters, elen): - """Check correct count for parameters of a generic cls (internal helper). - - This gives a nice error message in case of count mismatch. - """ - if not elen: - raise TypeError(f"{cls} is not a generic class") - alen = len(parameters) - if alen != elen: - expect_val = elen - if hasattr(cls, "__parameters__"): - parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] - - # deal with TypeVarLike defaults - # required TypeVarLikes cannot appear after a defaulted one. - if alen < elen: - # since we validate TypeVarLike default in _collect_type_vars - # or _collect_parameters we can safely check parameters[alen] - if ( - getattr(parameters[alen], '__default__', NoDefault) - is not NoDefault - ): - return - - num_default_tv = sum(getattr(p, '__default__', NoDefault) - is not NoDefault for p in parameters) - - elen -= num_default_tv - - expect_val = f"at least {elen}" - - raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments" - f" for {cls}; actual {alen}, expected {expect_val}") - -if not _PEP_696_IMPLEMENTED: - typing._check_generic = _check_generic - - -def _has_generic_or_protocol_as_origin() -> bool: - try: - frame = sys._getframe(2) - # - Catch AttributeError: not all Python implementations have sys._getframe() - # - Catch ValueError: maybe we're called from an unexpected module - # and the call stack isn't deep enough - except (AttributeError, ValueError): - return False # err on the side of leniency - else: - # If we somehow get invoked from outside typing.py, - # also err on the side of leniency - if frame.f_globals.get("__name__") != "typing": - return False - origin = frame.f_locals.get("origin") - # Cannot use "in" because origin may be an object with a buggy __eq__ that - # throws an error. - return origin is typing.Generic or origin is Protocol or origin is typing.Protocol - - -_TYPEVARTUPLE_TYPES = {TypeVarTuple, getattr(typing, "TypeVarTuple", None)} - - -def _is_unpacked_typevartuple(x) -> bool: - if get_origin(x) is not Unpack: - return False - args = get_args(x) - return ( - bool(args) - and len(args) == 1 - and type(args[0]) in _TYPEVARTUPLE_TYPES - ) - - -# Python 3.11+ _collect_type_vars was renamed to _collect_parameters -if hasattr(typing, '_collect_type_vars'): - def _collect_type_vars(types, typevar_types=None): - """Collect all type variable contained in types in order of - first appearance (lexicographic order). For example:: - - _collect_type_vars((T, List[S, T])) == (T, S) - """ - if typevar_types is None: - typevar_types = typing.TypeVar - tvars = [] - - # A required TypeVarLike cannot appear after a TypeVarLike with a default - # if it was a direct call to `Generic[]` or `Protocol[]` - enforce_default_ordering = _has_generic_or_protocol_as_origin() - default_encountered = False - - # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple - type_var_tuple_encountered = False - - for t in types: - if _is_unpacked_typevartuple(t): - type_var_tuple_encountered = True - elif ( - isinstance(t, typevar_types) and not isinstance(t, _UnpackAlias) - and t not in tvars - ): - if enforce_default_ordering: - has_default = getattr(t, '__default__', NoDefault) is not NoDefault - if has_default: - if type_var_tuple_encountered: - raise TypeError('Type parameter with a default' - ' follows TypeVarTuple') - default_encountered = True - elif default_encountered: - raise TypeError(f'Type parameter {t!r} without a default' - ' follows type parameter with a default') - - tvars.append(t) - if _should_collect_from_parameters(t): - tvars.extend([t for t in t.__parameters__ if t not in tvars]) - elif isinstance(t, tuple): - # Collect nested type_vars - # tuple wrapped by _prepare_paramspec_params(cls, params) - for x in t: - for collected in _collect_type_vars([x]): - if collected not in tvars: - tvars.append(collected) - return tuple(tvars) - - typing._collect_type_vars = _collect_type_vars -else: - def _collect_parameters(args): - """Collect all type variables and parameter specifications in args - in order of first appearance (lexicographic order). - - For example:: - - assert _collect_parameters((T, Callable[P, T])) == (T, P) - """ - parameters = [] - - # A required TypeVarLike cannot appear after a TypeVarLike with default - # if it was a direct call to `Generic[]` or `Protocol[]` - enforce_default_ordering = _has_generic_or_protocol_as_origin() - default_encountered = False - - # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple - type_var_tuple_encountered = False - - for t in args: - if isinstance(t, type): - # We don't want __parameters__ descriptor of a bare Python class. - pass - elif isinstance(t, tuple): - # `t` might be a tuple, when `ParamSpec` is substituted with - # `[T, int]`, or `[int, *Ts]`, etc. - for x in t: - for collected in _collect_parameters([x]): - if collected not in parameters: - parameters.append(collected) - elif hasattr(t, '__typing_subst__'): - if t not in parameters: - if enforce_default_ordering: - has_default = ( - getattr(t, '__default__', NoDefault) is not NoDefault - ) - - if type_var_tuple_encountered and has_default: - raise TypeError('Type parameter with a default' - ' follows TypeVarTuple') - - if has_default: - default_encountered = True - elif default_encountered: - raise TypeError(f'Type parameter {t!r} without a default' - ' follows type parameter with a default') - - parameters.append(t) - else: - if _is_unpacked_typevartuple(t): - type_var_tuple_encountered = True - for x in getattr(t, '__parameters__', ()): - if x not in parameters: - parameters.append(x) - - return tuple(parameters) - - if not _PEP_696_IMPLEMENTED: - typing._collect_parameters = _collect_parameters - -# Backport typing.NamedTuple as it exists in Python 3.13. -# In 3.11, the ability to define generic `NamedTuple`s was supported. -# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. -# On 3.12, we added __orig_bases__ to call-based NamedTuples -# On 3.13, we deprecated kwargs-based NamedTuples -# Breakpoint: https://github.com/python/cpython/pull/105609 -if sys.version_info >= (3, 13): - NamedTuple = typing.NamedTuple -else: - def _make_nmtuple(name, types, module, defaults=()): - fields = [n for n, t in types] - annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") - for n, t in types} - nm_tpl = collections.namedtuple(name, fields, - defaults=defaults, module=module) - nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations - return nm_tpl - - _prohibited_namedtuple_fields = typing._prohibited - _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) - - class _NamedTupleMeta(type): - def __new__(cls, typename, bases, ns): - assert _NamedTuple in bases - for base in bases: - if base is not _NamedTuple and base is not typing.Generic: - raise TypeError( - 'can only inherit from a NamedTuple type and Generic') - bases = tuple(tuple if base is _NamedTuple else base for base in bases) - if "__annotations__" in ns: - types = ns["__annotations__"] - elif "__annotate__" in ns: - # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated - types = ns["__annotate__"](1) - else: - types = {} - default_names = [] - for field_name in types: - if field_name in ns: - default_names.append(field_name) - elif default_names: - raise TypeError(f"Non-default namedtuple field {field_name} " - f"cannot follow default field" - f"{'s' if len(default_names) > 1 else ''} " - f"{', '.join(default_names)}") - nm_tpl = _make_nmtuple( - typename, types.items(), - defaults=[ns[n] for n in default_names], - module=ns['__module__'] - ) - nm_tpl.__bases__ = bases - if typing.Generic in bases: - if hasattr(typing, '_generic_class_getitem'): # 3.12+ - nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem) - else: - class_getitem = typing.Generic.__class_getitem__.__func__ - nm_tpl.__class_getitem__ = classmethod(class_getitem) - # update from user namespace without overriding special namedtuple attributes - for key, val in ns.items(): - if key in _prohibited_namedtuple_fields: - raise AttributeError("Cannot overwrite NamedTuple attribute " + key) - elif key not in _special_namedtuple_fields: - if key not in nm_tpl._fields: - setattr(nm_tpl, key, ns[key]) - try: - set_name = type(val).__set_name__ - except AttributeError: - pass - else: - try: - set_name(val, nm_tpl, key) - except BaseException as e: - msg = ( - f"Error calling __set_name__ on {type(val).__name__!r} " - f"instance {key!r} in {typename!r}" - ) - # BaseException.add_note() existed on py311, - # but the __set_name__ machinery didn't start - # using add_note() until py312. - # Making sure exceptions are raised in the same way - # as in "normal" classes seems most important here. - # Breakpoint: https://github.com/python/cpython/pull/95915 - if sys.version_info >= (3, 12): - e.add_note(msg) - raise - else: - raise RuntimeError(msg) from e - - if typing.Generic in bases: - nm_tpl.__init_subclass__() - return nm_tpl - - _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) - - def _namedtuple_mro_entries(bases): - assert NamedTuple in bases - return (_NamedTuple,) - - def NamedTuple(typename, fields=_marker, /, **kwargs): - """Typed version of namedtuple. - - Usage:: - - class Employee(NamedTuple): - name: str - id: int - - This is equivalent to:: - - Employee = collections.namedtuple('Employee', ['name', 'id']) - - The resulting class has an extra __annotations__ attribute, giving a - dict that maps field names to types. (The field names are also in - the _fields attribute, which is part of the namedtuple API.) - An alternative equivalent functional syntax is also accepted:: - - Employee = NamedTuple('Employee', [('name', str), ('id', int)]) - """ - if fields is _marker: - if kwargs: - deprecated_thing = "Creating NamedTuple classes using keyword arguments" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "Use the class-based or functional syntax instead." - ) - else: - deprecated_thing = "Failing to pass a value for the 'fields' parameter" - example = f"`{typename} = NamedTuple({typename!r}, [])`" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "To create a NamedTuple class with 0 fields " - "using the functional syntax, " - "pass an empty list, e.g. " - ) + example + "." - elif fields is None: - if kwargs: - raise TypeError( - "Cannot pass `None` as the 'fields' parameter " - "and also specify fields using keyword arguments" - ) - else: - deprecated_thing = "Passing `None` as the 'fields' parameter" - example = f"`{typename} = NamedTuple({typename!r}, [])`" - deprecation_msg = ( - "{name} is deprecated and will be disallowed in Python {remove}. " - "To create a NamedTuple class with 0 fields " - "using the functional syntax, " - "pass an empty list, e.g. " - ) + example + "." - elif kwargs: - raise TypeError("Either list of fields or keywords" - " can be provided to NamedTuple, not both") - if fields is _marker or fields is None: - warnings.warn( - deprecation_msg.format(name=deprecated_thing, remove="3.15"), - DeprecationWarning, - stacklevel=2, - ) - fields = kwargs.items() - nt = _make_nmtuple(typename, fields, module=_caller()) - nt.__orig_bases__ = (NamedTuple,) - return nt - - NamedTuple.__mro_entries__ = _namedtuple_mro_entries - - -if hasattr(collections.abc, "Buffer"): - Buffer = collections.abc.Buffer -else: - class Buffer(abc.ABC): # noqa: B024 - """Base class for classes that implement the buffer protocol. - - The buffer protocol allows Python objects to expose a low-level - memory buffer interface. Before Python 3.12, it is not possible - to implement the buffer protocol in pure Python code, or even - to check whether a class implements the buffer protocol. In - Python 3.12 and higher, the ``__buffer__`` method allows access - to the buffer protocol from Python code, and the - ``collections.abc.Buffer`` ABC allows checking whether a class - implements the buffer protocol. - - To indicate support for the buffer protocol in earlier versions, - inherit from this ABC, either in a stub file or at runtime, - or use ABC registration. This ABC provides no methods, because - there is no Python-accessible methods shared by pre-3.12 buffer - classes. It is useful primarily for static checks. - - """ - - # As a courtesy, register the most common stdlib buffer classes. - Buffer.register(memoryview) - Buffer.register(bytearray) - Buffer.register(bytes) - - -# Backport of types.get_original_bases, available on 3.12+ in CPython -if hasattr(_types, "get_original_bases"): - get_original_bases = _types.get_original_bases -else: - def get_original_bases(cls, /): - """Return the class's "original" bases prior to modification by `__mro_entries__`. - - Examples:: - - from typing import TypeVar, Generic - from typing_extensions import NamedTuple, TypedDict - - T = TypeVar("T") - class Foo(Generic[T]): ... - class Bar(Foo[int], float): ... - class Baz(list[str]): ... - Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) - Spam = TypedDict("Spam", {"a": int, "b": str}) - - assert get_original_bases(Bar) == (Foo[int], float) - assert get_original_bases(Baz) == (list[str],) - assert get_original_bases(Eggs) == (NamedTuple,) - assert get_original_bases(Spam) == (TypedDict,) - assert get_original_bases(int) == (object,) - """ - try: - return cls.__dict__.get("__orig_bases__", cls.__bases__) - except AttributeError: - raise TypeError( - f'Expected an instance of type, not {type(cls).__name__!r}' - ) from None - - -# NewType is a class on Python 3.10+, making it pickleable -# The error message for subclassing instances of NewType was improved on 3.11+ -# Breakpoint: https://github.com/python/cpython/pull/30268 -if sys.version_info >= (3, 11): - NewType = typing.NewType -else: - class NewType: - """NewType creates simple unique types with almost zero - runtime overhead. NewType(name, tp) is considered a subtype of tp - by static type checkers. At runtime, NewType(name, tp) returns - a dummy callable that simply returns its argument. Usage:: - UserId = NewType('UserId', int) - def name_by_id(user_id: UserId) -> str: - ... - UserId('user') # Fails type check - name_by_id(42) # Fails type check - name_by_id(UserId(42)) # OK - num = UserId(5) + 1 # type: int - """ - - def __call__(self, obj, /): - return obj - - def __init__(self, name, tp): - self.__qualname__ = name - if '.' in name: - name = name.rpartition('.')[-1] - self.__name__ = name - self.__supertype__ = tp - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __mro_entries__(self, bases): - # We defined __mro_entries__ to get a better error message - # if a user attempts to subclass a NewType instance. bpo-46170 - supercls_name = self.__name__ - - class Dummy: - def __init_subclass__(cls): - subcls_name = cls.__name__ - raise TypeError( - f"Cannot subclass an instance of NewType. " - f"Perhaps you were looking for: " - f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`" - ) - - return (Dummy,) - - def __repr__(self): - return f'{self.__module__}.{self.__qualname__}' - - def __reduce__(self): - return self.__qualname__ - - # Breakpoint: https://github.com/python/cpython/pull/21515 - if sys.version_info >= (3, 10): - # PEP 604 methods - # It doesn't make sense to have these methods on Python <3.10 - - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - -# Breakpoint: https://github.com/python/cpython/pull/149172 -if sys.version_info >= (3, 15): - TypeAliasType = typing.TypeAliasType -# <=3.14 -else: - # Breakpoint: https://github.com/python/cpython/pull/103764 - if sys.version_info >= (3, 12): - # 3.12-3.14 - def _is_unionable(obj): - """Corresponds to is_unionable() in unionobject.c in CPython.""" - return obj is None or isinstance(obj, ( - type, - _types.GenericAlias, - _types.UnionType, - typing.TypeAliasType, - TypeAliasType, - )) - else: - # <=3.11 - def _is_unionable(obj): - """Corresponds to is_unionable() in unionobject.c in CPython.""" - return obj is None or isinstance(obj, ( - type, - _types.GenericAlias, - _types.UnionType, - TypeAliasType, - )) - - if sys.version_info < (3, 10): - # Copied and pasted from https://github.com/python/cpython/blob/986a4e1b6fcae7fe7a1d0a26aea446107dd58dd2/Objects/genericaliasobject.c#L568-L582, - # so that we emulate the behaviour of `types.GenericAlias` - # on the latest versions of CPython - _ATTRIBUTE_DELEGATION_EXCLUSIONS = frozenset({ - "__class__", - "__bases__", - "__origin__", - "__args__", - "__unpacked__", - "__parameters__", - "__typing_unpacked_tuple_args__", - "__mro_entries__", - "__reduce_ex__", - "__reduce__", - "__copy__", - "__deepcopy__", - }) - - class _TypeAliasGenericAlias(typing._GenericAlias, _root=True): - def __getattr__(self, attr): - if attr in _ATTRIBUTE_DELEGATION_EXCLUSIONS: - return object.__getattr__(self, attr) - return getattr(self.__origin__, attr) - - - class TypeAliasType: - """Create named, parameterized type aliases. - - This provides a backport of the new `type` statement in Python 3.12: - - type ListOrSet[T] = list[T] | set[T] - - is equivalent to: - - T = TypeVar("T") - ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,)) - - The name ListOrSet can then be used as an alias for the type it refers to. - - The type_params argument should contain all the type parameters used - in the value of the type alias. If the alias is not generic, this - argument is omitted. - - Static type checkers should only support type aliases declared using - TypeAliasType that follow these rules: - - - The first argument (the name) must be a string literal. - - The TypeAliasType instance must be immediately assigned to a variable - of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid, - as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)'). - - """ - - def __init__(self, name: str, value, *, type_params=()): - if not isinstance(name, str): - raise TypeError("TypeAliasType name must be a string") - if not isinstance(type_params, tuple): - raise TypeError("type_params must be a tuple") - self.__value__ = value - self.__type_params__ = type_params - - default_value_encountered = False - parameters = [] - for type_param in type_params: - if ( - not isinstance(type_param, (TypeVar, TypeVarTuple, ParamSpec)) - # <=3.11 - # Unpack Backport passes isinstance(type_param, TypeVar) - or _is_unpack(type_param) - ): - raise TypeError(f"Expected a type param, got {type_param!r}") - has_default = ( - getattr(type_param, '__default__', NoDefault) is not NoDefault - ) - if default_value_encountered and not has_default: - raise TypeError(f"non-default type parameter '{type_param!r}'" - " follows default type parameter") - if has_default: - default_value_encountered = True - if isinstance(type_param, TypeVarTuple): - parameters.extend(type_param) - else: - parameters.append(type_param) - self.__parameters__ = tuple(parameters) - def_mod = _caller() - if def_mod != 'typing_extensions': - self.__module__ = def_mod - # Setting this attribute closes the TypeAliasType from further modification - self.__name__ = name - - def __setattr__(self, name: str, value: object, /) -> None: - if hasattr(self, "__name__") and name != "__module__": - self._raise_attribute_error(name) - super().__setattr__(name, value) - - def __delattr__(self, name: str, /) -> Never: - self._raise_attribute_error(name) - - def _raise_attribute_error(self, name: str) -> Never: - # Match the Python 3.12 error messages exactly - if name == "__name__": - raise AttributeError("readonly attribute") - elif name in {"__value__", "__type_params__", "__parameters__"}: - raise AttributeError( - f"attribute '{name}' of 'typing.TypeAliasType' objects " - "is not writable" - ) - else: - raise AttributeError( - f"'typing.TypeAliasType' object has no attribute '{name}'" - ) - - def __repr__(self) -> str: - return self.__name__ - - if sys.version_info < (3, 11): - def _check_single_param(self, param, recursion=0): - # Allow [], [int], [int, str], [int, ...], [int, T] - if param is ...: - return ... - if param is None: - return None - # Note in <= 3.9 _ConcatenateGenericAlias inherits from list - if isinstance(param, list) and recursion == 0: - return [self._check_single_param(arg, recursion+1) - for arg in param] - return typing._type_check( - param, f'Subscripting {self.__name__} requires a type.' - ) - - def _check_parameters(self, parameters): - if sys.version_info < (3, 11): - return tuple( - self._check_single_param(item) - for item in parameters - ) - return tuple(typing._type_check( - item, f'Subscripting {self.__name__} requires a type.' - ) - for item in parameters - ) - - def __getitem__(self, parameters): - if not self.__type_params__: - raise TypeError("Only generic type aliases are subscriptable") - if not isinstance(parameters, tuple): - parameters = (parameters,) - # Using 3.9 here will create problems with Concatenate - if sys.version_info >= (3, 10): - return _types.GenericAlias(self, parameters) - type_vars = _collect_type_vars(parameters) - parameters = self._check_parameters(parameters) - alias = _TypeAliasGenericAlias(self, parameters) - # alias.__parameters__ is not complete if Concatenate is present - # as it is converted to a list from which no parameters are extracted. - if alias.__parameters__ != type_vars: - alias.__parameters__ = type_vars - return alias - - def __reduce__(self): - return self.__name__ - - def __init_subclass__(cls, *args, **kwargs): - raise TypeError( - "type 'typing_extensions.TypeAliasType' is not an acceptable base type" - ) - - # The presence of this method convinces typing._type_check - # that TypeAliasTypes are types. - def __call__(self): - raise TypeError("Type alias is not callable") - - # Breakpoint: https://github.com/python/cpython/pull/21515 - if sys.version_info >= (3, 10): - def __or__(self, right): - # For forward compatibility with 3.12, reject Unions - # that are not accepted by the built-in Union. - if not _is_unionable(right): - return NotImplemented - return typing.Union[self, right] - - def __ror__(self, left): - if not _is_unionable(left): - return NotImplemented - return typing.Union[left, self] - - -if hasattr(typing, "is_protocol"): - is_protocol = typing.is_protocol - get_protocol_members = typing.get_protocol_members -else: - def is_protocol(tp: type, /) -> bool: - """Return True if the given type is a Protocol. - - Example:: - - >>> from typing_extensions import Protocol, is_protocol - >>> class P(Protocol): - ... def a(self) -> str: ... - ... b: int - >>> is_protocol(P) - True - >>> is_protocol(int) - False - """ - return ( - isinstance(tp, type) - and getattr(tp, '_is_protocol', False) - and tp is not Protocol - and tp is not typing.Protocol - ) - - def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]: - """Return the set of members defined in a Protocol. - - Example:: - - >>> from typing_extensions import Protocol, get_protocol_members - >>> class P(Protocol): - ... def a(self) -> str: ... - ... b: int - >>> get_protocol_members(P) == frozenset({'a', 'b'}) - True - - Raise a TypeError for arguments that are not Protocols. - """ - if not is_protocol(tp): - raise TypeError(f'{tp!r} is not a Protocol') - if hasattr(tp, '__protocol_attrs__'): - return frozenset(tp.__protocol_attrs__) - return frozenset(_get_protocol_attrs(tp)) - - -if hasattr(typing, "Doc"): - Doc = typing.Doc -else: - class Doc: - """Define the documentation of a type annotation using ``Annotated``, to be - used in class attributes, function and method parameters, return values, - and variables. - - The value should be a positional-only string literal to allow static tools - like editors and documentation generators to use it. - - This complements docstrings. - - The string value passed is available in the attribute ``documentation``. - - Example:: - - >>> from typing_extensions import Annotated, Doc - >>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ... - """ - def __init__(self, documentation: str, /) -> None: - self.documentation = documentation - - def __repr__(self) -> str: - return f"Doc({self.documentation!r})" - - def __hash__(self) -> int: - return hash(self.documentation) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Doc): - return NotImplemented - return self.documentation == other.documentation - - -_CapsuleType = getattr(_types, "CapsuleType", None) - -if _CapsuleType is None: - try: - import _socket - except ImportError: - pass - else: - _CAPI = getattr(_socket, "CAPI", None) - if _CAPI is not None: - _CapsuleType = type(_CAPI) - -if _CapsuleType is not None: - CapsuleType = _CapsuleType - __all__.append("CapsuleType") - - -if sys.version_info >= (3, 14): - from annotationlib import Format, get_annotations -else: - # Available since Python 3.14.0a3 - # PR: https://github.com/python/cpython/pull/124415 - class Format(enum.IntEnum): - VALUE = 1 - VALUE_WITH_FAKE_GLOBALS = 2 - FORWARDREF = 3 - STRING = 4 - - # Available since Python 3.14.0a1 - # PR: https://github.com/python/cpython/pull/119891 - def get_annotations(obj, *, globals=None, locals=None, eval_str=False, - format=Format.VALUE): - """Compute the annotations dict for an object. - - obj may be a callable, class, or module. - Passing in an object of any other type raises TypeError. - - Returns a dict. get_annotations() returns a new dict every time - it's called; calling it twice on the same object will return two - different but equivalent dicts. - - This is a backport of `inspect.get_annotations`, which has been - in the standard library since Python 3.10. See the standard library - documentation for more: - - https://docs.python.org/3/library/inspect.html#inspect.get_annotations - - This backport adds the *format* argument introduced by PEP 649. The - three formats supported are: - * VALUE: the annotations are returned as-is. This is the default and - it is compatible with the behavior on previous Python versions. - * FORWARDREF: return annotations as-is if possible, but replace any - undefined names with ForwardRef objects. The implementation proposed by - PEP 649 relies on language changes that cannot be backported; the - typing-extensions implementation simply returns the same result as VALUE. - * STRING: return annotations as strings, in a format close to the original - source. Again, this behavior cannot be replicated directly in a backport. - As an approximation, typing-extensions retrieves the annotations under - VALUE semantics and then stringifies them. - - The purpose of this backport is to allow users who would like to use - FORWARDREF or STRING semantics once PEP 649 is implemented, but who also - want to support earlier Python versions, to simply write: - - typing_extensions.get_annotations(obj, format=Format.FORWARDREF) - - """ - format = Format(format) - if format is Format.VALUE_WITH_FAKE_GLOBALS: - raise ValueError( - "The VALUE_WITH_FAKE_GLOBALS format is for internal use only" - ) - - if eval_str and format is not Format.VALUE: - raise ValueError("eval_str=True is only supported with format=Format.VALUE") - - if isinstance(obj, type): - # class - obj_dict = getattr(obj, '__dict__', None) - if obj_dict and hasattr(obj_dict, 'get'): - ann = obj_dict.get('__annotations__', None) - if isinstance(ann, _types.GetSetDescriptorType): - ann = None - else: - ann = None - - obj_globals = None - module_name = getattr(obj, '__module__', None) - if module_name: - module = sys.modules.get(module_name, None) - if module: - obj_globals = getattr(module, '__dict__', None) - obj_locals = dict(vars(obj)) - unwrap = obj - elif isinstance(obj, _types.ModuleType): - # module - ann = getattr(obj, '__annotations__', None) - obj_globals = obj.__dict__ - obj_locals = None - unwrap = None - elif callable(obj): - # this includes types.Function, types.BuiltinFunctionType, - # types.BuiltinMethodType, functools.partial, functools.singledispatch, - # "class funclike" from Lib/test/test_inspect... on and on it goes. - ann = getattr(obj, '__annotations__', None) - obj_globals = getattr(obj, '__globals__', None) - obj_locals = None - unwrap = obj - elif hasattr(obj, '__annotations__'): - ann = obj.__annotations__ - obj_globals = obj_locals = unwrap = None - else: - raise TypeError(f"{obj!r} is not a module, class, or callable.") - - if ann is None: - return {} - - if not isinstance(ann, dict): - raise ValueError(f"{obj!r}.__annotations__ is neither a dict nor None") - - if not ann: - return {} - - if not eval_str: - if format is Format.STRING: - return { - key: value if isinstance(value, str) else typing._type_repr(value) - for key, value in ann.items() - } - return dict(ann) - - if unwrap is not None: - while True: - if hasattr(unwrap, '__wrapped__'): - unwrap = unwrap.__wrapped__ - continue - if isinstance(unwrap, functools.partial): - unwrap = unwrap.func - continue - break - if hasattr(unwrap, "__globals__"): - obj_globals = unwrap.__globals__ - - if globals is None: - globals = obj_globals - if locals is None: - locals = obj_locals or {} - - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - if type_params := getattr(obj, "__type_params__", ()): - locals = {param.__name__: param for param in type_params} | locals - - return_value = {key: - value if not isinstance(value, str) else eval(value, globals, locals) - for key, value in ann.items() } - return return_value - - -if hasattr(typing, "evaluate_forward_ref"): - evaluate_forward_ref = typing.evaluate_forward_ref -else: - # Implements annotationlib.ForwardRef.evaluate - def _eval_with_owner( - forward_ref, *, owner=None, globals=None, locals=None, type_params=None - ): - if forward_ref.__forward_evaluated__: - return forward_ref.__forward_value__ - if getattr(forward_ref, "__cell__", None) is not None: - try: - value = forward_ref.__cell__.cell_contents - except ValueError: - pass - else: - forward_ref.__forward_evaluated__ = True - forward_ref.__forward_value__ = value - return value - if owner is None: - owner = getattr(forward_ref, "__owner__", None) - - if ( - globals is None - and getattr(forward_ref, "__forward_module__", None) is not None - ): - globals = getattr( - sys.modules.get(forward_ref.__forward_module__, None), "__dict__", None - ) - if globals is None: - globals = getattr(forward_ref, "__globals__", None) - if globals is None: - if isinstance(owner, type): - module_name = getattr(owner, "__module__", None) - if module_name: - module = sys.modules.get(module_name, None) - if module: - globals = getattr(module, "__dict__", None) - elif isinstance(owner, _types.ModuleType): - globals = getattr(owner, "__dict__", None) - elif callable(owner): - globals = getattr(owner, "__globals__", None) - - # If we pass None to eval() below, the globals of this module are used. - if globals is None: - globals = {} - - if locals is None: - locals = {} - if isinstance(owner, type): - locals.update(vars(owner)) - - if type_params is None and owner is not None: - # "Inject" type parameters into the local namespace - # (unless they are shadowed by assignments *in* the local namespace), - # as a way of emulating annotation scopes when calling `eval()` - type_params = getattr(owner, "__type_params__", None) - - # Type parameters exist in their own scope, which is logically - # between the locals and the globals. We simulate this by adding - # them to the globals. - if type_params is not None: - globals = dict(globals) - for param in type_params: - globals[param.__name__] = param - - arg = forward_ref.__forward_arg__ - if arg.isidentifier() and not keyword.iskeyword(arg): - if arg in locals: - value = locals[arg] - elif arg in globals: - value = globals[arg] - elif hasattr(builtins, arg): - return getattr(builtins, arg) - else: - raise NameError(arg) - else: - code = forward_ref.__forward_code__ - value = eval(code, globals, locals) - forward_ref.__forward_evaluated__ = True - forward_ref.__forward_value__ = value - return value - - def evaluate_forward_ref( - forward_ref, - *, - owner=None, - globals=None, - locals=None, - type_params=None, - format=None, - _recursive_guard=frozenset(), - ): - """Evaluate a forward reference as a type hint. - - This is similar to calling the ForwardRef.evaluate() method, - but unlike that method, evaluate_forward_ref() also: - - * Recursively evaluates forward references nested within the type hint. - * Rejects certain objects that are not valid type hints. - * Replaces type hints that evaluate to None with types.NoneType. - * Supports the *FORWARDREF* and *STRING* formats. - - *forward_ref* must be an instance of ForwardRef. *owner*, if given, - should be the object that holds the annotations that the forward reference - derived from, such as a module, class object, or function. It is used to - infer the namespaces to use for looking up names. *globals* and *locals* - can also be explicitly given to provide the global and local namespaces. - *type_params* is a tuple of type parameters that are in scope when - evaluating the forward reference. This parameter must be provided (though - it may be an empty tuple) if *owner* is not given and the forward reference - does not already have an owner set. *format* specifies the format of the - annotation and is a member of the annotationlib.Format enum. - - """ - if format == Format.STRING: - return forward_ref.__forward_arg__ - if forward_ref.__forward_arg__ in _recursive_guard: - return forward_ref - - # Evaluate the forward reference - try: - value = _eval_with_owner( - forward_ref, - owner=owner, - globals=globals, - locals=locals, - type_params=type_params, - ) - except NameError: - if format == Format.FORWARDREF: - return forward_ref - else: - raise - - if isinstance(value, str): - value = ForwardRef(value) - - # Recursively evaluate the type - if isinstance(value, ForwardRef): - if getattr(value, "__forward_module__", True) is not None: - globals = None - return evaluate_forward_ref( - value, - globals=globals, - locals=locals, - type_params=type_params, owner=owner, - _recursive_guard=_recursive_guard, format=format - ) - if sys.version_info < (3, 12, 5) and type_params: - # Make use of type_params - locals = dict(locals) if locals else {} - for tvar in type_params: - if tvar.__name__ not in locals: # lets not overwrite something present - locals[tvar.__name__] = tvar - if sys.version_info < (3, 12, 5): - return typing._eval_type( - value, - globals, - locals, - recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, - ) - else: - return typing._eval_type( - value, - globals, - locals, - type_params, - recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, - ) - - -if sys.version_info >= (3, 14, 0, "beta"): - type_repr = annotationlib.type_repr -else: - def type_repr(value): - """Convert a Python value to a format suitable for use with the STRING format. - - This is intended as a helper for tools that support the STRING format but do - not have access to the code that originally produced the annotations. It uses - repr() for most objects. - - """ - if isinstance(value, (type, _types.FunctionType, _types.BuiltinFunctionType)): - if value.__module__ == "builtins": - return value.__qualname__ - return f"{value.__module__}.{value.__qualname__}" - if value is ...: - return "..." - return repr(value) - - -# Aliases for items that are in typing in all supported versions. -# We use hasattr() checks so this library will continue to import on -# future versions of Python that may remove these names. -_typing_names = [ - "AbstractSet", - "AnyStr", - "BinaryIO", - "Callable", - "Collection", - "Container", - "Dict", - "FrozenSet", - "Hashable", - "IO", - "ItemsView", - "Iterable", - "Iterator", - "KeysView", - "List", - "Mapping", - "MappingView", - "Match", - "MutableMapping", - "MutableSequence", - "MutableSet", - "Optional", - "Pattern", - "Reversible", - "Sequence", - "Set", - "Sized", - "TextIO", - "Tuple", - "Union", - "ValuesView", - "cast", - "no_type_check", - # This is private, but it was defined by typing_extensions for a long time - # and some users rely on it. - "_AnnotatedAlias", -] - -# Breakpoint: https://github.com/python/cpython/pull/133602 -if sys.version_info < (3, 15, 0): - _typing_names.append("no_type_check_decorator") - __all__.append("no_type_check_decorator") - -globals().update( - {name: getattr(typing, name) for name in _typing_names if hasattr(typing, name)} -) -# These are defined unconditionally because they are used in -# typing-extensions itself. -Generic = typing.Generic -ForwardRef = typing.ForwardRef -Annotated = typing.Annotated diff --git a/venv/pyvenv.cfg b/venv/pyvenv.cfg old mode 100755 new mode 100644 index b76f367..83d072d --- a/venv/pyvenv.cfg +++ b/venv/pyvenv.cfg @@ -1,5 +1,5 @@ home = /usr/bin include-system-site-packages = false -version = 3.11.2 -executable = /usr/bin/python3.11 -command = /usr/bin/python3 -m venv /home/marco/Jogo3/app/venv +version = 3.14.4 +executable = /usr/bin/python3.14 +command = /usr/bin/python3 -m venv /home/apps/apps/Jogo3/app/venv