From 66449003d3671834385b281294f0c9a77c642fc8 Mon Sep 17 00:00:00 2001 From: Marco Costa Date: Fri, 18 Sep 2026 21:33:05 -0300 Subject: [PATCH] hgfhgfhgfhjh --- .../__pycache__/__init__.cpython-311.pyc | Bin 567 -> 0 bytes .../__pycache__/_manylinux.cpython-311.pyc | Bin 13233 -> 0 bytes .../__pycache__/_musllinux.cpython-311.pyc | Bin 8001 -> 0 bytes .../__pycache__/_structures.cpython-311.pyc | Bin 3689 -> 0 bytes .../__pycache__/markers.cpython-311.pyc | Bin 16535 -> 0 bytes .../__pycache__/requirements.cpython-311.pyc | Bin 7650 -> 0 bytes .../__pycache__/specifiers.cpython-311.pyc | Bin 34367 -> 0 bytes .../__pycache__/tags.cpython-311.pyc | Bin 21352 -> 0 bytes .../__pycache__/utils.cpython-311.pyc | Bin 6687 -> 0 bytes .../__pycache__/version.cpython-311.pyc | Bin 21879 -> 0 bytes .../_vendor/packaging/_manylinux.py | 301 - .../_vendor/packaging/_musllinux.py | 136 - .../_vendor/packaging/_structures.py | 61 - .../setuptools/_vendor/packaging/markers.py | 304 - .../_vendor/packaging/requirements.py | 146 - .../_vendor/packaging/specifiers.py | 802 -- .../setuptools/_vendor/packaging/tags.py | 487 - .../setuptools/_vendor/packaging/utils.py | 136 - .../setuptools/_vendor/packaging/version.py | 504 - .../setuptools/_vendor/pyparsing/__init__.py | 331 - .../__pycache__/__init__.cpython-311.pyc | Bin 8340 -> 0 bytes .../__pycache__/actions.cpython-311.pyc | Bin 8466 -> 0 bytes .../__pycache__/common.cpython-311.pyc | Bin 14788 -> 0 bytes .../__pycache__/core.cpython-311.pyc | Bin 277640 -> 0 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 12930 -> 0 bytes .../__pycache__/helpers.cpython-311.pyc | Bin 53631 -> 0 bytes .../__pycache__/results.cpython-311.pyc | Bin 36314 -> 0 bytes .../__pycache__/testing.cpython-311.pyc | Bin 19510 -> 0 bytes .../__pycache__/unicode.cpython-311.pyc | Bin 15368 -> 0 bytes .../__pycache__/util.cpython-311.pyc | Bin 14267 -> 0 bytes .../setuptools/_vendor/pyparsing/actions.py | 207 - .../setuptools/_vendor/pyparsing/common.py | 424 - .../setuptools/_vendor/pyparsing/core.py | 5814 --------- .../_vendor/pyparsing/diagram/__init__.py | 642 - .../__pycache__/__init__.cpython-311.pyc | Bin 28003 -> 0 bytes .../_vendor/pyparsing/exceptions.py | 267 - .../setuptools/_vendor/pyparsing/helpers.py | 1088 -- .../setuptools/_vendor/pyparsing/results.py | 760 -- .../setuptools/_vendor/pyparsing/testing.py | 331 - .../setuptools/_vendor/pyparsing/unicode.py | 352 - .../setuptools/_vendor/pyparsing/util.py | 235 - .../setuptools/_vendor/tomli/__init__.py | 11 - .../__pycache__/__init__.cpython-311.pyc | Bin 417 -> 0 bytes .../tomli/__pycache__/_parser.cpython-311.pyc | Bin 30856 -> 0 bytes .../tomli/__pycache__/_re.cpython-311.pyc | Bin 4496 -> 0 bytes .../tomli/__pycache__/_types.cpython-311.pyc | Bin 409 -> 0 bytes .../setuptools/_vendor/tomli/_parser.py | 691 -- .../setuptools/_vendor/tomli/_re.py | 107 - .../setuptools/_vendor/tomli/_types.py | 10 - .../setuptools/_vendor/typing_extensions.py | 2296 ---- .../site-packages/setuptools/_vendor/zipp.py | 329 - .../site-packages/setuptools/archive_util.py | 213 - .../site-packages/setuptools/build_meta.py | 512 - .../site-packages/setuptools/cli-32.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/cli-64.exe | Bin 74752 -> 0 bytes .../site-packages/setuptools/cli-arm64.exe | Bin 137216 -> 0 bytes .../site-packages/setuptools/cli.exe | Bin 65536 -> 0 bytes .../setuptools/command/__init__.py | 12 - .../__pycache__/__init__.cpython-311.pyc | Bin 636 -> 0 bytes .../command/__pycache__/alias.cpython-311.pyc | Bin 3903 -> 0 bytes .../__pycache__/bdist_egg.cpython-311.pyc | Bin 25585 -> 0 bytes .../__pycache__/bdist_rpm.cpython-311.pyc | Bin 2191 -> 0 bytes .../command/__pycache__/build.cpython-311.pyc | Bin 6991 -> 0 bytes .../__pycache__/build_clib.cpython-311.pyc | Bin 4166 -> 0 bytes .../__pycache__/build_ext.cpython-311.pyc | Bin 22011 -> 0 bytes .../__pycache__/build_py.cpython-311.pyc | Bin 23177 -> 0 bytes .../__pycache__/develop.cpython-311.pyc | Bin 10919 -> 0 bytes .../__pycache__/dist_info.cpython-311.pyc | Bin 7981 -> 0 bytes .../__pycache__/easy_install.cpython-311.pyc | Bin 121501 -> 0 bytes .../editable_wheel.cpython-311.pyc | Bin 51414 -> 0 bytes .../__pycache__/egg_info.cpython-311.pyc | Bin 40839 -> 0 bytes .../__pycache__/install.cpython-311.pyc | Bin 6816 -> 0 bytes .../install_egg_info.cpython-311.pyc | Bin 5342 -> 0 bytes .../__pycache__/install_lib.cpython-311.pyc | Bin 8413 -> 0 bytes .../install_scripts.cpython-311.pyc | Bin 4280 -> 0 bytes .../__pycache__/py36compat.cpython-311.pyc | Bin 8037 -> 0 bytes .../__pycache__/register.cpython-311.pyc | Bin 1127 -> 0 bytes .../__pycache__/rotate.cpython-311.pyc | Bin 4187 -> 0 bytes .../__pycache__/saveopts.cpython-311.pyc | Bin 1367 -> 0 bytes .../command/__pycache__/sdist.cpython-311.pyc | Bin 13439 -> 0 bytes .../__pycache__/setopt.cpython-311.pyc | Bin 7679 -> 0 bytes .../command/__pycache__/test.cpython-311.pyc | Bin 14620 -> 0 bytes .../__pycache__/upload.cpython-311.pyc | Bin 1091 -> 0 bytes .../__pycache__/upload_docs.cpython-311.pyc | Bin 11942 -> 0 bytes .../site-packages/setuptools/command/alias.py | 78 - .../setuptools/command/bdist_egg.py | 457 - .../setuptools/command/bdist_rpm.py | 40 - .../site-packages/setuptools/command/build.py | 146 - .../setuptools/command/build_clib.py | 101 - .../setuptools/command/build_ext.py | 383 - .../setuptools/command/build_py.py | 368 - .../setuptools/command/develop.py | 193 - .../setuptools/command/dist_info.py | 142 - .../setuptools/command/easy_install.py | 2366 ---- .../setuptools/command/editable_wheel.py | 844 -- .../setuptools/command/egg_info.py | 775 -- .../setuptools/command/install.py | 139 - .../setuptools/command/install_egg_info.py | 83 - .../setuptools/command/install_lib.py | 148 - .../setuptools/command/install_scripts.py | 70 - .../setuptools/command/launcher manifest.xml | 15 - .../setuptools/command/py36compat.py | 134 - .../setuptools/command/register.py | 18 - .../setuptools/command/rotate.py | 64 - .../setuptools/command/saveopts.py | 22 - .../site-packages/setuptools/command/sdist.py | 210 - .../setuptools/command/setopt.py | 149 - .../site-packages/setuptools/command/test.py | 251 - .../setuptools/command/upload.py | 17 - .../setuptools/command/upload_docs.py | 212 - .../setuptools/config/__init__.py | 35 - .../__pycache__/__init__.cpython-311.pyc | Bin 2031 -> 0 bytes .../_apply_pyprojecttoml.cpython-311.pyc | Bin 22840 -> 0 bytes .../config/__pycache__/expand.cpython-311.pyc | Bin 28245 -> 0 bytes .../__pycache__/pyprojecttoml.cpython-311.pyc | Bin 27876 -> 0 bytes .../__pycache__/setupcfg.cpython-311.pyc | Bin 33285 -> 0 bytes .../setuptools/config/_apply_pyprojecttoml.py | 384 - .../config/_validate_pyproject/__init__.py | 34 - .../__pycache__/__init__.cpython-311.pyc | Bin 2319 -> 0 bytes .../error_reporting.cpython-311.pyc | Bin 20210 -> 0 bytes .../extra_validations.cpython-311.pyc | Bin 1868 -> 0 bytes .../fastjsonschema_exceptions.cpython-311.pyc | Bin 3243 -> 0 bytes ...fastjsonschema_validations.cpython-311.pyc | Bin 192641 -> 0 bytes .../__pycache__/formats.cpython-311.pyc | Bin 14358 -> 0 bytes .../_validate_pyproject/error_reporting.py | 318 - .../_validate_pyproject/extra_validations.py | 36 - .../fastjsonschema_exceptions.py | 51 - .../fastjsonschema_validations.py | 1035 -- .../config/_validate_pyproject/formats.py | 259 - .../site-packages/setuptools/config/expand.py | 462 - .../setuptools/config/pyprojecttoml.py | 498 - .../setuptools/config/setupcfg.py | 769 -- .../site-packages/setuptools/dep_util.py | 25 - .../site-packages/setuptools/depends.py | 176 - .../site-packages/setuptools/discovery.py | 601 - .../site-packages/setuptools/dist.py | 1218 -- .../site-packages/setuptools/errors.py | 58 - .../site-packages/setuptools/extension.py | 148 - .../setuptools/extern/__init__.py | 76 - .../__pycache__/__init__.cpython-311.pyc | Bin 4395 -> 0 bytes .../site-packages/setuptools/glob.py | 167 - .../site-packages/setuptools/gui-32.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/gui-64.exe | Bin 75264 -> 0 bytes .../site-packages/setuptools/gui-arm64.exe | Bin 137728 -> 0 bytes .../site-packages/setuptools/gui.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/installer.py | 104 - .../site-packages/setuptools/launch.py | 36 - .../site-packages/setuptools/logging.py | 37 - .../site-packages/setuptools/monkey.py | 165 - .../site-packages/setuptools/msvc.py | 1703 --- .../site-packages/setuptools/namespaces.py | 107 - .../site-packages/setuptools/package_index.py | 1181 -- .../site-packages/setuptools/py34compat.py | 13 - .../site-packages/setuptools/sandbox.py | 530 - .../setuptools/script (dev).tmpl | 6 - .../site-packages/setuptools/script.tmpl | 3 - .../site-packages/setuptools/unicode_utils.py | 42 - .../site-packages/setuptools/version.py | 6 - .../site-packages/setuptools/wheel.py | 222 - .../setuptools/windows_support.py | 29 - .../site-packages/telegram/__init__.py | 544 - .../site-packages/telegram/__main__.py | 54 - .../__pycache__/__init__.cpython-311.pyc | Bin 17060 -> 0 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 2004 -> 0 bytes .../__pycache__/_birthdate.cpython-311.pyc | Bin 3177 -> 0 bytes .../telegram/__pycache__/_bot.cpython-311.pyc | Bin 388732 -> 0 bytes .../__pycache__/_botcommand.cpython-311.pyc | Bin 3078 -> 0 bytes .../_botcommandscope.cpython-311.pyc | Bin 14363 -> 0 bytes .../_botdescription.cpython-311.pyc | Bin 2918 -> 0 bytes .../__pycache__/_botname.cpython-311.pyc | Bin 1897 -> 0 bytes .../__pycache__/_business.cpython-311.pyc | Bin 19628 -> 0 bytes .../_callbackquery.cpython-311.pyc | Bin 31345 -> 0 bytes .../__pycache__/_chat.cpython-311.pyc | Bin 118735 -> 0 bytes .../_chatadministratorrights.cpython-311.pyc | Bin 10850 -> 0 bytes .../_chatbackground.cpython-311.pyc | Bin 25026 -> 0 bytes .../__pycache__/_chatboost.cpython-311.pyc | Bin 22025 -> 0 bytes .../__pycache__/_chatfullinfo.cpython-311.pyc | Bin 25685 -> 0 bytes .../_chatinvitelink.cpython-311.pyc | Bin 7885 -> 0 bytes .../_chatjoinrequest.cpython-311.pyc | Bin 9373 -> 0 bytes .../__pycache__/_chatlocation.cpython-311.pyc | Bin 3630 -> 0 bytes .../__pycache__/_chatmember.cpython-311.pyc | Bin 29417 -> 0 bytes .../_chatmemberupdated.cpython-311.pyc | Bin 9738 -> 0 bytes .../_chatpermissions.cpython-311.pyc | Bin 10314 -> 0 bytes .../_choseninlineresult.cpython-311.pyc | Bin 4620 -> 0 bytes .../_copytextbutton.cpython-311.pyc | Bin 2148 -> 0 bytes .../__pycache__/_dice.cpython-311.pyc | Bin 6458 -> 0 bytes .../__pycache__/_forcereply.cpython-311.pyc | Bin 4370 -> 0 bytes .../__pycache__/_forumtopic.cpython-311.pyc | Bin 9005 -> 0 bytes .../__pycache__/_gifts.cpython-311.pyc | Bin 6292 -> 0 bytes .../__pycache__/_giveaway.cpython-311.pyc | Bin 18204 -> 0 bytes .../_keyboardbutton.cpython-311.pyc | Bin 9251 -> 0 bytes .../_keyboardbuttonpolltype.cpython-311.pyc | Bin 2648 -> 0 bytes .../_keyboardbuttonrequest.cpython-311.pyc | Bin 12646 -> 0 bytes .../_linkpreviewoptions.cpython-311.pyc | Bin 4238 -> 0 bytes .../__pycache__/_loginurl.cpython-311.pyc | Bin 5017 -> 0 bytes .../__pycache__/_menubutton.cpython-311.pyc | Bin 9869 -> 0 bytes .../__pycache__/_message.cpython-311.pyc | Bin 205325 -> 0 bytes ...sageautodeletetimerchanged.cpython-311.pyc | Bin 1979 -> 0 bytes .../_messageentity.cpython-311.pyc | Bin 19813 -> 0 bytes .../__pycache__/_messageid.cpython-311.pyc | Bin 2324 -> 0 bytes .../_messageorigin.cpython-311.pyc | Bin 13051 -> 0 bytes .../_messagereactionupdated.cpython-311.pyc | Bin 9313 -> 0 bytes .../__pycache__/_paidmedia.cpython-311.pyc | Bin 15687 -> 0 bytes .../__pycache__/_poll.cpython-311.pyc | Bin 29336 -> 0 bytes .../_proximityalerttriggered.cpython-311.pyc | Bin 3337 -> 0 bytes .../__pycache__/_reaction.cpython-311.pyc | Bin 10020 -> 0 bytes .../__pycache__/_reply.cpython-311.pyc | Bin 24733 -> 0 bytes .../_replykeyboardmarkup.cpython-311.pyc | Bin 16580 -> 0 bytes .../_replykeyboardremove.cpython-311.pyc | Bin 3317 -> 0 bytes .../_sentwebappmessage.cpython-311.pyc | Bin 2172 -> 0 bytes .../__pycache__/_shared.cpython-311.pyc | Bin 12160 -> 0 bytes .../__pycache__/_story.cpython-311.pyc | Bin 2923 -> 0 bytes ...witchinlinequerychosenchat.cpython-311.pyc | Bin 3934 -> 0 bytes .../_telegramobject.cpython-311.pyc | Bin 30953 -> 0 bytes .../__pycache__/_update.cpython-311.pyc | Bin 33719 -> 0 bytes .../__pycache__/_user.cpython-311.pyc | Bin 76811 -> 0 bytes .../_userprofilephotos.cpython-311.pyc | Bin 3783 -> 0 bytes .../__pycache__/_version.cpython-311.pyc | Bin 1836 -> 0 bytes .../__pycache__/_videochat.cpython-311.pyc | Bin 8156 -> 0 bytes .../__pycache__/_webappdata.cpython-311.pyc | Bin 2443 -> 0 bytes .../__pycache__/_webappinfo.cpython-311.pyc | Bin 2136 -> 0 bytes .../__pycache__/_webhookinfo.cpython-311.pyc | Bin 7570 -> 0 bytes .../_writeaccessallowed.cpython-311.pyc | Bin 3504 -> 0 bytes .../__pycache__/constants.cpython-311.pyc | Bin 60516 -> 0 bytes .../__pycache__/error.cpython-311.pyc | Bin 11047 -> 0 bytes .../__pycache__/helpers.cpython-311.pyc | Bin 7932 -> 0 bytes .../__pycache__/warnings.cpython-311.pyc | Bin 2773 -> 0 bytes .../site-packages/telegram/_birthdate.py | 92 - .../python3.11/site-packages/telegram/_bot.py | 10224 ---------------- .../site-packages/telegram/_botcommand.py | 83 - .../telegram/_botcommandscope.py | 273 - .../site-packages/telegram/_botdescription.py | 77 - .../site-packages/telegram/_botname.py | 54 - .../site-packages/telegram/_business.py | 455 - .../site-packages/telegram/_callbackquery.py | 895 -- .../site-packages/telegram/_chat.py | 3599 ------ .../telegram/_chatadministratorrights.py | 247 - .../site-packages/telegram/_chatbackground.py | 547 - .../site-packages/telegram/_chatboost.py | 464 - .../site-packages/telegram/_chatfullinfo.py | 552 - .../site-packages/telegram/_chatinvitelink.py | 195 - .../telegram/_chatjoinrequest.py | 213 - .../site-packages/telegram/_chatlocation.py | 93 - .../site-packages/telegram/_chatmember.py | 665 - .../telegram/_chatmemberupdated.py | 217 - .../telegram/_chatpermissions.py | 249 - .../telegram/_choseninlineresult.py | 109 - .../site-packages/telegram/_copytextbutton.py | 55 - .../site-packages/telegram/_dice.py | 160 - .../site-packages/telegram/_files/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 192 -> 0 bytes .../__pycache__/_basemedium.cpython-311.pyc | Bin 3675 -> 0 bytes .../_basethumbedmedium.cpython-311.pyc | Bin 4093 -> 0 bytes .../__pycache__/animation.cpython-311.pyc | Bin 4325 -> 0 bytes .../_files/__pycache__/audio.cpython-311.pyc | Bin 4523 -> 0 bytes .../__pycache__/chatphoto.cpython-311.pyc | Bin 7008 -> 0 bytes .../__pycache__/contact.cpython-311.pyc | Bin 2645 -> 0 bytes .../__pycache__/document.cpython-311.pyc | Bin 3656 -> 0 bytes .../_files/__pycache__/file.cpython-311.pyc | Bin 17262 -> 0 bytes .../__pycache__/inputfile.cpython-311.pyc | Bin 6373 -> 0 bytes .../__pycache__/inputmedia.cpython-311.pyc | Bin 37347 -> 0 bytes .../__pycache__/inputsticker.cpython-311.pyc | Bin 5629 -> 0 bytes .../__pycache__/location.cpython-311.pyc | Bin 4402 -> 0 bytes .../__pycache__/photosize.cpython-311.pyc | Bin 2903 -> 0 bytes .../__pycache__/sticker.cpython-311.pyc | Bin 17088 -> 0 bytes .../_files/__pycache__/venue.cpython-311.pyc | Bin 4611 -> 0 bytes .../_files/__pycache__/video.cpython-311.pyc | Bin 4159 -> 0 bytes .../__pycache__/videonote.cpython-311.pyc | Bin 3603 -> 0 bytes .../_files/__pycache__/voice.cpython-311.pyc | Bin 3071 -> 0 bytes .../telegram/_files/_basemedium.py | 100 - .../telegram/_files/_basethumbedmedium.py | 103 - .../telegram/_files/animation.py | 102 - .../site-packages/telegram/_files/audio.py | 104 - .../telegram/_files/chatphoto.py | 176 - .../site-packages/telegram/_files/contact.py | 71 - .../site-packages/telegram/_files/document.py | 88 - .../site-packages/telegram/_files/file.py | 371 - .../telegram/_files/inputfile.py | 142 - .../telegram/_files/inputmedia.py | 827 -- .../telegram/_files/inputsticker.py | 119 - .../site-packages/telegram/_files/location.py | 113 - .../telegram/_files/photosize.py | 77 - .../site-packages/telegram/_files/sticker.py | 388 - .../site-packages/telegram/_files/venue.py | 115 - .../site-packages/telegram/_files/video.py | 99 - .../telegram/_files/videonote.py | 90 - .../site-packages/telegram/_files/voice.py | 76 - .../site-packages/telegram/_forcereply.py | 106 - .../site-packages/telegram/_forumtopic.py | 215 - .../site-packages/telegram/_games/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 192 -> 0 bytes .../__pycache__/callbackgame.cpython-311.pyc | Bin 1335 -> 0 bytes .../_games/__pycache__/game.cpython-311.pyc | Bin 9357 -> 0 bytes .../__pycache__/gamehighscore.cpython-311.pyc | Bin 2986 -> 0 bytes .../telegram/_games/callbackgame.py | 35 - .../site-packages/telegram/_games/game.py | 197 - .../telegram/_games/gamehighscore.py | 75 - .../site-packages/telegram/_gifts.py | 153 - .../site-packages/telegram/_giveaway.py | 393 - .../telegram/_inline/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 193 -> 0 bytes .../inlinekeyboardbutton.cpython-311.pyc | Bin 16731 -> 0 bytes .../inlinekeyboardmarkup.cpython-311.pyc | Bin 6637 -> 0 bytes .../__pycache__/inlinequery.cpython-311.pyc | Bin 9499 -> 0 bytes .../inlinequeryresult.cpython-311.pyc | Bin 2898 -> 0 bytes .../inlinequeryresultarticle.cpython-311.pyc | Bin 5897 -> 0 bytes .../inlinequeryresultaudio.cpython-311.pyc | Bin 5736 -> 0 bytes ...linequeryresultcachedaudio.cpython-311.pyc | Bin 5266 -> 0 bytes ...equeryresultcacheddocument.cpython-311.pyc | Bin 5741 -> 0 bytes ...inlinequeryresultcachedgif.cpython-311.pyc | Bin 5875 -> 0 bytes ...equeryresultcachedmpeg4gif.cpython-311.pyc | Bin 5970 -> 0 bytes ...linequeryresultcachedphoto.cpython-311.pyc | Bin 6092 -> 0 bytes ...nequeryresultcachedsticker.cpython-311.pyc | Bin 3763 -> 0 bytes ...linequeryresultcachedvideo.cpython-311.pyc | Bin 6005 -> 0 bytes ...linequeryresultcachedvoice.cpython-311.pyc | Bin 5465 -> 0 bytes .../inlinequeryresultcontact.cpython-311.pyc | Bin 5394 -> 0 bytes .../inlinequeryresultdocument.cpython-311.pyc | Bin 7055 -> 0 bytes .../inlinequeryresultgame.cpython-311.pyc | Bin 2891 -> 0 bytes .../inlinequeryresultgif.cpython-311.pyc | Bin 7611 -> 0 bytes .../inlinequeryresultlocation.cpython-311.pyc | Bin 8658 -> 0 bytes .../inlinequeryresultmpeg4gif.cpython-311.pyc | Bin 7704 -> 0 bytes .../inlinequeryresultphoto.cpython-311.pyc | Bin 6977 -> 0 bytes .../inlinequeryresultsbutton.cpython-311.pyc | Bin 5589 -> 0 bytes .../inlinequeryresultvenue.cpython-311.pyc | Bin 6868 -> 0 bytes .../inlinequeryresultvideo.cpython-311.pyc | Bin 7929 -> 0 bytes .../inlinequeryresultvoice.cpython-311.pyc | Bin 5662 -> 0 bytes ...inputcontactmessagecontent.cpython-311.pyc | Bin 2814 -> 0 bytes ...inputinvoicemessagecontent.cpython-311.pyc | Bin 13747 -> 0 bytes ...nputlocationmessagecontent.cpython-311.pyc | Bin 6152 -> 0 bytes .../inputmessagecontent.cpython-311.pyc | Bin 1617 -> 0 bytes .../inputtextmessagecontent.cpython-311.pyc | Bin 4998 -> 0 bytes .../inputvenuemessagecontent.cpython-311.pyc | Bin 4377 -> 0 bytes .../preparedinlinemessage.cpython-311.pyc | Bin 3327 -> 0 bytes .../telegram/_inline/inlinekeyboardbutton.py | 341 - .../telegram/_inline/inlinekeyboardmarkup.py | 165 - .../telegram/_inline/inlinequery.py | 228 - .../telegram/_inline/inlinequeryresult.py | 79 - .../_inline/inlinequeryresultarticle.py | 149 - .../_inline/inlinequeryresultaudio.py | 130 - .../_inline/inlinequeryresultcachedaudio.py | 116 - .../inlinequeryresultcacheddocument.py | 126 - .../_inline/inlinequeryresultcachedgif.py | 131 - .../inlinequeryresultcachedmpeg4gif.py | 131 - .../_inline/inlinequeryresultcachedphoto.py | 136 - .../_inline/inlinequeryresultcachedsticker.py | 81 - .../_inline/inlinequeryresultcachedvideo.py | 132 - .../_inline/inlinequeryresultcachedvoice.py | 121 - .../_inline/inlinequeryresultcontact.py | 130 - .../_inline/inlinequeryresultdocument.py | 165 - .../telegram/_inline/inlinequeryresultgame.py | 66 - .../telegram/_inline/inlinequeryresultgif.py | 174 - .../_inline/inlinequeryresultlocation.py | 207 - .../_inline/inlinequeryresultmpeg4gif.py | 176 - .../_inline/inlinequeryresultphoto.py | 161 - .../_inline/inlinequeryresultsbutton.py | 118 - .../_inline/inlinequeryresultvenue.py | 160 - .../_inline/inlinequeryresultvideo.py | 182 - .../_inline/inlinequeryresultvoice.py | 127 - .../_inline/inputcontactmessagecontent.py | 68 - .../_inline/inputinvoicemessagecontent.py | 268 - .../_inline/inputlocationmessagecontent.py | 150 - .../telegram/_inline/inputmessagecontent.py | 42 - .../_inline/inputtextmessagecontent.py | 116 - .../_inline/inputvenuemessagecontent.py | 108 - .../telegram/_inline/preparedinlinemessage.py | 83 - .../site-packages/telegram/_keyboardbutton.py | 191 - .../telegram/_keyboardbuttonpolltype.py | 63 - .../telegram/_keyboardbuttonrequest.py | 276 - .../telegram/_linkpreviewoptions.py | 103 - .../site-packages/telegram/_loginurl.py | 105 - .../site-packages/telegram/_menubutton.py | 201 - .../site-packages/telegram/_message.py | 5160 -------- .../_messageautodeletetimerchanged.py | 60 - .../site-packages/telegram/_messageentity.py | 414 - .../site-packages/telegram/_messageid.py | 54 - .../site-packages/telegram/_messageorigin.py | 286 - .../telegram/_messagereactionupdated.py | 209 - .../site-packages/telegram/_paidmedia.py | 341 - .../telegram/_passport/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 195 -> 0 bytes .../__pycache__/credentials.cpython-311.pyc | Bin 26810 -> 0 bytes .../__pycache__/data.cpython-311.pyc | Bin 6549 -> 0 bytes 382 files changed, 71949 deletions(-) delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_manylinux.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_musllinux.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_structures.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/markers.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/requirements.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/specifiers.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/tags.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/utils.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/version.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/common.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/results.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/util.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/actions.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/common.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/core.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/exceptions.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/helpers.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/results.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/testing.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/unicode.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/util.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_parser.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_re.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_types.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_parser.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_re.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_types.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/typing_extensions.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/_vendor/zipp.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/archive_util.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/build_meta.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/cli-32.exe delete mode 100755 venv/lib/python3.11/site-packages/setuptools/cli-64.exe delete mode 100755 venv/lib/python3.11/site-packages/setuptools/cli-arm64.exe delete mode 100755 venv/lib/python3.11/site-packages/setuptools/cli.exe delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/alias.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_clib.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_ext.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_py.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/develop.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/dist_info.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/easy_install.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/editable_wheel.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/egg_info.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_lib.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_scripts.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/py36compat.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/register.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/rotate.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/saveopts.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/sdist.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/setopt.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/test.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload_docs.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/alias.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/bdist_egg.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/bdist_rpm.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/build.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/build_clib.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/build_ext.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/build_py.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/develop.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/dist_info.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/easy_install.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/editable_wheel.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/egg_info.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/install.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/install_egg_info.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/install_lib.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/install_scripts.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/launcher manifest.xml delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/py36compat.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/register.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/rotate.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/saveopts.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/sdist.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/setopt.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/test.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/upload.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/command/upload_docs.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/__pycache__/expand.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/__pycache__/pyprojecttoml.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/__pycache__/setupcfg.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_apply_pyprojecttoml.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/extra_validations.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_validations.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/formats.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/error_reporting.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/extra_validations.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/formats.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/expand.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/config/setupcfg.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/dep_util.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/depends.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/discovery.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/dist.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/errors.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/extension.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/extern/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/extern/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/setuptools/glob.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/gui-32.exe delete mode 100755 venv/lib/python3.11/site-packages/setuptools/gui-64.exe delete mode 100755 venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe delete mode 100755 venv/lib/python3.11/site-packages/setuptools/gui.exe delete mode 100755 venv/lib/python3.11/site-packages/setuptools/installer.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/launch.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/logging.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/monkey.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/msvc.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/namespaces.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/package_index.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/py34compat.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/sandbox.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/script (dev).tmpl delete mode 100755 venv/lib/python3.11/site-packages/setuptools/script.tmpl delete mode 100755 venv/lib/python3.11/site-packages/setuptools/unicode_utils.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/version.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/wheel.py delete mode 100755 venv/lib/python3.11/site-packages/setuptools/windows_support.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/__main__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/__main__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_birthdate.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_bot.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommand.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommandscope.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_botdescription.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_botname.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_business.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_callbackquery.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chat.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatadministratorrights.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatbackground.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatboost.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatfullinfo.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatinvitelink.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatjoinrequest.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatlocation.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmember.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmemberupdated.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_chatpermissions.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_choseninlineresult.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_copytextbutton.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_dice.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_forcereply.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_forumtopic.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_gifts.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_giveaway.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbutton.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonpolltype.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonrequest.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_linkpreviewoptions.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_loginurl.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_menubutton.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_message.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_messageautodeletetimerchanged.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_messageentity.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_messageid.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_messageorigin.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_messagereactionupdated.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_paidmedia.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_poll.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_proximityalerttriggered.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_reaction.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_reply.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardmarkup.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardremove.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_sentwebappmessage.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_shared.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_story.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_switchinlinequerychosenchat.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_telegramobject.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_update.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_user.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_userprofilephotos.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_version.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_videochat.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_webappdata.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_webappinfo.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_webhookinfo.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/_writeaccessallowed.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/constants.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/error.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/helpers.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/__pycache__/warnings.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_birthdate.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_bot.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_botcommand.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_botcommandscope.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_botdescription.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_botname.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_business.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_callbackquery.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chat.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatadministratorrights.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatbackground.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatboost.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatfullinfo.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatinvitelink.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatjoinrequest.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatlocation.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatmember.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatmemberupdated.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_chatpermissions.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_choseninlineresult.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_copytextbutton.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_dice.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basemedium.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basethumbedmedium.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/animation.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/audio.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/chatphoto.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/contact.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/document.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/file.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputfile.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputmedia.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputsticker.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/location.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/photosize.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/sticker.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/venue.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/video.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/videonote.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/__pycache__/voice.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/_basemedium.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/_basethumbedmedium.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/animation.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/audio.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/chatphoto.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/contact.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/document.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/file.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/inputfile.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/inputmedia.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/inputsticker.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/location.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/photosize.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/sticker.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/venue.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/video.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/videonote.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_files/voice.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_forcereply.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_forumtopic.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_games/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_games/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_games/__pycache__/callbackgame.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_games/__pycache__/game.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_games/__pycache__/gamehighscore.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_games/callbackgame.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_games/game.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_games/gamehighscore.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_gifts.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_giveaway.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinekeyboardbutton.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinekeyboardmarkup.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequery.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresult.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultarticle.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultaudio.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedaudio.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcacheddocument.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedgif.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedmpeg4gif.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedphoto.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedsticker.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedvideo.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedvoice.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcontact.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultdocument.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgame.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgif.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultlocation.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultmpeg4gif.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultphoto.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultsbutton.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvenue.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvideo.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvoice.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputcontactmessagecontent.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputinvoicemessagecontent.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputlocationmessagecontent.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputmessagecontent.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputtextmessagecontent.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputvenuemessagecontent.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/preparedinlinemessage.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardbutton.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardmarkup.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequery.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresult.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultarticle.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultaudio.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedaudio.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcacheddocument.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedgif.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedmpeg4gif.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedphoto.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedsticker.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvideo.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvoice.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcontact.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultdocument.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgame.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgif.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultlocation.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultmpeg4gif.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultphoto.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultsbutton.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvenue.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvideo.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvoice.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inputcontactmessagecontent.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inputinvoicemessagecontent.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inputlocationmessagecontent.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inputmessagecontent.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inputtextmessagecontent.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/inputvenuemessagecontent.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_inline/preparedinlinemessage.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_keyboardbutton.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_keyboardbuttonpolltype.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_keyboardbuttonrequest.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_linkpreviewoptions.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_loginurl.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_menubutton.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_message.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_messageautodeletetimerchanged.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_messageentity.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_messageid.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_messageorigin.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_messagereactionupdated.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_paidmedia.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/__init__.py delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/__init__.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/credentials.cpython-311.pyc delete mode 100755 venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/data.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index c5ba20ee2fe964d35ea9419c9ae3e2334d8d1602..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 567 zcmcJLzfQw25XS8!ZT?h6OuRz|YE_k(5D&n>!sg|06Du{uapWYGx*#3`35k&f@jgsl znb?ZDb>iF<#0zkie!4qIF+_8)YhhG_nyo+0Y?&a1XP-!@yza z5FoD7#94~D>CnAbxc(p6e#m~@?hH*8_FWVl{t*rh4VjETBtOIa;h zsphO+;cKheWIAPyYUODyvO7`8hBdP7>eiUDVSwt~Sk~XEs$c-BQn=QnUhSfDZSt;^ k7xowp-9I+>h>cGv-6S#fHspVC5|5n60S}=&_6S$_1}0RHga7~l diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc deleted file mode 100755 index 39a5372e72595296799f2d7ecf79e7fc36ba9bc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13233 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc deleted file mode 100755 index 8c9ebed376fe5b7a080da15297c7c17986c54726..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8001 zcmb6;Yitxpn$S|*cg^2u#o673D=CLd+aguqPqud z-#9yoSluY%ZoLw>OtS3m+=^tK3#aqFbZoTJk?fvyKc`Vk8MTCz(`lvS-$W!5;?Lbz z)$?itQLd)@tE#T5ufF=K>U+&^JsuZ=q}}{*zPAmb|HhSCA}vsP{CgUqTS!15Bv1k! zr$Q9T=@3nFOUOcUCd8238nTky7P67t9`1VRUcn}|h;4#BN;keoZGz)E6WZ`hf1BtLy-ocX!3q7^X>pWM(B=ib> zK>3zhy*U>)3NM*42%8#vVcst@MaR*_w$N5gySP=@{45NhV{-S?=tjGM7qnG1(Q5B`=Et7oH8rlCr`jGID$u7fuS?wYjiS<*tg793#EC zj4TQP*CWh?Gk&X1pL|VsoK!?9tfVB}btaq;g$o%VM|ZrIR$xpxu3L={R8+S_6N+w= zL?t671Cjb30xk!<_+&r63g8w}>SqC=`Fc4^Wl^zt6!bNcsek>3WGOSx*VRnt=sfy_ zI^$<_o2*Eg2vC_xro)lTIwOf;L3c#L@rWE-68*G5oAD&IZI#yE1iIh5{5sVXP z^F>&ul3o2sVH&vR>-`6i#8Bu>Bv{U)YiPmpCb~vtLAVOcPntxff|*=Rg4MivmkBP3 z#u#2ivtq4{hC@^@3pO(*!EUA-uS{?VPQi7X2AY`0b#9d2hS`_tWy><7c$((Gyd){h z{54v(Cfi{B-r6^Wp111tT+FWH;@g08*|uzl7ylf~&i@}*mG;K`S*KuMf~tA_Ac+2X z+4UkGX6;!=*0luOdv+w|6pgZ0^Et>`%=|RZMmWbVyO%x5?(aAqR(v`@sWzVvR$!~U zPTdH-kY2ZWJ_;$F4Gzq+wK9x%*UHU#)?*%Tt`(bhyD>^wH|KJT;K{aJr6h~7f^18K zrVt2oSdG7B>A#K}q8Zrm}+Mjf)b#ow_5HuIVoj&xu)40ez-BejqMR8hxd3a#qyol&m|V zvLHrMz^Yb)43tGI?QbPILAS;P(6KNBkJX$tUCUy^0Yg8(D3CIrZLDe)!#!*H7k7R%na0=upPQXE#9L5&$KF@qI`weG68kausnb+}@+Y<5); z1~$ZcSEw69-`FjiJ5)y>P?K2^zimNnJ({<__Wt}yrHVQc4&EYR=tH9)z&du0UwfZ0wTW;WZla_;?!{6yK^QJZr?b@()g zujKGO?DE~bT-@^8ZNJ&J>QlGw)wb?cyY^{a`@ZZt_@L|Hy#clBh}Lx^&z9M?LSKm; zfTub|xwW_Cs6J)3H9sOBgVS=$JA_tSCoG>)6P7QS&SOL9iy_ysG0PXD6o%uzSKHAa z+FM`UX8FS)1@MnOFCE`c|8aloBy0T-7X>f^Sn7$WZm2yT0B{S52s|B;lDi{}li7|L#*zmf^Z zt1T9|I(jS5hm*;aLWG&j^PeCIYe;f!Bs?DhC!ip21(0j{mD!fusobe|Pt^;!Y7ECC zbz3Toije3fOhVv_W`@_yj!0V(}K5g{`@0TLx?NADArlGx~=8Jd%z>69J#l zIvv=fQ^~67Pmaw~*P%G5Ur@X0!%N$%k{4?qu<4206gY$xd|W;Zg<8iS0!kSxtQ;!2 zr;KN1`2JBS<ki+#1x%*()9}I$fRiirbRgq&5B8JAuSzV+V$?dj+22l|tLEyFcvypyzgv z@ue9Wmj|=KQ2clgq%8oJI;vNl8+u#V>3=&wGNR@|+rNyvVFvi^x=T*SV+vR)qO4ou zVp69i5z7Z9GH2XpEWmW@tdz>6!E%@+HKRL~kn!$=_B6C+`*YSQy$(H2!z-@=$f2^a zS!8XiQ(x|S`N6K2)m=xlT}NPDs_zvITHI5rdrEUp>m##0Z9DVPd+&hKN z!j;>;;@0ADaqI1kt6dLzf~B4y(Nhl{t{aY0+tBLZ8g&=6#y-ulFL$)ex*MwOA=~}S z2#EFVzuCUJXX_kb%31 zBU2rFEtQE2+>FS{5HC^YFxm0gWpRAmaBHv`OO{TYqM?NYWBk~NpUi=qY7${Mus5)` z{`Giuac8B}tQ1agrwQq#8AQR%nG1dz$8=yhlD;96jA5A^j`KlR(D>oxy`-?7HA}Ri#fGb`T76y{b2)DD=Px*-TFC$i=S_xaJhX0E)O$DN9~^+y#G487Vc z50xf)H(xKWlRTh5_48FI@_77XV$OKWFrVkTVyS4gvXV28{uh$&s-xy5e7O8Jat(EhyeN~~ zEDga|Vto)h1Z;{~_@FzWo!nm1WHu~3HSY6xm!t&rPr@rp01RX4+YQLO<)ijHo7C1l zTI-(NblKiovUisqEqU9+wyu?ho9`5*)xBz4Kx+%&i!wn#-db)MFC4gixYRNZ&+4R+ zuN^n?l4HF7U_ad$WEchDF(n}2&+|(*gON*4aEq{x$Sf>bF~Q?YR?G{?FxBHvDb7#n z76?->F>eKSUnJalO6@jcFELoklD&E){QbI}=Y>>+=cTuxL3c(o$p{H_OM_6C{1}|Y z0LNscOBi5hMYloV1Jr_q?J^198wpEE3HuHbzErw(W>LYG9w;3NTXsfd2ZuEbYY&@i zx-%|i_(&LZBiTE`aOntXfn5TL9*xcFZY*wV8v`O4Rty4NfzvNvgFu>YO@mrf3;}Kd zK@U0PitE7)MN_R6^ek8z{~CY&rqSfGQ&UvY zQb9Ohb*ydFh7KE*=fDm`cjkIDszar^G^(pYcTl^E{S^e+>d@LDZO1F5+yGx&5Zztt zSqXTki2_UoS<$iDe#b+K>j8%tcYf)CrKe=+DKj0V+Vd5=C4Ug&R4UuAvHiK@5D@w4 zk@t@j4yf#a22m4c7@p!~l^NDZ@hireo6K)t8BrOZ#`sE%uWWoNwGY5kJb&lU)%Fps z9ok1VX0*hNR@+zP64R$LeHzmTg|eqNf3YxD*n4}dxP5is8uM?ie{$X1cb`)C9Mkq3 zyT4c4Go|*O(E3iOo@vc94ZCLDLI4gxc_1DZUI~>Poa*2-2L}asDxHYwh2>Q?)cO)B F@PD8He%Am1 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-311.pyc deleted file mode 100755 index ea40f917845b4caaebbe4ba41fb64ecc59153404..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3689 zcmc&#Pfz1U6dyZI2#{dZge5F&$%UT99$INDP){5xD#Vuoi9=;+PyGT^>1j`WZzeIeW3z0FR40C(H}huRoA>Ycdp0{l z;JJML>(*hCkUx>>KT>bdU5CLT5y{s?C$ESuoQQ;+!ONd2tQh13n6v&AsR~S51nERb zS_Ek^B%RQuHBw4y-hLQ(+P??p5HwT;om53#FcKT0F20hg5{#2DPQW;&OU4lJ=?zIw z0zd5IQ^1e-_#xm&eS8}DjE^4%KC6%5dHN`vmjQlE&w_D>sD!7tuG&gJ%Exy&1O>5gwwrfhjSqHhS^V4*)f1g6+X4#*$!RHxmAAqm_IvV-62OBfsy$9HE3 z@7sI!$qB5Sd8aqE~2Tp8euA*MxpLKAP3})ocrag zqx{dSuU9YR*-Lr$JUvS@cu3N6HVvwINeXjlQYbK|V&yr-Tc3(_7(O%)#Kuj$%VXzlUb1K_I;M`>@dymQc2Nrrjt%aDKny!!Q?n@n?i#33uwVgVHf)Z2EoYe z3;Sg2Iu?PtT_bc1Hb68+8g|39otmi`?y#zA&6;gPVno?zyo|69Cv$LA7u||J6UP}_Er+mF6b!ib`uTLp&#HVWvy=+n&V3A z&|_!;rsy=1B9cc)o*?-c36=r(36>|tbYujZpgjo=IPiW~qL93QG#Ja zT=ElGnmBrnvlGV-`-I7@B+C4ZGC!k?XZQ)6k>?V5E|EtGKe?4e@uv;kS3H0CIs3*E z?lW|k2Cw%>y;1l71V3X8z;6`5Pu4R4Vp;kWtfFXIban>-uRT29&r+Top*GKwt^FXJ z^Z`(M1gbnxy5ISZm$ui=VD*kbi8VqhSK3)~(0p@M@U!e|tfG39$hP9ShgAisGaoa;A z127on=6JAW4J=j_0?QI=iALP_RD}r=uL|7!SwIzomFNMKWN+ljj?5feDUDN%D`g3=fFlJ7A_QeIz`CGiB%dOQMF)liQ4qnJ36eQ@?R((T zAVf@a9GJ$|=_k;CZ-9uqXx{IJh`Ruy0*8pg@eJOu5KDMdK}S_e5(icmY34uH3WC`C zHoeR-euXZ>CQMa(56D$Q5QMADqyV5gNdCgPzpodbkxZep{KLwRD+lST)T99R4HDc` bz)ii?XC(jhJon@xSGvrV&dE6cvkUwK{8i(c diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-311.pyc deleted file mode 100755 index 660bac78a89c8c33947939402c9eb22e7f227c09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16535 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-311.pyc deleted file mode 100755 index ef9150fb13206e388363c3477b88c58e9f4122bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7650 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc deleted file mode 100755 index 0d4141e6c4c04ddb859042e1b582adf7204dc60d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34367 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-311.pyc deleted file mode 100755 index b2ca9c49b054f62a6d386af8d141bfee8fef0fbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6687 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-311.pyc deleted file mode 100755 index 9b8f22fea7c6c6c5ee1e8e4f83ebf058397c4ab7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21879 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_manylinux.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_manylinux.py deleted file mode 100755 index 4c379aa..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_manylinux.py +++ /dev/null @@ -1,301 +0,0 @@ -import collections -import functools -import os -import re -import struct -import sys -import warnings -from typing import IO, Dict, Iterator, NamedTuple, Optional, Tuple - - -# Python does not provide platform information at sufficient granularity to -# identify the architecture of the running executable in some cases, so we -# determine it dynamically by reading the information from the running -# process. This only applies on Linux, which uses the ELF format. -class _ELFFileHeader: - # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header - class _InvalidELFFileHeader(ValueError): - """ - An invalid ELF file header was found. - """ - - ELF_MAGIC_NUMBER = 0x7F454C46 - ELFCLASS32 = 1 - ELFCLASS64 = 2 - ELFDATA2LSB = 1 - ELFDATA2MSB = 2 - EM_386 = 3 - EM_S390 = 22 - EM_ARM = 40 - EM_X86_64 = 62 - EF_ARM_ABIMASK = 0xFF000000 - EF_ARM_ABI_VER5 = 0x05000000 - EF_ARM_ABI_FLOAT_HARD = 0x00000400 - - def __init__(self, file: IO[bytes]) -> None: - def unpack(fmt: str) -> int: - try: - data = file.read(struct.calcsize(fmt)) - result: Tuple[int, ...] = struct.unpack(fmt, data) - except struct.error: - raise _ELFFileHeader._InvalidELFFileHeader() - return result[0] - - self.e_ident_magic = unpack(">I") - if self.e_ident_magic != self.ELF_MAGIC_NUMBER: - raise _ELFFileHeader._InvalidELFFileHeader() - self.e_ident_class = unpack("B") - if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}: - raise _ELFFileHeader._InvalidELFFileHeader() - self.e_ident_data = unpack("B") - if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}: - raise _ELFFileHeader._InvalidELFFileHeader() - self.e_ident_version = unpack("B") - self.e_ident_osabi = unpack("B") - self.e_ident_abiversion = unpack("B") - self.e_ident_pad = file.read(7) - format_h = "H" - format_i = "I" - format_q = "Q" - format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q - self.e_type = unpack(format_h) - self.e_machine = unpack(format_h) - self.e_version = unpack(format_i) - self.e_entry = unpack(format_p) - self.e_phoff = unpack(format_p) - self.e_shoff = unpack(format_p) - self.e_flags = unpack(format_i) - self.e_ehsize = unpack(format_h) - self.e_phentsize = unpack(format_h) - self.e_phnum = unpack(format_h) - self.e_shentsize = unpack(format_h) - self.e_shnum = unpack(format_h) - self.e_shstrndx = unpack(format_h) - - -def _get_elf_header() -> Optional[_ELFFileHeader]: - try: - with open(sys.executable, "rb") as f: - elf_header = _ELFFileHeader(f) - except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader): - return None - return elf_header - - -def _is_linux_armhf() -> bool: - # hard-float ABI can be detected from the ELF header of the running - # process - # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf - elf_header = _get_elf_header() - if elf_header is None: - return False - result = elf_header.e_ident_class == elf_header.ELFCLASS32 - result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB - result &= elf_header.e_machine == elf_header.EM_ARM - result &= ( - elf_header.e_flags & elf_header.EF_ARM_ABIMASK - ) == elf_header.EF_ARM_ABI_VER5 - result &= ( - elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD - ) == elf_header.EF_ARM_ABI_FLOAT_HARD - return result - - -def _is_linux_i686() -> bool: - elf_header = _get_elf_header() - if elf_header is None: - return False - result = elf_header.e_ident_class == elf_header.ELFCLASS32 - result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB - result &= elf_header.e_machine == elf_header.EM_386 - return result - - -def _have_compatible_abi(arch: str) -> bool: - if arch == "armv7l": - return _is_linux_armhf() - if arch == "i686": - return _is_linux_i686() - return arch in {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x"} - - -# If glibc ever changes its major version, we need to know what the last -# minor version was, so we can build the complete list of all versions. -# For now, guess what the highest minor version might be, assume it will -# be 50 for testing. Once this actually happens, update the dictionary -# with the actual value. -_LAST_GLIBC_MINOR: Dict[int, int] = collections.defaultdict(lambda: 50) - - -class _GLibCVersion(NamedTuple): - major: int - minor: int - - -def _glibc_version_string_confstr() -> Optional[str]: - """ - Primary implementation of glibc_version_string using os.confstr. - """ - # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely - # to be broken or missing. This strategy is used in the standard library - # platform module. - # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 - try: - # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17". - version_string = os.confstr("CS_GNU_LIBC_VERSION") - assert version_string is not None - _, version = version_string.split() - except (AssertionError, AttributeError, OSError, ValueError): - # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... - return None - return version - - -def _glibc_version_string_ctypes() -> Optional[str]: - """ - Fallback implementation of glibc_version_string using ctypes. - """ - try: - import ctypes - except ImportError: - return None - - # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen - # manpage says, "If filename is NULL, then the returned handle is for the - # main program". This way we can let the linker do the work to figure out - # which libc our process is actually using. - # - # We must also handle the special case where the executable is not a - # dynamically linked executable. This can occur when using musl libc, - # for example. In this situation, dlopen() will error, leading to an - # OSError. Interestingly, at least in the case of musl, there is no - # errno set on the OSError. The single string argument used to construct - # OSError comes from libc itself and is therefore not portable to - # hard code here. In any case, failure to call dlopen() means we - # can proceed, so we bail on our attempt. - try: - process_namespace = ctypes.CDLL(None) - except OSError: - return None - - try: - gnu_get_libc_version = process_namespace.gnu_get_libc_version - except AttributeError: - # Symbol doesn't exist -> therefore, we are not linked to - # glibc. - return None - - # Call gnu_get_libc_version, which returns a string like "2.5" - gnu_get_libc_version.restype = ctypes.c_char_p - version_str: str = gnu_get_libc_version() - # py2 / py3 compatibility: - if not isinstance(version_str, str): - version_str = version_str.decode("ascii") - - return version_str - - -def _glibc_version_string() -> Optional[str]: - """Returns glibc version string, or None if not using glibc.""" - return _glibc_version_string_confstr() or _glibc_version_string_ctypes() - - -def _parse_glibc_version(version_str: str) -> Tuple[int, int]: - """Parse glibc version. - - We use a regexp instead of str.split because we want to discard any - random junk that might come after the minor version -- this might happen - in patched/forked versions of glibc (e.g. Linaro's version of glibc - uses version strings like "2.20-2014.11"). See gh-3588. - """ - m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) - if not m: - warnings.warn( - "Expected glibc version with 2 components major.minor," - " got: %s" % version_str, - RuntimeWarning, - ) - return -1, -1 - return int(m.group("major")), int(m.group("minor")) - - -@functools.lru_cache() -def _get_glibc_version() -> Tuple[int, int]: - version_str = _glibc_version_string() - if version_str is None: - return (-1, -1) - return _parse_glibc_version(version_str) - - -# From PEP 513, PEP 600 -def _is_compatible(name: str, arch: str, version: _GLibCVersion) -> bool: - sys_glibc = _get_glibc_version() - if sys_glibc < version: - return False - # Check for presence of _manylinux module. - try: - import _manylinux # noqa - except ImportError: - return True - if hasattr(_manylinux, "manylinux_compatible"): - result = _manylinux.manylinux_compatible(version[0], version[1], arch) - if result is not None: - return bool(result) - return True - if version == _GLibCVersion(2, 5): - if hasattr(_manylinux, "manylinux1_compatible"): - return bool(_manylinux.manylinux1_compatible) - if version == _GLibCVersion(2, 12): - if hasattr(_manylinux, "manylinux2010_compatible"): - return bool(_manylinux.manylinux2010_compatible) - if version == _GLibCVersion(2, 17): - if hasattr(_manylinux, "manylinux2014_compatible"): - return bool(_manylinux.manylinux2014_compatible) - return True - - -_LEGACY_MANYLINUX_MAP = { - # CentOS 7 w/ glibc 2.17 (PEP 599) - (2, 17): "manylinux2014", - # CentOS 6 w/ glibc 2.12 (PEP 571) - (2, 12): "manylinux2010", - # CentOS 5 w/ glibc 2.5 (PEP 513) - (2, 5): "manylinux1", -} - - -def platform_tags(linux: str, arch: str) -> Iterator[str]: - if not _have_compatible_abi(arch): - return - # Oldest glibc to be supported regardless of architecture is (2, 17). - too_old_glibc2 = _GLibCVersion(2, 16) - if arch in {"x86_64", "i686"}: - # On x86/i686 also oldest glibc to be supported is (2, 5). - too_old_glibc2 = _GLibCVersion(2, 4) - current_glibc = _GLibCVersion(*_get_glibc_version()) - glibc_max_list = [current_glibc] - # We can assume compatibility across glibc major versions. - # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 - # - # Build a list of maximum glibc versions so that we can - # output the canonical list of all glibc from current_glibc - # down to too_old_glibc2, including all intermediary versions. - for glibc_major in range(current_glibc.major - 1, 1, -1): - glibc_minor = _LAST_GLIBC_MINOR[glibc_major] - glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) - for glibc_max in glibc_max_list: - if glibc_max.major == too_old_glibc2.major: - min_minor = too_old_glibc2.minor - else: - # For other glibc major versions oldest supported is (x, 0). - min_minor = -1 - for glibc_minor in range(glibc_max.minor, min_minor, -1): - glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) - tag = "manylinux_{}_{}".format(*glibc_version) - if _is_compatible(tag, arch, glibc_version): - yield linux.replace("linux", tag) - # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. - if glibc_version in _LEGACY_MANYLINUX_MAP: - legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] - if _is_compatible(legacy_tag, arch, glibc_version): - yield linux.replace("linux", legacy_tag) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_musllinux.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_musllinux.py deleted file mode 100755 index 8ac3059..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_musllinux.py +++ /dev/null @@ -1,136 +0,0 @@ -"""PEP 656 support. - -This module implements logic to detect if the currently running Python is -linked against musl, and what musl version is used. -""" - -import contextlib -import functools -import operator -import os -import re -import struct -import subprocess -import sys -from typing import IO, Iterator, NamedTuple, Optional, Tuple - - -def _read_unpacked(f: IO[bytes], fmt: str) -> Tuple[int, ...]: - return struct.unpack(fmt, f.read(struct.calcsize(fmt))) - - -def _parse_ld_musl_from_elf(f: IO[bytes]) -> Optional[str]: - """Detect musl libc location by parsing the Python executable. - - Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca - ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html - """ - f.seek(0) - try: - ident = _read_unpacked(f, "16B") - except struct.error: - return None - if ident[:4] != tuple(b"\x7fELF"): # Invalid magic, not ELF. - return None - f.seek(struct.calcsize("HHI"), 1) # Skip file type, machine, and version. - - try: - # e_fmt: Format for program header. - # p_fmt: Format for section header. - # p_idx: Indexes to find p_type, p_offset, and p_filesz. - e_fmt, p_fmt, p_idx = { - 1: ("IIIIHHH", "IIIIIIII", (0, 1, 4)), # 32-bit. - 2: ("QQQIHHH", "IIQQQQQQ", (0, 2, 5)), # 64-bit. - }[ident[4]] - except KeyError: - return None - else: - p_get = operator.itemgetter(*p_idx) - - # Find the interpreter section and return its content. - try: - _, e_phoff, _, _, _, e_phentsize, e_phnum = _read_unpacked(f, e_fmt) - except struct.error: - return None - for i in range(e_phnum + 1): - f.seek(e_phoff + e_phentsize * i) - try: - p_type, p_offset, p_filesz = p_get(_read_unpacked(f, p_fmt)) - except struct.error: - return None - if p_type != 3: # Not PT_INTERP. - continue - f.seek(p_offset) - interpreter = os.fsdecode(f.read(p_filesz)).strip("\0") - if "musl" not in interpreter: - return None - return interpreter - return None - - -class _MuslVersion(NamedTuple): - major: int - minor: int - - -def _parse_musl_version(output: str) -> Optional[_MuslVersion]: - lines = [n for n in (n.strip() for n in output.splitlines()) if n] - if len(lines) < 2 or lines[0][:4] != "musl": - return None - m = re.match(r"Version (\d+)\.(\d+)", lines[1]) - if not m: - return None - return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) - - -@functools.lru_cache() -def _get_musl_version(executable: str) -> Optional[_MuslVersion]: - """Detect currently-running musl runtime version. - - This is done by checking the specified executable's dynamic linking - information, and invoking the loader to parse its output for a version - string. If the loader is musl, the output would be something like:: - - musl libc (x86_64) - Version 1.2.2 - Dynamic Program Loader - """ - with contextlib.ExitStack() as stack: - try: - f = stack.enter_context(open(executable, "rb")) - except OSError: - return None - ld = _parse_ld_musl_from_elf(f) - if not ld: - return None - proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True) - return _parse_musl_version(proc.stderr) - - -def platform_tags(arch: str) -> Iterator[str]: - """Generate musllinux tags compatible to the current platform. - - :param arch: Should be the part of platform tag after the ``linux_`` - prefix, e.g. ``x86_64``. The ``linux_`` prefix is assumed as a - prerequisite for the current platform to be musllinux-compatible. - - :returns: An iterator of compatible musllinux tags. - """ - sys_musl = _get_musl_version(sys.executable) - if sys_musl is None: # Python not dynamically linked against musl. - return - for minor in range(sys_musl.minor, -1, -1): - yield f"musllinux_{sys_musl.major}_{minor}_{arch}" - - -if __name__ == "__main__": # pragma: no cover - import sysconfig - - plat = sysconfig.get_platform() - assert plat.startswith("linux-"), "not linux" - - print("plat:", plat) - print("musl:", _get_musl_version(sys.executable)) - print("tags:", end=" ") - for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): - print(t, end="\n ") diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_structures.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_structures.py deleted file mode 100755 index 90a6465..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_structures.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - - -class InfinityType: - def __repr__(self) -> str: - return "Infinity" - - def __hash__(self) -> int: - return hash(repr(self)) - - def __lt__(self, other: object) -> bool: - return False - - def __le__(self, other: object) -> bool: - return False - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) - - def __gt__(self, other: object) -> bool: - return True - - def __ge__(self, other: object) -> bool: - return True - - def __neg__(self: object) -> "NegativeInfinityType": - return NegativeInfinity - - -Infinity = InfinityType() - - -class NegativeInfinityType: - def __repr__(self) -> str: - return "-Infinity" - - def __hash__(self) -> int: - return hash(repr(self)) - - def __lt__(self, other: object) -> bool: - return True - - def __le__(self, other: object) -> bool: - return True - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) - - def __gt__(self, other: object) -> bool: - return False - - def __ge__(self, other: object) -> bool: - return False - - def __neg__(self: object) -> InfinityType: - return Infinity - - -NegativeInfinity = NegativeInfinityType() diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/markers.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/markers.py deleted file mode 100755 index eb0541b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/markers.py +++ /dev/null @@ -1,304 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import operator -import os -import platform -import sys -from typing import Any, Callable, Dict, List, Optional, Tuple, Union - -from setuptools.extern.pyparsing import ( # noqa: N817 - Forward, - Group, - Literal as L, - ParseException, - ParseResults, - QuotedString, - ZeroOrMore, - stringEnd, - stringStart, -) - -from .specifiers import InvalidSpecifier, Specifier - -__all__ = [ - "InvalidMarker", - "UndefinedComparison", - "UndefinedEnvironmentName", - "Marker", - "default_environment", -] - -Operator = Callable[[str, str], bool] - - -class InvalidMarker(ValueError): - """ - An invalid marker was found, users should refer to PEP 508. - """ - - -class UndefinedComparison(ValueError): - """ - An invalid operation was attempted on a value that doesn't support it. - """ - - -class UndefinedEnvironmentName(ValueError): - """ - A name was attempted to be used that does not exist inside of the - environment. - """ - - -class Node: - def __init__(self, value: Any) -> None: - self.value = value - - def __str__(self) -> str: - return str(self.value) - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}('{self}')>" - - def serialize(self) -> str: - raise NotImplementedError - - -class Variable(Node): - def serialize(self) -> str: - return str(self) - - -class Value(Node): - def serialize(self) -> str: - return f'"{self}"' - - -class Op(Node): - def serialize(self) -> str: - return str(self) - - -VARIABLE = ( - L("implementation_version") - | L("platform_python_implementation") - | L("implementation_name") - | L("python_full_version") - | L("platform_release") - | L("platform_version") - | L("platform_machine") - | L("platform_system") - | L("python_version") - | L("sys_platform") - | L("os_name") - | L("os.name") # PEP-345 - | L("sys.platform") # PEP-345 - | L("platform.version") # PEP-345 - | L("platform.machine") # PEP-345 - | L("platform.python_implementation") # PEP-345 - | L("python_implementation") # undocumented setuptools legacy - | L("extra") # PEP-508 -) -ALIASES = { - "os.name": "os_name", - "sys.platform": "sys_platform", - "platform.version": "platform_version", - "platform.machine": "platform_machine", - "platform.python_implementation": "platform_python_implementation", - "python_implementation": "platform_python_implementation", -} -VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) - -VERSION_CMP = ( - L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<") -) - -MARKER_OP = VERSION_CMP | L("not in") | L("in") -MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) - -MARKER_VALUE = QuotedString("'") | QuotedString('"') -MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) - -BOOLOP = L("and") | L("or") - -MARKER_VAR = VARIABLE | MARKER_VALUE - -MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) -MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) - -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() - -MARKER_EXPR = Forward() -MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) -MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) - -MARKER = stringStart + MARKER_EXPR + stringEnd - - -def _coerce_parse_result(results: Union[ParseResults, List[Any]]) -> List[Any]: - if isinstance(results, ParseResults): - return [_coerce_parse_result(i) for i in results] - else: - return results - - -def _format_marker( - marker: Union[List[str], Tuple[Node, ...], str], first: Optional[bool] = True -) -> str: - - assert isinstance(marker, (list, tuple, str)) - - # Sometimes we have a structure like [[...]] which is a single item list - # where the single item is itself it's own list. In that case we want skip - # the rest of this function so that we don't get extraneous () on the - # outside. - if ( - isinstance(marker, list) - and len(marker) == 1 - and isinstance(marker[0], (list, tuple)) - ): - return _format_marker(marker[0]) - - if isinstance(marker, list): - inner = (_format_marker(m, first=False) for m in marker) - if first: - return " ".join(inner) - else: - return "(" + " ".join(inner) + ")" - elif isinstance(marker, tuple): - return " ".join([m.serialize() for m in marker]) - else: - return marker - - -_operators: Dict[str, Operator] = { - "in": lambda lhs, rhs: lhs in rhs, - "not in": lambda lhs, rhs: lhs not in rhs, - "<": operator.lt, - "<=": operator.le, - "==": operator.eq, - "!=": operator.ne, - ">=": operator.ge, - ">": operator.gt, -} - - -def _eval_op(lhs: str, op: Op, rhs: str) -> bool: - try: - spec = Specifier("".join([op.serialize(), rhs])) - except InvalidSpecifier: - pass - else: - return spec.contains(lhs) - - oper: Optional[Operator] = _operators.get(op.serialize()) - if oper is None: - raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.") - - return oper(lhs, rhs) - - -class Undefined: - pass - - -_undefined = Undefined() - - -def _get_env(environment: Dict[str, str], name: str) -> str: - value: Union[str, Undefined] = environment.get(name, _undefined) - - if isinstance(value, Undefined): - raise UndefinedEnvironmentName( - f"{name!r} does not exist in evaluation environment." - ) - - return value - - -def _evaluate_markers(markers: List[Any], environment: Dict[str, str]) -> bool: - groups: List[List[bool]] = [[]] - - for marker in markers: - assert isinstance(marker, (list, tuple, str)) - - if isinstance(marker, list): - groups[-1].append(_evaluate_markers(marker, environment)) - elif isinstance(marker, tuple): - lhs, op, rhs = marker - - if isinstance(lhs, Variable): - lhs_value = _get_env(environment, lhs.value) - rhs_value = rhs.value - else: - lhs_value = lhs.value - rhs_value = _get_env(environment, rhs.value) - - groups[-1].append(_eval_op(lhs_value, op, rhs_value)) - else: - assert marker in ["and", "or"] - if marker == "or": - groups.append([]) - - return any(all(item) for item in groups) - - -def format_full_version(info: "sys._version_info") -> str: - version = "{0.major}.{0.minor}.{0.micro}".format(info) - kind = info.releaselevel - if kind != "final": - version += kind[0] + str(info.serial) - return version - - -def default_environment() -> Dict[str, str]: - iver = format_full_version(sys.implementation.version) - implementation_name = sys.implementation.name - return { - "implementation_name": implementation_name, - "implementation_version": iver, - "os_name": os.name, - "platform_machine": platform.machine(), - "platform_release": platform.release(), - "platform_system": platform.system(), - "platform_version": platform.version(), - "python_full_version": platform.python_version(), - "platform_python_implementation": platform.python_implementation(), - "python_version": ".".join(platform.python_version_tuple()[:2]), - "sys_platform": sys.platform, - } - - -class Marker: - def __init__(self, marker: str) -> None: - try: - self._markers = _coerce_parse_result(MARKER.parseString(marker)) - except ParseException as e: - raise InvalidMarker( - f"Invalid marker: {marker!r}, parse error at " - f"{marker[e.loc : e.loc + 8]!r}" - ) - - def __str__(self) -> str: - return _format_marker(self._markers) - - def __repr__(self) -> str: - return f"" - - def evaluate(self, environment: Optional[Dict[str, str]] = None) -> bool: - """Evaluate a marker. - - Return the boolean from evaluating the given marker against the - environment. environment is an optional argument to override all or - part of the determined environment. - - The environment is determined from the current Python process. - """ - current_environment = default_environment() - if environment is not None: - current_environment.update(environment) - - return _evaluate_markers(self._markers, current_environment) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/requirements.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/requirements.py deleted file mode 100755 index 0d93231..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/requirements.py +++ /dev/null @@ -1,146 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import re -import string -import urllib.parse -from typing import List, Optional as TOptional, Set - -from setuptools.extern.pyparsing import ( # noqa - Combine, - Literal as L, - Optional, - ParseException, - Regex, - Word, - ZeroOrMore, - originalTextFor, - stringEnd, - stringStart, -) - -from .markers import MARKER_EXPR, Marker -from .specifiers import LegacySpecifier, Specifier, SpecifierSet - - -class InvalidRequirement(ValueError): - """ - An invalid requirement was found, users should refer to PEP 508. - """ - - -ALPHANUM = Word(string.ascii_letters + string.digits) - -LBRACKET = L("[").suppress() -RBRACKET = L("]").suppress() -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() -COMMA = L(",").suppress() -SEMICOLON = L(";").suppress() -AT = L("@").suppress() - -PUNCTUATION = Word("-_.") -IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) -IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) - -NAME = IDENTIFIER("name") -EXTRA = IDENTIFIER - -URI = Regex(r"[^ ]+")("url") -URL = AT + URI - -EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) -EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") - -VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) -VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) - -VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY -VERSION_MANY = Combine( - VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False -)("_raw_spec") -_VERSION_SPEC = Optional((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY) -_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "") - -VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") -VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) - -MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") -MARKER_EXPR.setParseAction( - lambda s, l, t: Marker(s[t._original_start : t._original_end]) -) -MARKER_SEPARATOR = SEMICOLON -MARKER = MARKER_SEPARATOR + MARKER_EXPR - -VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) -URL_AND_MARKER = URL + Optional(MARKER) - -NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) - -REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd -# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see -# issue #104 -REQUIREMENT.parseString("x[]") - - -class Requirement: - """Parse a requirement. - - Parse a given requirement string into its parts, such as name, specifier, - URL, and extras. Raises InvalidRequirement on a badly-formed requirement - string. - """ - - # TODO: Can we test whether something is contained within a requirement? - # If so how do we do that? Do we need to test against the _name_ of - # the thing as well as the version? What about the markers? - # TODO: Can we normalize the name and extra name? - - def __init__(self, requirement_string: str) -> None: - try: - req = REQUIREMENT.parseString(requirement_string) - except ParseException as e: - raise InvalidRequirement( - f'Parse error at "{ requirement_string[e.loc : e.loc + 8]!r}": {e.msg}' - ) - - self.name: str = req.name - if req.url: - parsed_url = urllib.parse.urlparse(req.url) - if parsed_url.scheme == "file": - if urllib.parse.urlunparse(parsed_url) != req.url: - raise InvalidRequirement("Invalid URL given") - elif not (parsed_url.scheme and parsed_url.netloc) or ( - not parsed_url.scheme and not parsed_url.netloc - ): - raise InvalidRequirement(f"Invalid URL: {req.url}") - self.url: TOptional[str] = req.url - else: - self.url = None - self.extras: Set[str] = set(req.extras.asList() if req.extras else []) - self.specifier: SpecifierSet = SpecifierSet(req.specifier) - self.marker: TOptional[Marker] = req.marker if req.marker else None - - def __str__(self) -> str: - parts: List[str] = [self.name] - - if self.extras: - formatted_extras = ",".join(sorted(self.extras)) - parts.append(f"[{formatted_extras}]") - - if self.specifier: - parts.append(str(self.specifier)) - - if self.url: - parts.append(f"@ {self.url}") - if self.marker: - parts.append(" ") - - if self.marker: - parts.append(f"; {self.marker}") - - return "".join(parts) - - def __repr__(self) -> str: - return f"" diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/specifiers.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/specifiers.py deleted file mode 100755 index 0e218a6..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/specifiers.py +++ /dev/null @@ -1,802 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import abc -import functools -import itertools -import re -import warnings -from typing import ( - Callable, - Dict, - Iterable, - Iterator, - List, - Optional, - Pattern, - Set, - Tuple, - TypeVar, - Union, -) - -from .utils import canonicalize_version -from .version import LegacyVersion, Version, parse - -ParsedVersion = Union[Version, LegacyVersion] -UnparsedVersion = Union[Version, LegacyVersion, str] -VersionTypeVar = TypeVar("VersionTypeVar", bound=UnparsedVersion) -CallableOperator = Callable[[ParsedVersion, str], bool] - - -class InvalidSpecifier(ValueError): - """ - An invalid specifier was found, users should refer to PEP 440. - """ - - -class BaseSpecifier(metaclass=abc.ABCMeta): - @abc.abstractmethod - def __str__(self) -> str: - """ - Returns the str representation of this Specifier like object. This - should be representative of the Specifier itself. - """ - - @abc.abstractmethod - def __hash__(self) -> int: - """ - Returns a hash value for this Specifier like object. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Returns a boolean representing whether or not the two Specifier like - objects are equal. - """ - - @abc.abstractproperty - def prereleases(self) -> Optional[bool]: - """ - Returns whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @prereleases.setter - def prereleases(self, value: bool) -> None: - """ - Sets whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @abc.abstractmethod - def contains(self, item: str, prereleases: Optional[bool] = None) -> bool: - """ - Determines if the given item is contained within this specifier. - """ - - @abc.abstractmethod - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - """ - Takes an iterable of items and filters them so that only items which - are contained within this specifier are allowed in it. - """ - - -class _IndividualSpecifier(BaseSpecifier): - - _operators: Dict[str, str] = {} - _regex: Pattern[str] - - def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None: - match = self._regex.search(spec) - if not match: - raise InvalidSpecifier(f"Invalid specifier: '{spec}'") - - self._spec: Tuple[str, str] = ( - match.group("operator").strip(), - match.group("version").strip(), - ) - - # Store whether or not this Specifier should accept prereleases - self._prereleases = prereleases - - def __repr__(self) -> str: - pre = ( - f", prereleases={self.prereleases!r}" - if self._prereleases is not None - else "" - ) - - return f"<{self.__class__.__name__}({str(self)!r}{pre})>" - - def __str__(self) -> str: - return "{}{}".format(*self._spec) - - @property - def _canonical_spec(self) -> Tuple[str, str]: - return self._spec[0], canonicalize_version(self._spec[1]) - - def __hash__(self) -> int: - return hash(self._canonical_spec) - - def __eq__(self, other: object) -> bool: - if isinstance(other, str): - try: - other = self.__class__(str(other)) - except InvalidSpecifier: - return NotImplemented - elif not isinstance(other, self.__class__): - return NotImplemented - - return self._canonical_spec == other._canonical_spec - - def _get_operator(self, op: str) -> CallableOperator: - operator_callable: CallableOperator = getattr( - self, f"_compare_{self._operators[op]}" - ) - return operator_callable - - def _coerce_version(self, version: UnparsedVersion) -> ParsedVersion: - if not isinstance(version, (LegacyVersion, Version)): - version = parse(version) - return version - - @property - def operator(self) -> str: - return self._spec[0] - - @property - def version(self) -> str: - return self._spec[1] - - @property - def prereleases(self) -> Optional[bool]: - return self._prereleases - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - def __contains__(self, item: str) -> bool: - return self.contains(item) - - def contains( - self, item: UnparsedVersion, prereleases: Optional[bool] = None - ) -> bool: - - # Determine if prereleases are to be allowed or not. - if prereleases is None: - prereleases = self.prereleases - - # Normalize item to a Version or LegacyVersion, this allows us to have - # a shortcut for ``"2.0" in Specifier(">=2") - normalized_item = self._coerce_version(item) - - # Determine if we should be supporting prereleases in this specifier - # or not, if we do not support prereleases than we can short circuit - # logic if this version is a prereleases. - if normalized_item.is_prerelease and not prereleases: - return False - - # Actually do the comparison to determine if this item is contained - # within this Specifier or not. - operator_callable: CallableOperator = self._get_operator(self.operator) - return operator_callable(normalized_item, self.version) - - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - - yielded = False - found_prereleases = [] - - kw = {"prereleases": prereleases if prereleases is not None else True} - - # Attempt to iterate over all the values in the iterable and if any of - # them match, yield them. - for version in iterable: - parsed_version = self._coerce_version(version) - - if self.contains(parsed_version, **kw): - # If our version is a prerelease, and we were not set to allow - # prereleases, then we'll store it for later in case nothing - # else matches this specifier. - if parsed_version.is_prerelease and not ( - prereleases or self.prereleases - ): - found_prereleases.append(version) - # Either this is not a prerelease, or we should have been - # accepting prereleases from the beginning. - else: - yielded = True - yield version - - # Now that we've iterated over everything, determine if we've yielded - # any values, and if we have not and we have any prereleases stored up - # then we will go ahead and yield the prereleases. - if not yielded and found_prereleases: - for version in found_prereleases: - yield version - - -class LegacySpecifier(_IndividualSpecifier): - - _regex_str = r""" - (?P(==|!=|<=|>=|<|>)) - \s* - (?P - [^,;\s)]* # Since this is a "legacy" specifier, and the version - # string can be just about anything, we match everything - # except for whitespace, a semi-colon for marker support, - # a closing paren since versions can be enclosed in - # them, and a comma since it's a version separator. - ) - """ - - _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) - - _operators = { - "==": "equal", - "!=": "not_equal", - "<=": "less_than_equal", - ">=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - } - - def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None: - super().__init__(spec, prereleases) - - warnings.warn( - "Creating a LegacyVersion has been deprecated and will be " - "removed in the next major release", - DeprecationWarning, - ) - - def _coerce_version(self, version: UnparsedVersion) -> LegacyVersion: - if not isinstance(version, LegacyVersion): - version = LegacyVersion(str(version)) - return version - - def _compare_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective == self._coerce_version(spec) - - def _compare_not_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective != self._coerce_version(spec) - - def _compare_less_than_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective <= self._coerce_version(spec) - - def _compare_greater_than_equal( - self, prospective: LegacyVersion, spec: str - ) -> bool: - return prospective >= self._coerce_version(spec) - - def _compare_less_than(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective < self._coerce_version(spec) - - def _compare_greater_than(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective > self._coerce_version(spec) - - -def _require_version_compare( - fn: Callable[["Specifier", ParsedVersion, str], bool] -) -> Callable[["Specifier", ParsedVersion, str], bool]: - @functools.wraps(fn) - def wrapped(self: "Specifier", prospective: ParsedVersion, spec: str) -> bool: - if not isinstance(prospective, Version): - return False - return fn(self, prospective, spec) - - return wrapped - - -class Specifier(_IndividualSpecifier): - - _regex_str = r""" - (?P(~=|==|!=|<=|>=|<|>|===)) - (?P - (?: - # The identity operators allow for an escape hatch that will - # do an exact string match of the version you wish to install. - # This will not be parsed by PEP 440 and we cannot determine - # any semantic meaning from it. This operator is discouraged - # but included entirely as an escape hatch. - (?<====) # Only match for the identity operator - \s* - [^\s]* # We just match everything, except for whitespace - # since we are only testing for strict identity. - ) - | - (?: - # The (non)equality operators allow for wild card and local - # versions to be specified so we have to define these two - # operators separately to enable that. - (?<===|!=) # Only match for equals and not equals - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)* # release - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - - # You cannot use a wild card and a dev or local version - # together so group them with a | and make them optional. - (?: - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local - | - \.\* # Wild card syntax of .* - )? - ) - | - (?: - # The compatible operator requires at least two digits in the - # release segment. - (?<=~=) # Only match for the compatible operator - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - ) - | - (?: - # All other operators only allow a sub set of what the - # (non)equality operators do. Specifically they do not allow - # local versions to be specified nor do they allow the prefix - # matching wild cards. - (?=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - "===": "arbitrary", - } - - @_require_version_compare - def _compare_compatible(self, prospective: ParsedVersion, spec: str) -> bool: - - # Compatible releases have an equivalent combination of >= and ==. That - # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to - # implement this in terms of the other specifiers instead of - # implementing it ourselves. The only thing we need to do is construct - # the other specifiers. - - # We want everything but the last item in the version, but we want to - # ignore suffix segments. - prefix = ".".join( - list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1] - ) - - # Add the prefix notation to the end of our string - prefix += ".*" - - return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( - prospective, prefix - ) - - @_require_version_compare - def _compare_equal(self, prospective: ParsedVersion, spec: str) -> bool: - - # We need special logic to handle prefix matching - if spec.endswith(".*"): - # In the case of prefix matching we want to ignore local segment. - prospective = Version(prospective.public) - # Split the spec out by dots, and pretend that there is an implicit - # dot in between a release segment and a pre-release segment. - split_spec = _version_split(spec[:-2]) # Remove the trailing .* - - # Split the prospective version out by dots, and pretend that there - # is an implicit dot in between a release segment and a pre-release - # segment. - split_prospective = _version_split(str(prospective)) - - # Shorten the prospective version to be the same length as the spec - # so that we can determine if the specifier is a prefix of the - # prospective version or not. - shortened_prospective = split_prospective[: len(split_spec)] - - # Pad out our two sides with zeros so that they both equal the same - # length. - padded_spec, padded_prospective = _pad_version( - split_spec, shortened_prospective - ) - - return padded_prospective == padded_spec - else: - # Convert our spec string into a Version - spec_version = Version(spec) - - # If the specifier does not have a local segment, then we want to - # act as if the prospective version also does not have a local - # segment. - if not spec_version.local: - prospective = Version(prospective.public) - - return prospective == spec_version - - @_require_version_compare - def _compare_not_equal(self, prospective: ParsedVersion, spec: str) -> bool: - return not self._compare_equal(prospective, spec) - - @_require_version_compare - def _compare_less_than_equal(self, prospective: ParsedVersion, spec: str) -> bool: - - # NB: Local version identifiers are NOT permitted in the version - # specifier, so local version labels can be universally removed from - # the prospective version. - return Version(prospective.public) <= Version(spec) - - @_require_version_compare - def _compare_greater_than_equal( - self, prospective: ParsedVersion, spec: str - ) -> bool: - - # NB: Local version identifiers are NOT permitted in the version - # specifier, so local version labels can be universally removed from - # the prospective version. - return Version(prospective.public) >= Version(spec) - - @_require_version_compare - def _compare_less_than(self, prospective: ParsedVersion, spec_str: str) -> bool: - - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec_str) - - # Check to see if the prospective version is less than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective < spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a pre-release version, that we do not accept pre-release - # versions for the version mentioned in the specifier (e.g. <3.1 should - # not match 3.1.dev0, but should match 3.0.dev0). - if not spec.is_prerelease and prospective.is_prerelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # less than the spec version *and* it's not a pre-release of the same - # version in the spec. - return True - - @_require_version_compare - def _compare_greater_than(self, prospective: ParsedVersion, spec_str: str) -> bool: - - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec_str) - - # Check to see if the prospective version is greater than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective > spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a post-release version, that we do not accept - # post-release versions for the version mentioned in the specifier - # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). - if not spec.is_postrelease and prospective.is_postrelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # Ensure that we do not allow a local version of the version mentioned - # in the specifier, which is technically greater than, to match. - if prospective.local is not None: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # greater than the spec version *and* it's not a pre-release of the - # same version in the spec. - return True - - def _compare_arbitrary(self, prospective: Version, spec: str) -> bool: - return str(prospective).lower() == str(spec).lower() - - @property - def prereleases(self) -> bool: - - # If there is an explicit prereleases set for this, then we'll just - # blindly use that. - if self._prereleases is not None: - return self._prereleases - - # Look at all of our specifiers and determine if they are inclusive - # operators, and if they are if they are including an explicit - # prerelease. - operator, version = self._spec - if operator in ["==", ">=", "<=", "~=", "==="]: - # The == specifier can include a trailing .*, if it does we - # want to remove before parsing. - if operator == "==" and version.endswith(".*"): - version = version[:-2] - - # Parse the version, and if it is a pre-release than this - # specifier allows pre-releases. - if parse(version).is_prerelease: - return True - - return False - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - -_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") - - -def _version_split(version: str) -> List[str]: - result: List[str] = [] - for item in version.split("."): - match = _prefix_regex.search(item) - if match: - result.extend(match.groups()) - else: - result.append(item) - return result - - -def _is_not_suffix(segment: str) -> bool: - return not any( - segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post") - ) - - -def _pad_version(left: List[str], right: List[str]) -> Tuple[List[str], List[str]]: - left_split, right_split = [], [] - - # Get the release segment of our versions - left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) - right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) - - # Get the rest of our versions - left_split.append(left[len(left_split[0]) :]) - right_split.append(right[len(right_split[0]) :]) - - # Insert our padding - left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) - right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) - - return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split))) - - -class SpecifierSet(BaseSpecifier): - def __init__( - self, specifiers: str = "", prereleases: Optional[bool] = None - ) -> None: - - # Split on , to break each individual specifier into it's own item, and - # strip each item to remove leading/trailing whitespace. - split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] - - # Parsed each individual specifier, attempting first to make it a - # Specifier and falling back to a LegacySpecifier. - parsed: Set[_IndividualSpecifier] = set() - for specifier in split_specifiers: - try: - parsed.add(Specifier(specifier)) - except InvalidSpecifier: - parsed.add(LegacySpecifier(specifier)) - - # Turn our parsed specifiers into a frozen set and save them for later. - self._specs = frozenset(parsed) - - # Store our prereleases value so we can use it later to determine if - # we accept prereleases or not. - self._prereleases = prereleases - - def __repr__(self) -> str: - pre = ( - f", prereleases={self.prereleases!r}" - if self._prereleases is not None - else "" - ) - - return f"" - - def __str__(self) -> str: - return ",".join(sorted(str(s) for s in self._specs)) - - def __hash__(self) -> int: - return hash(self._specs) - - def __and__(self, other: Union["SpecifierSet", str]) -> "SpecifierSet": - if isinstance(other, str): - other = SpecifierSet(other) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - specifier = SpecifierSet() - specifier._specs = frozenset(self._specs | other._specs) - - if self._prereleases is None and other._prereleases is not None: - specifier._prereleases = other._prereleases - elif self._prereleases is not None and other._prereleases is None: - specifier._prereleases = self._prereleases - elif self._prereleases == other._prereleases: - specifier._prereleases = self._prereleases - else: - raise ValueError( - "Cannot combine SpecifierSets with True and False prerelease " - "overrides." - ) - - return specifier - - def __eq__(self, other: object) -> bool: - if isinstance(other, (str, _IndividualSpecifier)): - other = SpecifierSet(str(other)) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - return self._specs == other._specs - - def __len__(self) -> int: - return len(self._specs) - - def __iter__(self) -> Iterator[_IndividualSpecifier]: - return iter(self._specs) - - @property - def prereleases(self) -> Optional[bool]: - - # If we have been given an explicit prerelease modifier, then we'll - # pass that through here. - if self._prereleases is not None: - return self._prereleases - - # If we don't have any specifiers, and we don't have a forced value, - # then we'll just return None since we don't know if this should have - # pre-releases or not. - if not self._specs: - return None - - # Otherwise we'll see if any of the given specifiers accept - # prereleases, if any of them do we'll return True, otherwise False. - return any(s.prereleases for s in self._specs) - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - def __contains__(self, item: UnparsedVersion) -> bool: - return self.contains(item) - - def contains( - self, item: UnparsedVersion, prereleases: Optional[bool] = None - ) -> bool: - - # Ensure that our item is a Version or LegacyVersion instance. - if not isinstance(item, (LegacyVersion, Version)): - item = parse(item) - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # We can determine if we're going to allow pre-releases by looking to - # see if any of the underlying items supports them. If none of them do - # and this item is a pre-release then we do not allow it and we can - # short circuit that here. - # Note: This means that 1.0.dev1 would not be contained in something - # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 - if not prereleases and item.is_prerelease: - return False - - # We simply dispatch to the underlying specs here to make sure that the - # given version is contained within all of them. - # Note: This use of all() here means that an empty set of specifiers - # will always return True, this is an explicit design decision. - return all(s.contains(item, prereleases=prereleases) for s in self._specs) - - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # If we have any specifiers, then we want to wrap our iterable in the - # filter method for each one, this will act as a logical AND amongst - # each specifier. - if self._specs: - for spec in self._specs: - iterable = spec.filter(iterable, prereleases=bool(prereleases)) - return iterable - # If we do not have any specifiers, then we need to have a rough filter - # which will filter out any pre-releases, unless there are no final - # releases, and which will filter out LegacyVersion in general. - else: - filtered: List[VersionTypeVar] = [] - found_prereleases: List[VersionTypeVar] = [] - - item: UnparsedVersion - parsed_version: Union[Version, LegacyVersion] - - for item in iterable: - # Ensure that we some kind of Version class for this item. - if not isinstance(item, (LegacyVersion, Version)): - parsed_version = parse(item) - else: - parsed_version = item - - # Filter out any item which is parsed as a LegacyVersion - if isinstance(parsed_version, LegacyVersion): - continue - - # Store any item which is a pre-release for later unless we've - # already found a final version or we are accepting prereleases - if parsed_version.is_prerelease and not prereleases: - if not filtered: - found_prereleases.append(item) - else: - filtered.append(item) - - # If we've found no items except for pre-releases, then we'll go - # ahead and use the pre-releases - if not filtered and found_prereleases and prereleases is None: - return found_prereleases - - return filtered diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/tags.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/tags.py deleted file mode 100755 index 9a3d25a..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/tags.py +++ /dev/null @@ -1,487 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import logging -import platform -import sys -import sysconfig -from importlib.machinery import EXTENSION_SUFFIXES -from typing import ( - Dict, - FrozenSet, - Iterable, - Iterator, - List, - Optional, - Sequence, - Tuple, - Union, - cast, -) - -from . import _manylinux, _musllinux - -logger = logging.getLogger(__name__) - -PythonVersion = Sequence[int] -MacVersion = Tuple[int, int] - -INTERPRETER_SHORT_NAMES: Dict[str, str] = { - "python": "py", # Generic. - "cpython": "cp", - "pypy": "pp", - "ironpython": "ip", - "jython": "jy", -} - - -_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32 - - -class Tag: - """ - A representation of the tag triple for a wheel. - - Instances are considered immutable and thus are hashable. Equality checking - is also supported. - """ - - __slots__ = ["_interpreter", "_abi", "_platform", "_hash"] - - def __init__(self, interpreter: str, abi: str, platform: str) -> None: - self._interpreter = interpreter.lower() - self._abi = abi.lower() - self._platform = platform.lower() - # The __hash__ of every single element in a Set[Tag] will be evaluated each time - # that a set calls its `.disjoint()` method, which may be called hundreds of - # times when scanning a page of links for packages with tags matching that - # Set[Tag]. Pre-computing the value here produces significant speedups for - # downstream consumers. - self._hash = hash((self._interpreter, self._abi, self._platform)) - - @property - def interpreter(self) -> str: - return self._interpreter - - @property - def abi(self) -> str: - return self._abi - - @property - def platform(self) -> str: - return self._platform - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Tag): - return NotImplemented - - return ( - (self._hash == other._hash) # Short-circuit ASAP for perf reasons. - and (self._platform == other._platform) - and (self._abi == other._abi) - and (self._interpreter == other._interpreter) - ) - - def __hash__(self) -> int: - return self._hash - - def __str__(self) -> str: - return f"{self._interpreter}-{self._abi}-{self._platform}" - - def __repr__(self) -> str: - return f"<{self} @ {id(self)}>" - - -def parse_tag(tag: str) -> FrozenSet[Tag]: - """ - Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances. - - Returning a set is required due to the possibility that the tag is a - compressed tag set. - """ - tags = set() - interpreters, abis, platforms = tag.split("-") - for interpreter in interpreters.split("."): - for abi in abis.split("."): - for platform_ in platforms.split("."): - tags.add(Tag(interpreter, abi, platform_)) - return frozenset(tags) - - -def _get_config_var(name: str, warn: bool = False) -> Union[int, str, None]: - value = sysconfig.get_config_var(name) - if value is None and warn: - logger.debug( - "Config variable '%s' is unset, Python ABI tag may be incorrect", name - ) - return value - - -def _normalize_string(string: str) -> str: - return string.replace(".", "_").replace("-", "_") - - -def _abi3_applies(python_version: PythonVersion) -> bool: - """ - Determine if the Python version supports abi3. - - PEP 384 was first implemented in Python 3.2. - """ - return len(python_version) > 1 and tuple(python_version) >= (3, 2) - - -def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> List[str]: - py_version = tuple(py_version) # To allow for version comparison. - abis = [] - version = _version_nodot(py_version[:2]) - debug = pymalloc = ucs4 = "" - with_debug = _get_config_var("Py_DEBUG", warn) - has_refcount = hasattr(sys, "gettotalrefcount") - # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled - # extension modules is the best option. - # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 - has_ext = "_d.pyd" in EXTENSION_SUFFIXES - if with_debug or (with_debug is None and (has_refcount or has_ext)): - debug = "d" - if py_version < (3, 8): - with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) - if with_pymalloc or with_pymalloc is None: - pymalloc = "m" - if py_version < (3, 3): - unicode_size = _get_config_var("Py_UNICODE_SIZE", warn) - if unicode_size == 4 or ( - unicode_size is None and sys.maxunicode == 0x10FFFF - ): - ucs4 = "u" - elif debug: - # Debug builds can also load "normal" extension modules. - # We can also assume no UCS-4 or pymalloc requirement. - abis.append(f"cp{version}") - abis.insert( - 0, - "cp{version}{debug}{pymalloc}{ucs4}".format( - version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4 - ), - ) - return abis - - -def cpython_tags( - python_version: Optional[PythonVersion] = None, - abis: Optional[Iterable[str]] = None, - platforms: Optional[Iterable[str]] = None, - *, - warn: bool = False, -) -> Iterator[Tag]: - """ - Yields the tags for a CPython interpreter. - - The tags consist of: - - cp-- - - cp-abi3- - - cp-none- - - cp-abi3- # Older Python versions down to 3.2. - - If python_version only specifies a major version then user-provided ABIs and - the 'none' ABItag will be used. - - If 'abi3' or 'none' are specified in 'abis' then they will be yielded at - their normal position and not at the beginning. - """ - if not python_version: - python_version = sys.version_info[:2] - - interpreter = f"cp{_version_nodot(python_version[:2])}" - - if abis is None: - if len(python_version) > 1: - abis = _cpython_abis(python_version, warn) - else: - abis = [] - abis = list(abis) - # 'abi3' and 'none' are explicitly handled later. - for explicit_abi in ("abi3", "none"): - try: - abis.remove(explicit_abi) - except ValueError: - pass - - platforms = list(platforms or platform_tags()) - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - if _abi3_applies(python_version): - yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms) - yield from (Tag(interpreter, "none", platform_) for platform_ in platforms) - - if _abi3_applies(python_version): - for minor_version in range(python_version[1] - 1, 1, -1): - for platform_ in platforms: - interpreter = "cp{version}".format( - version=_version_nodot((python_version[0], minor_version)) - ) - yield Tag(interpreter, "abi3", platform_) - - -def _generic_abi() -> Iterator[str]: - abi = sysconfig.get_config_var("SOABI") - if abi: - yield _normalize_string(abi) - - -def generic_tags( - interpreter: Optional[str] = None, - abis: Optional[Iterable[str]] = None, - platforms: Optional[Iterable[str]] = None, - *, - warn: bool = False, -) -> Iterator[Tag]: - """ - Yields the tags for a generic interpreter. - - The tags consist of: - - -- - - The "none" ABI will be added if it was not explicitly provided. - """ - if not interpreter: - interp_name = interpreter_name() - interp_version = interpreter_version(warn=warn) - interpreter = "".join([interp_name, interp_version]) - if abis is None: - abis = _generic_abi() - platforms = list(platforms or platform_tags()) - abis = list(abis) - if "none" not in abis: - abis.append("none") - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - - -def _py_interpreter_range(py_version: PythonVersion) -> Iterator[str]: - """ - Yields Python versions in descending order. - - After the latest version, the major-only version will be yielded, and then - all previous versions of that major version. - """ - if len(py_version) > 1: - yield f"py{_version_nodot(py_version[:2])}" - yield f"py{py_version[0]}" - if len(py_version) > 1: - for minor in range(py_version[1] - 1, -1, -1): - yield f"py{_version_nodot((py_version[0], minor))}" - - -def compatible_tags( - python_version: Optional[PythonVersion] = None, - interpreter: Optional[str] = None, - platforms: Optional[Iterable[str]] = None, -) -> Iterator[Tag]: - """ - Yields the sequence of tags that are compatible with a specific version of Python. - - The tags consist of: - - py*-none- - - -none-any # ... if `interpreter` is provided. - - py*-none-any - """ - if not python_version: - python_version = sys.version_info[:2] - platforms = list(platforms or platform_tags()) - for version in _py_interpreter_range(python_version): - for platform_ in platforms: - yield Tag(version, "none", platform_) - if interpreter: - yield Tag(interpreter, "none", "any") - for version in _py_interpreter_range(python_version): - yield Tag(version, "none", "any") - - -def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str: - if not is_32bit: - return arch - - if arch.startswith("ppc"): - return "ppc" - - return "i386" - - -def _mac_binary_formats(version: MacVersion, cpu_arch: str) -> List[str]: - formats = [cpu_arch] - if cpu_arch == "x86_64": - if version < (10, 4): - return [] - formats.extend(["intel", "fat64", "fat32"]) - - elif cpu_arch == "i386": - if version < (10, 4): - return [] - formats.extend(["intel", "fat32", "fat"]) - - elif cpu_arch == "ppc64": - # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? - if version > (10, 5) or version < (10, 4): - return [] - formats.append("fat64") - - elif cpu_arch == "ppc": - if version > (10, 6): - return [] - formats.extend(["fat32", "fat"]) - - if cpu_arch in {"arm64", "x86_64"}: - formats.append("universal2") - - if cpu_arch in {"x86_64", "i386", "ppc64", "ppc", "intel"}: - formats.append("universal") - - return formats - - -def mac_platforms( - version: Optional[MacVersion] = None, arch: Optional[str] = None -) -> Iterator[str]: - """ - Yields the platform tags for a macOS system. - - The `version` parameter is a two-item tuple specifying the macOS version to - generate platform tags for. The `arch` parameter is the CPU architecture to - generate platform tags for. Both parameters default to the appropriate value - for the current system. - """ - version_str, _, cpu_arch = platform.mac_ver() - if version is None: - version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2]))) - else: - version = version - if arch is None: - arch = _mac_arch(cpu_arch) - else: - arch = arch - - if (10, 0) <= version and version < (11, 0): - # Prior to Mac OS 11, each yearly release of Mac OS bumped the - # "minor" version number. The major version was always 10. - for minor_version in range(version[1], -1, -1): - compat_version = 10, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=10, minor=minor_version, binary_format=binary_format - ) - - if version >= (11, 0): - # Starting with Mac OS 11, each yearly release bumps the major version - # number. The minor versions are now the midyear updates. - for major_version in range(version[0], 10, -1): - compat_version = major_version, 0 - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=major_version, minor=0, binary_format=binary_format - ) - - if version >= (11, 0): - # Mac OS 11 on x86_64 is compatible with binaries from previous releases. - # Arm64 support was introduced in 11.0, so no Arm binaries from previous - # releases exist. - # - # However, the "universal2" binary format can have a - # macOS version earlier than 11.0 when the x86_64 part of the binary supports - # that version of macOS. - if arch == "x86_64": - for minor_version in range(16, 3, -1): - compat_version = 10, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=compat_version[0], - minor=compat_version[1], - binary_format=binary_format, - ) - else: - for minor_version in range(16, 3, -1): - compat_version = 10, minor_version - binary_format = "universal2" - yield "macosx_{major}_{minor}_{binary_format}".format( - major=compat_version[0], - minor=compat_version[1], - binary_format=binary_format, - ) - - -def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]: - linux = _normalize_string(sysconfig.get_platform()) - if is_32bit: - if linux == "linux_x86_64": - linux = "linux_i686" - elif linux == "linux_aarch64": - linux = "linux_armv7l" - _, arch = linux.split("_", 1) - yield from _manylinux.platform_tags(linux, arch) - yield from _musllinux.platform_tags(arch) - yield linux - - -def _generic_platforms() -> Iterator[str]: - yield _normalize_string(sysconfig.get_platform()) - - -def platform_tags() -> Iterator[str]: - """ - Provides the platform tags for this installation. - """ - if platform.system() == "Darwin": - return mac_platforms() - elif platform.system() == "Linux": - return _linux_platforms() - else: - return _generic_platforms() - - -def interpreter_name() -> str: - """ - Returns the name of the running interpreter. - """ - name = sys.implementation.name - return INTERPRETER_SHORT_NAMES.get(name) or name - - -def interpreter_version(*, warn: bool = False) -> str: - """ - Returns the version of the running interpreter. - """ - version = _get_config_var("py_version_nodot", warn=warn) - if version: - version = str(version) - else: - version = _version_nodot(sys.version_info[:2]) - return version - - -def _version_nodot(version: PythonVersion) -> str: - return "".join(map(str, version)) - - -def sys_tags(*, warn: bool = False) -> Iterator[Tag]: - """ - Returns the sequence of tag triples for the running interpreter. - - The order of the sequence corresponds to priority order for the - interpreter, from most to least important. - """ - - interp_name = interpreter_name() - if interp_name == "cp": - yield from cpython_tags(warn=warn) - else: - yield from generic_tags() - - if interp_name == "pp": - yield from compatible_tags(interpreter="pp3") - else: - yield from compatible_tags() diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/utils.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/utils.py deleted file mode 100755 index bab11b8..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/utils.py +++ /dev/null @@ -1,136 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import re -from typing import FrozenSet, NewType, Tuple, Union, cast - -from .tags import Tag, parse_tag -from .version import InvalidVersion, Version - -BuildTag = Union[Tuple[()], Tuple[int, str]] -NormalizedName = NewType("NormalizedName", str) - - -class InvalidWheelFilename(ValueError): - """ - An invalid wheel filename was found, users should refer to PEP 427. - """ - - -class InvalidSdistFilename(ValueError): - """ - An invalid sdist filename was found, users should refer to the packaging user guide. - """ - - -_canonicalize_regex = re.compile(r"[-_.]+") -# PEP 427: The build number must start with a digit. -_build_tag_regex = re.compile(r"(\d+)(.*)") - - -def canonicalize_name(name: str) -> NormalizedName: - # This is taken from PEP 503. - value = _canonicalize_regex.sub("-", name).lower() - return cast(NormalizedName, value) - - -def canonicalize_version(version: Union[Version, str]) -> str: - """ - This is very similar to Version.__str__, but has one subtle difference - with the way it handles the release segment. - """ - if isinstance(version, str): - try: - parsed = Version(version) - except InvalidVersion: - # Legacy versions cannot be normalized - return version - else: - parsed = version - - parts = [] - - # Epoch - if parsed.epoch != 0: - parts.append(f"{parsed.epoch}!") - - # Release segment - # NB: This strips trailing '.0's to normalize - parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in parsed.release))) - - # Pre-release - if parsed.pre is not None: - parts.append("".join(str(x) for x in parsed.pre)) - - # Post-release - if parsed.post is not None: - parts.append(f".post{parsed.post}") - - # Development release - if parsed.dev is not None: - parts.append(f".dev{parsed.dev}") - - # Local version segment - if parsed.local is not None: - parts.append(f"+{parsed.local}") - - return "".join(parts) - - -def parse_wheel_filename( - filename: str, -) -> Tuple[NormalizedName, Version, BuildTag, FrozenSet[Tag]]: - if not filename.endswith(".whl"): - raise InvalidWheelFilename( - f"Invalid wheel filename (extension must be '.whl'): {filename}" - ) - - filename = filename[:-4] - dashes = filename.count("-") - if dashes not in (4, 5): - raise InvalidWheelFilename( - f"Invalid wheel filename (wrong number of parts): {filename}" - ) - - parts = filename.split("-", dashes - 2) - name_part = parts[0] - # See PEP 427 for the rules on escaping the project name - if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None: - raise InvalidWheelFilename(f"Invalid project name: {filename}") - name = canonicalize_name(name_part) - version = Version(parts[1]) - if dashes == 5: - build_part = parts[2] - build_match = _build_tag_regex.match(build_part) - if build_match is None: - raise InvalidWheelFilename( - f"Invalid build number: {build_part} in '{filename}'" - ) - build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2))) - else: - build = () - tags = parse_tag(parts[-1]) - return (name, version, build, tags) - - -def parse_sdist_filename(filename: str) -> Tuple[NormalizedName, Version]: - if filename.endswith(".tar.gz"): - file_stem = filename[: -len(".tar.gz")] - elif filename.endswith(".zip"): - file_stem = filename[: -len(".zip")] - else: - raise InvalidSdistFilename( - f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):" - f" {filename}" - ) - - # We are requiring a PEP 440 version, which cannot contain dashes, - # so we split on the last dash. - name_part, sep, version_part = file_stem.rpartition("-") - if not sep: - raise InvalidSdistFilename(f"Invalid sdist filename: {filename}") - - name = canonicalize_name(name_part) - version = Version(version_part) - return (name, version) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/version.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/version.py deleted file mode 100755 index de9a09a..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/version.py +++ /dev/null @@ -1,504 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import collections -import itertools -import re -import warnings -from typing import Callable, Iterator, List, Optional, SupportsInt, Tuple, Union - -from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType - -__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"] - -InfiniteTypes = Union[InfinityType, NegativeInfinityType] -PrePostDevType = Union[InfiniteTypes, Tuple[str, int]] -SubLocalType = Union[InfiniteTypes, int, str] -LocalType = Union[ - NegativeInfinityType, - Tuple[ - Union[ - SubLocalType, - Tuple[SubLocalType, str], - Tuple[NegativeInfinityType, SubLocalType], - ], - ..., - ], -] -CmpKey = Tuple[ - int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType -] -LegacyCmpKey = Tuple[int, Tuple[str, ...]] -VersionComparisonMethod = Callable[ - [Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool -] - -_Version = collections.namedtuple( - "_Version", ["epoch", "release", "dev", "pre", "post", "local"] -) - - -def parse(version: str) -> Union["LegacyVersion", "Version"]: - """ - Parse the given version string and return either a :class:`Version` object - or a :class:`LegacyVersion` object depending on if the given version is - a valid PEP 440 version or a legacy version. - """ - try: - return Version(version) - except InvalidVersion: - return LegacyVersion(version) - - -class InvalidVersion(ValueError): - """ - An invalid version was found, users should refer to PEP 440. - """ - - -class _BaseVersion: - _key: Union[CmpKey, LegacyCmpKey] - - def __hash__(self) -> int: - return hash(self._key) - - # Please keep the duplicated `isinstance` check - # in the six comparisons hereunder - # unless you find a way to avoid adding overhead function calls. - def __lt__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key < other._key - - def __le__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key <= other._key - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key == other._key - - def __ge__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key >= other._key - - def __gt__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key > other._key - - def __ne__(self, other: object) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key != other._key - - -class LegacyVersion(_BaseVersion): - def __init__(self, version: str) -> None: - self._version = str(version) - self._key = _legacy_cmpkey(self._version) - - warnings.warn( - "Creating a LegacyVersion has been deprecated and will be " - "removed in the next major release", - DeprecationWarning, - ) - - def __str__(self) -> str: - return self._version - - def __repr__(self) -> str: - return f"" - - @property - def public(self) -> str: - return self._version - - @property - def base_version(self) -> str: - return self._version - - @property - def epoch(self) -> int: - return -1 - - @property - def release(self) -> None: - return None - - @property - def pre(self) -> None: - return None - - @property - def post(self) -> None: - return None - - @property - def dev(self) -> None: - return None - - @property - def local(self) -> None: - return None - - @property - def is_prerelease(self) -> bool: - return False - - @property - def is_postrelease(self) -> bool: - return False - - @property - def is_devrelease(self) -> bool: - return False - - -_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE) - -_legacy_version_replacement_map = { - "pre": "c", - "preview": "c", - "-": "final-", - "rc": "c", - "dev": "@", -} - - -def _parse_version_parts(s: str) -> Iterator[str]: - for part in _legacy_version_component_re.split(s): - part = _legacy_version_replacement_map.get(part, part) - - if not part or part == ".": - continue - - if part[:1] in "0123456789": - # pad for numeric comparison - yield part.zfill(8) - else: - yield "*" + part - - # ensure that alpha/beta/candidate are before final - yield "*final" - - -def _legacy_cmpkey(version: str) -> LegacyCmpKey: - - # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch - # greater than or equal to 0. This will effectively put the LegacyVersion, - # which uses the defacto standard originally implemented by setuptools, - # as before all PEP 440 versions. - epoch = -1 - - # This scheme is taken from pkg_resources.parse_version setuptools prior to - # it's adoption of the packaging library. - parts: List[str] = [] - for part in _parse_version_parts(version.lower()): - if part.startswith("*"): - # remove "-" before a prerelease tag - if part < "*final": - while parts and parts[-1] == "*final-": - parts.pop() - - # remove trailing zeros from each series of numeric parts - while parts and parts[-1] == "00000000": - parts.pop() - - parts.append(part) - - return epoch, tuple(parts) - - -# Deliberately not anchored to the start and end of the string, to make it -# easier for 3rd party code to reuse -VERSION_PATTERN = r""" - v? - (?: - (?:(?P[0-9]+)!)? # epoch - (?P[0-9]+(?:\.[0-9]+)*) # release segment - (?P
                                          # pre-release
-            [-_\.]?
-            (?P(a|b|c|rc|alpha|beta|pre|preview))
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-        (?P                                         # post release
-            (?:-(?P[0-9]+))
-            |
-            (?:
-                [-_\.]?
-                (?Ppost|rev|r)
-                [-_\.]?
-                (?P[0-9]+)?
-            )
-        )?
-        (?P                                          # dev release
-            [-_\.]?
-            (?Pdev)
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-    )
-    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
-"""
-
-
-class Version(_BaseVersion):
-
-    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
-
-    def __init__(self, version: str) -> None:
-
-        # Validate the version and parse it into pieces
-        match = self._regex.search(version)
-        if not match:
-            raise InvalidVersion(f"Invalid version: '{version}'")
-
-        # Store the parsed out pieces of the version
-        self._version = _Version(
-            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
-            release=tuple(int(i) for i in match.group("release").split(".")),
-            pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
-            post=_parse_letter_version(
-                match.group("post_l"), match.group("post_n1") or match.group("post_n2")
-            ),
-            dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
-            local=_parse_local_version(match.group("local")),
-        )
-
-        # Generate a key which will be used for sorting
-        self._key = _cmpkey(
-            self._version.epoch,
-            self._version.release,
-            self._version.pre,
-            self._version.post,
-            self._version.dev,
-            self._version.local,
-        )
-
-    def __repr__(self) -> str:
-        return f""
-
-    def __str__(self) -> str:
-        parts = []
-
-        # Epoch
-        if self.epoch != 0:
-            parts.append(f"{self.epoch}!")
-
-        # Release segment
-        parts.append(".".join(str(x) for x in self.release))
-
-        # Pre-release
-        if self.pre is not None:
-            parts.append("".join(str(x) for x in self.pre))
-
-        # Post-release
-        if self.post is not None:
-            parts.append(f".post{self.post}")
-
-        # Development release
-        if self.dev is not None:
-            parts.append(f".dev{self.dev}")
-
-        # Local version segment
-        if self.local is not None:
-            parts.append(f"+{self.local}")
-
-        return "".join(parts)
-
-    @property
-    def epoch(self) -> int:
-        _epoch: int = self._version.epoch
-        return _epoch
-
-    @property
-    def release(self) -> Tuple[int, ...]:
-        _release: Tuple[int, ...] = self._version.release
-        return _release
-
-    @property
-    def pre(self) -> Optional[Tuple[str, int]]:
-        _pre: Optional[Tuple[str, int]] = self._version.pre
-        return _pre
-
-    @property
-    def post(self) -> Optional[int]:
-        return self._version.post[1] if self._version.post else None
-
-    @property
-    def dev(self) -> Optional[int]:
-        return self._version.dev[1] if self._version.dev else None
-
-    @property
-    def local(self) -> Optional[str]:
-        if self._version.local:
-            return ".".join(str(x) for x in self._version.local)
-        else:
-            return None
-
-    @property
-    def public(self) -> str:
-        return str(self).split("+", 1)[0]
-
-    @property
-    def base_version(self) -> str:
-        parts = []
-
-        # Epoch
-        if self.epoch != 0:
-            parts.append(f"{self.epoch}!")
-
-        # Release segment
-        parts.append(".".join(str(x) for x in self.release))
-
-        return "".join(parts)
-
-    @property
-    def is_prerelease(self) -> bool:
-        return self.dev is not None or self.pre is not None
-
-    @property
-    def is_postrelease(self) -> bool:
-        return self.post is not None
-
-    @property
-    def is_devrelease(self) -> bool:
-        return self.dev is not None
-
-    @property
-    def major(self) -> int:
-        return self.release[0] if len(self.release) >= 1 else 0
-
-    @property
-    def minor(self) -> int:
-        return self.release[1] if len(self.release) >= 2 else 0
-
-    @property
-    def micro(self) -> int:
-        return self.release[2] if len(self.release) >= 3 else 0
-
-
-def _parse_letter_version(
-    letter: str, number: Union[str, bytes, SupportsInt]
-) -> Optional[Tuple[str, int]]:
-
-    if letter:
-        # We consider there to be an implicit 0 in a pre-release if there is
-        # not a numeral associated with it.
-        if number is None:
-            number = 0
-
-        # We normalize any letters to their lower case form
-        letter = letter.lower()
-
-        # We consider some words to be alternate spellings of other words and
-        # in those cases we want to normalize the spellings to our preferred
-        # spelling.
-        if letter == "alpha":
-            letter = "a"
-        elif letter == "beta":
-            letter = "b"
-        elif letter in ["c", "pre", "preview"]:
-            letter = "rc"
-        elif letter in ["rev", "r"]:
-            letter = "post"
-
-        return letter, int(number)
-    if not letter and number:
-        # We assume if we are given a number, but we are not given a letter
-        # then this is using the implicit post release syntax (e.g. 1.0-1)
-        letter = "post"
-
-        return letter, int(number)
-
-    return None
-
-
-_local_version_separators = re.compile(r"[\._-]")
-
-
-def _parse_local_version(local: str) -> Optional[LocalType]:
-    """
-    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
-    """
-    if local is not None:
-        return tuple(
-            part.lower() if not part.isdigit() else int(part)
-            for part in _local_version_separators.split(local)
-        )
-    return None
-
-
-def _cmpkey(
-    epoch: int,
-    release: Tuple[int, ...],
-    pre: Optional[Tuple[str, int]],
-    post: Optional[Tuple[str, int]],
-    dev: Optional[Tuple[str, int]],
-    local: Optional[Tuple[SubLocalType]],
-) -> CmpKey:
-
-    # When we compare a release version, we want to compare it with all of the
-    # trailing zeros removed. So we'll use a reverse the list, drop all the now
-    # leading zeros until we come to something non zero, then take the rest
-    # re-reverse it back into the correct order and make it a tuple and use
-    # that for our sorting key.
-    _release = tuple(
-        reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
-    )
-
-    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
-    # We'll do this by abusing the pre segment, but we _only_ want to do this
-    # if there is not a pre or a post segment. If we have one of those then
-    # the normal sorting rules will handle this case correctly.
-    if pre is None and post is None and dev is not None:
-        _pre: PrePostDevType = NegativeInfinity
-    # Versions without a pre-release (except as noted above) should sort after
-    # those with one.
-    elif pre is None:
-        _pre = Infinity
-    else:
-        _pre = pre
-
-    # Versions without a post segment should sort before those with one.
-    if post is None:
-        _post: PrePostDevType = NegativeInfinity
-
-    else:
-        _post = post
-
-    # Versions without a development segment should sort after those with one.
-    if dev is None:
-        _dev: PrePostDevType = Infinity
-
-    else:
-        _dev = dev
-
-    if local is None:
-        # Versions without a local segment should sort before those with one.
-        _local: LocalType = NegativeInfinity
-    else:
-        # Versions with a local segment need that segment parsed to implement
-        # the sorting rules in PEP440.
-        # - Alpha numeric segments sort before numeric segments
-        # - Alpha numeric segments sort lexicographically
-        # - Numeric segments sort numerically
-        # - Shorter versions sort before longer versions when the prefixes
-        #   match exactly
-        _local = tuple(
-            (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
-        )
-
-    return epoch, _release, _pre, _post, _dev, _local
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__init__.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__init__.py
deleted file mode 100755
index 7802ff1..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__init__.py
+++ /dev/null
@@ -1,331 +0,0 @@
-# module pyparsing.py
-#
-# Copyright (c) 2003-2022  Paul T. McGuire
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__doc__ = """
-pyparsing module - Classes and methods to define and execute parsing grammars
-=============================================================================
-
-The pyparsing module is an alternative approach to creating and
-executing simple grammars, vs. the traditional lex/yacc approach, or the
-use of regular expressions.  With pyparsing, you don't need to learn
-a new syntax for defining grammars or matching expressions - the parsing
-module provides a library of classes that you use to construct the
-grammar directly in Python.
-
-Here is a program to parse "Hello, World!" (or any greeting of the form
-``", !"``), built up using :class:`Word`,
-:class:`Literal`, and :class:`And` elements
-(the :meth:`'+'` operators create :class:`And` expressions,
-and the strings are auto-converted to :class:`Literal` expressions)::
-
-    from pyparsing import Word, alphas
-
-    # define grammar of a greeting
-    greet = Word(alphas) + "," + Word(alphas) + "!"
-
-    hello = "Hello, World!"
-    print(hello, "->", greet.parse_string(hello))
-
-The program outputs the following::
-
-    Hello, World! -> ['Hello', ',', 'World', '!']
-
-The Python representation of the grammar is quite readable, owing to the
-self-explanatory class names, and the use of :class:`'+'`,
-:class:`'|'`, :class:`'^'` and :class:`'&'` operators.
-
-The :class:`ParseResults` object returned from
-:class:`ParserElement.parseString` can be
-accessed as a nested list, a dictionary, or an object with named
-attributes.
-
-The pyparsing module handles some of the problems that are typically
-vexing when writing text parsers:
-
-  - extra or missing whitespace (the above program will also handle
-    "Hello,World!", "Hello  ,  World  !", etc.)
-  - quoted strings
-  - embedded comments
-
-
-Getting Started -
------------------
-Visit the classes :class:`ParserElement` and :class:`ParseResults` to
-see the base classes that most other pyparsing
-classes inherit from. Use the docstrings for examples of how to:
-
- - construct literal match expressions from :class:`Literal` and
-   :class:`CaselessLiteral` classes
- - construct character word-group expressions using the :class:`Word`
-   class
- - see how to create repetitive expressions using :class:`ZeroOrMore`
-   and :class:`OneOrMore` classes
- - use :class:`'+'`, :class:`'|'`, :class:`'^'`,
-   and :class:`'&'` operators to combine simple expressions into
-   more complex ones
- - associate names with your parsed results using
-   :class:`ParserElement.setResultsName`
- - access the parsed data, which is returned as a :class:`ParseResults`
-   object
- - find some helpful expression short-cuts like :class:`delimitedList`
-   and :class:`oneOf`
- - find more useful common expressions in the :class:`pyparsing_common`
-   namespace class
-"""
-from typing import NamedTuple
-
-
-class version_info(NamedTuple):
-    major: int
-    minor: int
-    micro: int
-    releaselevel: str
-    serial: int
-
-    @property
-    def __version__(self):
-        return (
-            "{}.{}.{}".format(self.major, self.minor, self.micro)
-            + (
-                "{}{}{}".format(
-                    "r" if self.releaselevel[0] == "c" else "",
-                    self.releaselevel[0],
-                    self.serial,
-                ),
-                "",
-            )[self.releaselevel == "final"]
-        )
-
-    def __str__(self):
-        return "{} {} / {}".format(__name__, self.__version__, __version_time__)
-
-    def __repr__(self):
-        return "{}.{}({})".format(
-            __name__,
-            type(self).__name__,
-            ", ".join("{}={!r}".format(*nv) for nv in zip(self._fields, self)),
-        )
-
-
-__version_info__ = version_info(3, 0, 9, "final", 0)
-__version_time__ = "05 May 2022 07:02 UTC"
-__version__ = __version_info__.__version__
-__versionTime__ = __version_time__
-__author__ = "Paul McGuire "
-
-from .util import *
-from .exceptions import *
-from .actions import *
-from .core import __diag__, __compat__
-from .results import *
-from .core import *
-from .core import _builtin_exprs as core_builtin_exprs
-from .helpers import *
-from .helpers import _builtin_exprs as helper_builtin_exprs
-
-from .unicode import unicode_set, UnicodeRangeList, pyparsing_unicode as unicode
-from .testing import pyparsing_test as testing
-from .common import (
-    pyparsing_common as common,
-    _builtin_exprs as common_builtin_exprs,
-)
-
-# define backward compat synonyms
-if "pyparsing_unicode" not in globals():
-    pyparsing_unicode = unicode
-if "pyparsing_common" not in globals():
-    pyparsing_common = common
-if "pyparsing_test" not in globals():
-    pyparsing_test = testing
-
-core_builtin_exprs += common_builtin_exprs + helper_builtin_exprs
-
-
-__all__ = [
-    "__version__",
-    "__version_time__",
-    "__author__",
-    "__compat__",
-    "__diag__",
-    "And",
-    "AtLineStart",
-    "AtStringStart",
-    "CaselessKeyword",
-    "CaselessLiteral",
-    "CharsNotIn",
-    "Combine",
-    "Dict",
-    "Each",
-    "Empty",
-    "FollowedBy",
-    "Forward",
-    "GoToColumn",
-    "Group",
-    "IndentedBlock",
-    "Keyword",
-    "LineEnd",
-    "LineStart",
-    "Literal",
-    "Located",
-    "PrecededBy",
-    "MatchFirst",
-    "NoMatch",
-    "NotAny",
-    "OneOrMore",
-    "OnlyOnce",
-    "OpAssoc",
-    "Opt",
-    "Optional",
-    "Or",
-    "ParseBaseException",
-    "ParseElementEnhance",
-    "ParseException",
-    "ParseExpression",
-    "ParseFatalException",
-    "ParseResults",
-    "ParseSyntaxException",
-    "ParserElement",
-    "PositionToken",
-    "QuotedString",
-    "RecursiveGrammarException",
-    "Regex",
-    "SkipTo",
-    "StringEnd",
-    "StringStart",
-    "Suppress",
-    "Token",
-    "TokenConverter",
-    "White",
-    "Word",
-    "WordEnd",
-    "WordStart",
-    "ZeroOrMore",
-    "Char",
-    "alphanums",
-    "alphas",
-    "alphas8bit",
-    "any_close_tag",
-    "any_open_tag",
-    "c_style_comment",
-    "col",
-    "common_html_entity",
-    "counted_array",
-    "cpp_style_comment",
-    "dbl_quoted_string",
-    "dbl_slash_comment",
-    "delimited_list",
-    "dict_of",
-    "empty",
-    "hexnums",
-    "html_comment",
-    "identchars",
-    "identbodychars",
-    "java_style_comment",
-    "line",
-    "line_end",
-    "line_start",
-    "lineno",
-    "make_html_tags",
-    "make_xml_tags",
-    "match_only_at_col",
-    "match_previous_expr",
-    "match_previous_literal",
-    "nested_expr",
-    "null_debug_action",
-    "nums",
-    "one_of",
-    "printables",
-    "punc8bit",
-    "python_style_comment",
-    "quoted_string",
-    "remove_quotes",
-    "replace_with",
-    "replace_html_entity",
-    "rest_of_line",
-    "sgl_quoted_string",
-    "srange",
-    "string_end",
-    "string_start",
-    "trace_parse_action",
-    "unicode_string",
-    "with_attribute",
-    "indentedBlock",
-    "original_text_for",
-    "ungroup",
-    "infix_notation",
-    "locatedExpr",
-    "with_class",
-    "CloseMatch",
-    "token_map",
-    "pyparsing_common",
-    "pyparsing_unicode",
-    "unicode_set",
-    "condition_as_parse_action",
-    "pyparsing_test",
-    # pre-PEP8 compatibility names
-    "__versionTime__",
-    "anyCloseTag",
-    "anyOpenTag",
-    "cStyleComment",
-    "commonHTMLEntity",
-    "countedArray",
-    "cppStyleComment",
-    "dblQuotedString",
-    "dblSlashComment",
-    "delimitedList",
-    "dictOf",
-    "htmlComment",
-    "javaStyleComment",
-    "lineEnd",
-    "lineStart",
-    "makeHTMLTags",
-    "makeXMLTags",
-    "matchOnlyAtCol",
-    "matchPreviousExpr",
-    "matchPreviousLiteral",
-    "nestedExpr",
-    "nullDebugAction",
-    "oneOf",
-    "opAssoc",
-    "pythonStyleComment",
-    "quotedString",
-    "removeQuotes",
-    "replaceHTMLEntity",
-    "replaceWith",
-    "restOfLine",
-    "sglQuotedString",
-    "stringEnd",
-    "stringStart",
-    "traceParseAction",
-    "unicodeString",
-    "withAttribute",
-    "indentedBlock",
-    "originalTextFor",
-    "infixNotation",
-    "locatedExpr",
-    "withClass",
-    "tokenMap",
-    "conditionAsParseAction",
-    "autoname_elements",
-]
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index c86725ed2c14db101890b97136ac100bf84955bc..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 8340
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

diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc
deleted file mode 100755
index cfc67a02e5b978622d65633bc5f7b686e356b6d5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 8466
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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-311.pyc deleted file mode 100755 index 336304899d0fbb1f081d976a45771c331f3c8739..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 277640 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 *{fEnYOgm2;*RYv;!u6%=?< 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

r-pcgy46u6Ta8l-~`4!JId{FTDHp!*3i; zSRJ!N;hNW)HkD+NeElZIY}_OAr%U_sE(zI~+a`J`i~!x+A`-HSXFVxi-YD zZIZQZ(b~IU?Y&j@PvnGj(H;dhlMrZps-#j zn7fiP;3pHD6>Ky?^}uH+u88adEjqg==Io7|cS+`5_XpzU{TQoa8q#9pe=|Bi*BHxd zi5pubV`~c1XdWQ^f6v>BO5wFMyS4<4Ow6@AZtat-ebD-_9;6XFM0Q__&Y|0H!iH*7+>2it!;M8*_AUD((s+Q`O>YI-n#MT zjhnCCdW{{oz|MCA4NL>5--tPKPAbH@ZzPry01^>$8eGMAAIdg?*^}_pfEHGPy8j0biPM)c^nh diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc deleted file mode 100755 index 09cf2ad1830311bfe55cd7fccf2da8c25f05761f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12930 zcmeHNU2GdycAnvo6h%>@WKn;%Vow}95@Y>X{+DbyYsYeIH<432o21(8(qqm@qRqd~ z3~h@hQ>AcGZE7G)D!|%>7s~})SAp~37W_ve* z^*eXS;gFKE$f8^Hp+oZW&iy&}+;i_e=ey_Lzin;xa(GJ1KfUz&D;)Q4^iqAAE0JeO zp5tzDGAHvxWv6HHgi2|wMA|XP;sTOk*_G-iZmjy`ga>{OhxOL1WeyDwRjP;vH|H4)Cb<)$018IRH| z_sY#T_`68EXXVa#l@{51gKJ3jDXnsg;+%EJz8lVlyf&8SLSE~-JinFKwl1&T%JZ+w z>!`HWe#1GlNyY@6>6H8AO>*aLUJjs##EVnzy3sTfKrc+ry3wmHB{0)13z!|7jZN=h zVkyTZO|hm)`rt*piq`0e;i#l(;%q_{rD#;FjGm~b;(8=zE2pUrNNCz{CNYH#A({vq zLQI@JOjnXlN zzzz^-Uc!g1oZk>9VM|iTU^>)_=Dbz~Q6RSg^` z3u$PQGzLI+uQv|gLZvCs%x9I8>c8GojZvTKO-;?@A*Zf~_2o#8GJl!LF2}2%WgL0S zK-Q=e{Y#dy%S<2Kl@7muq<$SB7ta(f$iZO{3Lwbb`zAKYaT`@SJVR zdNLlFua(R;XPRq7*8mHm0rhU=b;v%Wr5c)Ro;n8seFZ4tb!0E)<>o)C5EvLZ@x zn<10p$N;L+qLQwN`n)2(!+?tziR+3Qm!gy#RxSd)P*Osa#Arm*E!v4$R>?vzAe~ed zO#`;lkR$10SW0OM8Ug8={RE+lil|BvWQ}+&YOn-=UuamHs3i_lJ&}bbXsgr{^DI!TntmIj7oY7?DB zTEu9{;%q9;niL6wYKO(htT>&BD?^OZYzhd(PL354uSSpzK@ep{W_5NCiHUf0!A6`0 zWmbv+anGTH$&`-bL>H*`vZ4;L#x2315hm{{Wo`Yw{RQP$$r;$c9ucXh-nVB#!Q!0N!}pp}iiT501OUi^mt zQQCbyJ0V`rBD*P^z~sKBt6QkJ!)Q(tOQ&PWsL>i?@#(}HQg~iTd#`6lu4gfp*RyFC zi=%kcRTW5IQPZ9y<`&^-+HpPm4et&18BLM6mQ=#J;S48K3_cn#1Z_bxI_4BzRl+H3 zSuh5XSVT9x5o}*DaPhFBl0`AxL^dv~gp>?7c0Z|D+;9VA#v~Bb7tki538M|PBJsGQ z&eCepz;wu3q}Z+q*kKsW3Z|c;Vo@8O*${xI6x9p?6+sXiD_J2au+5I)h{%Q@$+AkS z+HhV3#Lx9W;7n|7XATla_Q9+>z#G+WEg!YuU!AA_o?5rWosxcx?2+(MzFhneq zBxFS+<6hNA?B7Iz9Z(lhDH0D^Bb?sB2Coi&kE|;d1Uc<}C^_K5?Ob!uQX75Bo`FLB z_eo3p(&XbnPbm;A26mMKyOyTPZS70K>0i<6npj-efvtjeFfjXvZv)!?`69e(6#7(8KPb)$^s{qhGrU z-9yFh=~DOf(wmPvyFc5%ynpG$B1)qE1f_7=;lWS&r583P`5L1 zW5$tsd3F-PEx3F#K(Ln(Hy^~UEgIsOnN~X0V$WTm-Fwz<0d|^Ce`#qj%ihkyyd=~G z5q7X*wY3OTQ)G5Q46BO7^eB|SNQ;ZvFH&ApRlk8nZ&ppjpj;DBqbd}bbR`jyHE~|L zLVCEmy%M#^TwH?QRz&E;*=QuJLnFr$D59kC2pJkt2t&Czl8Q#% zu5R%BA!5O{u(xlpup7!;Mt$uS1X$KSuDx?f%k5b{xN`jV$^7v~dlO_LT z!86H*$Z$g;!R&-B;iEE%m<`ndL~e1qEf3oX>kV;hnCbx`8=5z*ew&t!882qk2=l;v zh*u$66Ej)bOH72J<5dDROv@n%3QVD!`(Z-+U+~QEXvB!Q8D<62JsZe}+S5=@Bj~rt z{nm?#nme(4YDK;sDf$OX{=tH0(44GRzfkgjMgs3yeXvPjY?xdjG6M=Wi1Xb9LW`*; z5Otb*XcGrzr~6(Yj(CFhur`5o=j7%2yz@?T(f?Y>|60NG+8;z9U-0Q4ew#o{dkuv3 z`%aWE1eM0^TjWC7>Fy2Wg0??K-m}^)>CEk0KD6@g?LR5{2TFc2i+>QIsDDfxpQE60 z5J!mFjRw&a)DqP>PXYNb>((#1LD>3T#+-mhjH{_x^{?$KShqY^%u#@9=2O2Ry39(c zg3M?6cuJ?qReACx&~=Z!J$q~QIwI@HI6m%%+rq{}jTBq~;Qb!WY4&7=c>jy&+S`Du z2IcKeiY#1D86gd>^ES>aWbr4%W!u0RA9u)2Szh-1Zif>23+ptZPpE3}h_ExiZs%giEAAZAssFGJ8z4Lk&fLa`+jp4kc z5+ENE2T9FMT+a@{3PtfB47SuP4cw*xnSC`w61obfJzfd(!crP8z~k_|;hIwusie`Q zDnOKg)T6`;b6}F(RGN-3U3G@$+oaqs6xR^rb$7{+eD~MAv%75n{x98>#mab zDQal{gkX^?xA*T|&lV8cdihLdTb#HO&xzg5ixt4P0)$sYYVBTNwRSJTVDI|nNK26|M-h=mb6P*m z&%?M)V}~U`WQ_`eJiZtk66MAoUo-O;Xhds6u*g03Z_4fa@xsl8f~S|Ul@^Y^d<5iu z=Kl0N+m9Np=3C{I$O3J&_AE{EC1X9qf9%Ncad^J5dTm-I3om$W703>9mu8(AhdL+= zc?%gO)^gVIwfy<#wqjmv{|8EJZMMAlPK3ccad_>O2rCurvJ(^HdE$QC&z@{ zhr+N3gL#y0Zr>qy;5&2UPGYHnH!4HhKyqEM^;$>kY6SiZNu<4N1U?^aA$BnltznpH zwy4<(#u_3`z}Ay`7%{^|jV6OGwzgD-GG$8l5Q8)-MhlCXdcW};z)x)AC;-lf5EV;r z1QQ#|+yQwlh5#_p%LNY<29M>kx$J|?lCRv^vpl}!DR*yPzMMbySz@WB+|skg3C(Tg zp1xaGKfhY;=vx_DIlMAd>KItvSog}KNT*ajKgL}nw>#i(NXkf}9PRBb+IZA3f^BcWb}Po8?aV0Mm3lkKSZwksZ8 zi#~ZLwIOVUBjI_tjTgw}999=_xgtz$z+qwc@0+5u4h!JTt&-Joc3v}1wf(f^*wh$x zcrkH`VU}flS&Wz-Z~#$S1$74y667UEG@!x-h}rZkix)0be2Nz?RK^l=Pl#}kvfeVM zdc|vPH38ymgzBU=#0G$R4&Mq`N{AQ-kY^LI>Vh7*qNo=WY-z#mZ+iVF#dp<|a^ZqS zKFF(Y!gvH7rXig~yw0K0RN;6-BwES)d#Xej7nbo14`;z6|IUa0oq2h6s_5TS^6x2l z_AomJuLN1LX`nTADBn`jr!50Jn?uCSVa8ZaAKRF$~XHc7sNW zsxMKV4+DTfH@#M@BSs5zAXQTShzfa$vd)Gog)hx2-vxu3#<Si8%+(z(XruQAxcyZYcLtp;wNOZ>VETN{^H3s%7c5(?+v ztEJgu{X1QI*Ej@u^N+=C!8Ffx?O1%9KIW*>IS9=F>md|R&oj!Yzq%wl0HXw>tzP9z ze~Kz>P1TH&KCj}aiu`r8Lp&^)ikcARgrdaf*ue%Z-d_)sWVkV>5NTiLmLEYx{_KY(ys4Os!hl zbyjw&Y9T9}*7oMR8?EA4t<`E%W2Shfzi>9F4wdkE<9fY9X%ze`ej4eW+In4cw7Wbs z2W^2lDX7ACoD`jGQk;}@DQZoFbc#)j@8cTNFq;v~9NJ8cZI-~K;{cnEPUAp1go?;P zPH&7xgzkR9g>V?=Fp&fdv|R#=#9|77g056fTBp^k;J;B43zSB|8h+~}A&?O20#g!H z;X6tqz$9^g0dVA6O%%^qH_oJR>Ku*WPQV0H)f1-Gsu$aZA@L%RPGt?zB%x~omCl(< zDsI)EQq_cd9x^#{EH00Ptkk)9D1HOJ)>Q zM4K>yEZ9{79BPQEIGv@F9lcD0$U393E{Y0q09%aXb{tNc!(?t`Hy()VG!PX0*G2>3 zqJgLj%z>Z^bpuh|7Czg7oJKu`Ylu!+Q0S_o6BiTRvJ0BaZSqd)(Ui z{3q*@^?ALcldvea@tcnVX8r>@I*Zs}EOBp|2>1t7wM6 z3%ff3sVi|ypiz_tfUBHY17p(I)J+ttd9zlCYQV=+sd1#9#SP0GHQ|rtw1Mz&v{u?f|o+FY^lGyL3&Zf}Mb&SsL&@unWBme$~{{8pm(t)>%{uzkSI-f(eG~A|$C9#iFKOp+e*2*;@Dzke` z;DGr=1_P-$l#-v<@&=t$bbV0R4CaxH8wk|`ZElLK4+>jGo>KDjTHdA>o+jhQ QVZQk(%X$8Sd^S!08w@Cv!~g&Q diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc deleted file mode 100755 index f0d0f51d1895b1592ea7f19290fc8fd74d4d3d16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53631 zcmd?SdvIG8@y|l5FqHWCoYHGsK`)yQ#?|kR=o$qyi-|5T~aLMm}c;(+O3&Q_S zKh(>u+e4wiITmgChH|q7iji9(pm(y|&4H3P z%_Bvc-=+9n%xfDM36!C><@bz%3e?PWr6gSkN2bJ}Lx+P(z`YIsRrs&Qe+~Y5J+`Cd z(trmg?@&t53DlyrGSuw?O4_N^tqv)6DXDCMdZa4Xz}J8j6`J2({H_f60*wKKQ3!7P zJ%IRK6-;5myzyC}3FS0z(o!v(JZs$&n{BAWZlxZMKs%tULRr;;J-=rF1o-C{d)A?U zHen3xebX>f6WF&&iLT)Gpi|$kCd`5TsHNv?#P39WU^!SDIM5A1*xf<813Vu5?+n%j zcLloU@Z|T5fEWM#ir1@m+V8+2eGT-#UPJ1Uh7oU|`%NKexZ+b&UTIYC;!WzE_FLap zM+N=wk!HZz66gu^##^{tBW;1cH-(YiM&Y;+=zmiP z90|7no(Y)2KfgxyptYPB^V|8iw%2cbqJ2AI%8Ztg4#eFa>hZReoYKy$j>0^yNmn#IH8#%1he^~!^ zi#*QjV~zA-E`I4v!he4jZjNj~9v>4>AJT&rBuxI4uVDHE)sQ0VE!y_ZXzL5(7!#TnC+D{4Gp`X$`>@%cnqoaXI|E1AU z+#4Ewrj&JbEHdSfT*jM;DStE?45cbYgOPFnOmI{TUJBkA75$-0!O`){elhZ;q4^jR z7W=2B!q-QmqJMH~GIVJ)5S*HvPML!@X2g_*|FDjSr^hBk!IWuwGK9c?LnIm{l_LhD zvtnr6LQvr%uyXNFlgk$$WBPnwh^CheL5K;_^n{!}L5r19Gg2v6JUuGI68!%zaFV=VX3m?(~fuNB7)#>Eq}-m97kf{$0!>)&`8v09#f%eJ&wG!1SqE zKV8q~#EcPFv>*d(EGv(BL(KHe%9tsTbCpFBUD2XU?0{8Y#%~~YAZM;j5avxW^Ea!I zwj^ebnXa;S%Svn8kk+iEHOGXQAtun|7(+hVshpn8TY-_nm^GRvwGb~0?l~umXB2Cr zfJVJyS@6ak>KpBMEJqL7IU#0!)|kFre;c~niQv>sQ1nE@orClS#*|Ba4I+* z3?Y_36v$){@r?UJESJmvYeCOsC>j*61w$B;p6izZMP$Z59&Bc5FdSJ1&7QH@DDs_T zX+2{>mOOkdD2kJTKrrMPyXl$n1775D@uD(_dxpi?;Khq5fI&2lx+|gNwDfu|H2D1u&7Ov_F$%}W8(wF{ zZk6lh;EmAibi~)pyI4;{7m{iFKz4b3eO>+iT}O^|9X;ALFpw!#|6D0`Zu>174D+4~ zx7aY5_we7Zx3;$40$S$hEO<5ldP?w_M4F978n`JFUJZ#fyU$f(E%8jxVqlF0J(t9w zAN?Jz?GJf&&-t*#Z2GR*6Ba$eH)j1))FY9D&zZ`bL@$d({h{$-$_C_(MsLmpQ_dF% znc@H+YpEjO8wL2M&aqB-1gm5ul`|0*(YI12q)M5`!!tKidAJSwr?Cw>}3`Pfyp=GwjL+Wnwda_yI0`xnhmoULoleXGuWkDczN z;`b}wskpoC-EC_H4XXtWQh`q{@JY@_+1dCwzhG(C?JIY#BpZ7Zj$@0*zcuvs(EX0( z*$=wzbxDqT*-@Wx)IaK9w+i|DKNrmTIX|Od;n=!Ea1>GLp2zO;<&wLucU_B?C)T`$ zZzS#cO9gLtE_OaHtV&cLlnT4#!mfm)D`~SYzH!^OXi6%v7N1*=#K%9JTb^SvPe_G> za^YaYF_?*2Srgy2Quk5w1Ji?Z4{Y*|gHq+egt_dAbsH7kn6z!XABpe#VD8?WWb-9# z+n!kS*9DVh?_*bKqO4JJHOa1~HP_x%*WL#&Nv>|$)t#_)KXKKrxtdm8O)JMFSBLEC zNZ2~Q0EUTbvtnu=AnMA78`k_{J>HC~v=ObmM6u8)`C<&e-V)w2zc0j$GlrO9-l(Oh z^z_Nw=0)=&ZD9;=+OV1%7kp95L%Fo{m43C{oZ1SQ-pr=AjG^M#7F3NMl6fQIsZ^l~ z0Q(M@^<^7Sug&Q*&?S~nbM)JIihbKm6vY;~Tcc@)lpx&Bf}hd_Y!vEY0AZc$|8;=7 z2@NnFp2b4EDFvWR^24WmdQ$c@#R#`PcG&nVd;=16beE%j!-}B%!WsWfnO#qM}1>5(XF1NtY%u=~5ExmHgsOPKD5nzSGmt zzPkZ$0+ZwZC^aXmS7&Y31P*gMT~< zlGHoppB@YNJ<%>?7WGCi?0&u3v&ZL4=e9M5&^pRg)RR?Y7LkB@d=2DHc*5vtq6Zyd zDiBF8=nQBOh!cFp4}vPeAY-)bSP&zH_53u{J2~}@g>E|1%y7&{6wednI3u`e38vnH zo_;xa6GYk6lqLuCI3oLqpbn^*P7{zX5TS6E=hKx=#9$gF;%;<081)DIQ9sbHws{k8 z2!(R<))L84o53{w4DgAwfZ+Vu+)Sx#GSZJmGj18JzF;l=h}45-P%1B9tZY&TenIOq3rh~_{Dy@Ldsv;nv~}|trgv`p7Ijo3+@h2utXdF$YOf0Fy7+y#L_o3b(No(_hFQJ4$pnHmku(%ukUsGD;+-l<^7=b1BMIrQ05)?;Du zx?c>W%ry6<%rt6J?(E4=tVC&|2SLj14+L~gB2vHcSvY;(K=JA+Xs2K|f(TJ67ty$f zdD}X5wG(^r_BciR=Lmj*R$4!65J3Fp?^rHhIR3bx{BFg&6$>ZV%@#|+y0BG{FW6iQ z-*{YD`d;*Ia#zo_Vff1Ns_r$fm z4r%!nGX#vEnz9ME+s3#`;HnYXcfcIgu->v+d>e^1gK*mjg3aOww|NtSEuYX!!?iGKpmf#LQGU zd^JLZ9m~e=X%K@m*u*vvMYU=2R*wf=8ToBs3QSCj*aj<$J6jdfQ*R`Q#Xo>|47gDh zDs?yOWl1v&50AyD!X7NUlx>rzwyPE)&q<*#u{`n|!TqRh?`p5Tc#$)cLg6TXv zaer{!KO3PHd6KUO97&ACRWYROtckIMY%$qkXHMK9T8dQymQ^TS7Olbj$8J^(xG;>1 zg|;F90>KE{3p682W(m8-X}{ieF$)P)PXKu|>}f=@MvBgvOSB^viHziXUzSHOc4W|YEN04s@eG4np1)o-JKh!?@%;%`AnRCeOC zvgdwhe9s4m?j7R4wIQ1jeU_97%Z^BMQOfF%Fy2hc)E5efO?ZUWgBDYy!oZoOEZ$s<1>o~ z2sI=JW2-P^g3I*IX=WQi1d#rb`Sw7{qq{ZUU=Jg$G31~-JELy zUuKh_RIuc(nJZS!6^Y8-kIV^kg=8L(%>xPZK+-2A&UaGi%E?)e>tM^`&3hE_u zgKTa{m>a-KS~&TXH8BYo-ZDLPO*Cz_66(j@yy3PfW?_mQTKtv5}!&KQrqzTfcPc z=OGqRlNAYLJV9bEV2%W>Lv#R_9AQP~GA0NDusG5hi`ANzVywf&!%&~|b(CK46>Pct4 z{P#DY>IdMBLvzIgH^5w@_PsUV3_5f+6u32yd6-r(k@hR8e8$-rxG^4_A^wn9j)xl; zGCTT2Bsk2Zcqu#Uc>G89vQ|dIno&Myvow5(i_8sY&EwP)GYj+Pi(%&d7Px^#z!CoX~8}~;beuwNY7m>J5446HU(W^X~ z_$n$QjvyGP>eEH5GqpGk*DoBnd&~V+0mxws#4)CMOUxWL#EkQ1-E?7iilU2GD~P$0 zo&?0IC{01iwS{wXjAVYEIydtQ68-cix}zDk-$oT6 zTgVmNmPs4fsG?$vQ zQer$O7WN1RA=H7`)>vN5krjK##@I1iT+{9v2y?Sj8z|?TJ0}_BkaT|?Y&>`?W?nLg zJJDwy(fUj&SBlkpC_UxPJ9C97ZM&2!;CzO5=?LVepv&QFW=?HJE=D>WLv10|b7nB7aW zN^_x2>H?*k)#B}fm@7`}#)fOL02El+n_2xIVp`WZVW*&L;q)l26U6NX;TdMT^37wuR@L$nI$0@RMEmyK(zZowudIBCdZ>ZBdB_UVNT1ODu12~%|KHO>tGN>?!51uH38)QqqY6sZ;43N#9J30wBDKDqas# zGU?OBi=0bJS*4eL4ll_KJz>zu)01;(p>T+A#T0mmMFn0W$*k3eW5mTpPk8JKfIq~A zoLpOtaX{4+N(Py9TJ-Y79`7V6ps9eXx_Lkjw9-`CMS03_HmRa%oG?J5&>qw*I2xYt)^_8**VB!l$FrkHBZa-@ zr)XOBJp~OO4;c7kEED!t&(25hpGG=L9aAEv)A6nMWF#D7az{jCv71G(35uT>QwD#^Fs5aAi~A5`uAJ8~ zvjbM8rvDjlBeYB|2-pc;|M2<;H}BnC>HEXue{lSh!A}QQx9?lv0#seiXrIDr7R3!} z_DnFxH|4fG8&>pmgIaH+IF9le{>5m7xI`)8G6e*1Y;U~h^1;|7I(RPN~Bi{Gn zwato6cPx?*Y>obGmaK|4gLoO~zAj{Df{e@8fvVR&d~IdN2c!2!75L^l2SZ@~O+v*+ z9blS~h1r?2jnq|IB)tuh7m37lI#;n_aHt}pBC0bXS&{4HH6`+zmXG{a$71C6fjbA5 z{BL*TLDq*cL6~@p!|*GqA@wv}4aI3Z5JMD%5qzCm)o0bJaBre;Z~WYQ9ZQkB2i`rf z{Kh*yc#!pBwVE@Nezi!Ow#{p`7jM$-_BBLz$~-0#JK}5C$4B*{t(($H+lCU`h8{-# zZPmU9<5E?ZT-Al&SszxNFAcHHtI?~iM!CNGT}gM?Y-Ss&g?d9RImpX&l=_O&ru8z3~i6qz$& z_1{oiHhB???tNjBq^%fg&o-II4FA}8ryTXXg2a%~S)c(56Oin#_+?%<^bey%F7(b- zZWw3jcb!z#T4V*`X>~vUJm^>+|MujElOJ5YcXg#B{g_p8oTfnaN>7JJ@r2muka_7e zx8iC{-M4;4&1`E?DMGq<69IVJH2gI(*gQ-jW8o?Aq-P>D?SNaUuwo-~mLmaJ zmJdcA86NHUbMyb0_s{eGnd8qL^1kO6_$oVhAk8}Wq^WI2o3g!;N~w&^PEIiu-3)cV zp=sGX+KK|-Go(kPYu;dlF3T1j*PZUTtX09Jrb$zrL69mSwT7T#*}yCr6uGKW`LCEr z`>FPARC{HNmK;u$9DY!gC~d%J#UzzB%caeDl=Wea?W-1vRU?*AKsZnBf^t@96h!MZ z6fq}Z?xIkhP=CA>Az3{T6`n}hC>k~mk(8P4Qm!KkCst+9rXMKV;*?c+Blc42-_BxSx5hIylfHL>VHJSNUgS!gVYsk}`4`U=Gh^!halUZ>#KD0r0u z;vGZ9Kf;VuQkH3d^*L*S*3!gcIcG=~mcHNkPUGF?cbiEk?lE9KdfzMM z?v!(PlI6uY1GMOtm=+zq|17^OQU0Qoe^$;vo3Nct+95A7SSnziar@?-n+aPv>SeQY zx**<(Zz-=yMrdu4txfBK(^8g%)}K-yS!_`#!R)7(U8Pls6`eE0zY5C6!C(mpkGXsia;mK}6GL5x2cR^v+PcJsy;b zo8{u>L~%1qylzG8^*o`VaOuUnIZKB1GQs8E1pM_%wASZBwIx64YfqFPxNp4YTy{Qq zW6`#5uFTDc773>;R*vIaD%>k0bnTU0djYreh~Y_D_51Vh%qNRW-#`A&alUFlx`c0O z+mMW~ct|cDf`qM{By8n{OXel>x=kqG_Wq4`Zt%tMVFSLU?fo*svVOU&A2D(ScLkcr zxhGjxw^r7)TGq63R4Qwi%i5RBpB0uZo8u=Eg)LHHi(J^UR=9t)aQ}nZKc4%exkn9B z=SjKqq*QoHEi$;8XAKwjvq{9G_P^HD=5 zV(9}D68+*AzxX)}l}fd<mB-p*U1iNfyZg^|3b&(1Q%rzEKcIrjDw{jYT2DcMSz0_^9M3MjWF|%o0#?) z&jQRMaAD{nR3fRIbp5KO6q>8fr(lNx11rFaHR!A`N)*xJ;F zpaNH^HgXw`1-d-vUOeA-cEB?ej)b~AjQN2&O+<;i8y363xVdy0)*Ue30r%<#vEsVG zf)=OzGqnr~THCPli7M9%b}VDTDQK*!=9gZWuKMu%Oeo0P)l1eGqa@ZvO`~CO?Ls{) z(I!SQ4W5QpTGuspFr00cF7iTqvj?i?uj`E{2vpxj+X$A51K8tX-}*YRRswE*wXkb# zGa_J9Pl11kEj@L7&d$d}P+lT9;9!X}ZhbTj7w;5+iN+>zH8XX<_#nhHptCG}SpCy^ zaFp?!(nwK>679C zSk+XIw809?J(9(|AD$-5@!Oj7?Owq&M<^5?9Z(u+(-gTNnUJY2(XsQ9oIV$j2K?NQ$MBs@A z5qPTBmTYp^=xms0g~6?enL1i3H$DDR7B-FgjN-SkmWXi#TAoMBs`NDRJ9u-Pwi^w& zfg18>#>}Gx1G^w` zHw8@k6_q>2z#DV6`75o(&>=C3W~RH56M{1i(#?ojHit9Y(FG)}!WF^+yJD76&Hd&& zBwEdoE2JyNEMz!<`&?$oR?M(Cc?m|2Q&7N&ut-D z|H(*$u#laP1Se*h?LOubxSSxv0<6EZpCvs-W+q6|(vauG@bjlJx%)*vkwyK?1~$y% zi~j2#dcew?j6$Plf(gekB|;k+yF5r;ktYf57;uktAi2PSfI?xXLJ~_7D|JCnXQtGVWx}U(X7qsKm~tK*8j!?K z>E{fw^do&yBK!P$#~zv-wFqSSDCv~G0jnE^V~$adGIWb`VGrb> zls3~_)LKXRLZA|GDndsIlcVTt=?ZC0b$E*__Sl>P)YY@ub2B{44N_rAmW6usgEWo_ zE=1)hA*u{7NoAKh5daRu;zXOVV$rLRPQ$1WwJM*-(5PtvrnYs_b{P>T6Xxk9o6jiM z+?rgAh~q@9sTMY*L*VHi>xGdhjIp~XdkK@>ZIh65w&7`rWc?VTG?p_28jWf`20h-| zvD#)&?PRSlV=YUh0BC4P%Hd;V3RofODCshcUXD&rjUr{liy%W3Py(W35p6?@dU;Mn z0bZS)84i1Sjzj_~cdR)m3%WRcL78QVK2dKUjGz_E)=db7hApw6F>Jliph1!Hd^|nf zWA>zFi1BW7a6=Lxh2yL;?ucm#jkffSPGla)IE^4H(!c8~n$#ic$d!!o!XQ z&Y(P&a*d{wvZ*rV%shbq4;`3PE(4Pos!Tp+Bz`f!V#W+BU8{$dW}b`RMMUva1fQ6) z*su!o@$1%TnQBCA#04SlUoptugAeQX z)>j)N;YlFNs!Ln%OVH`$_QKs16G8-^X-I_{op&nL{*Da+A5c}J}CI(l0PbW@C~W`xZHj`QF>f1 zK9MLITG#?+k+U83zWOxfA)P|^1uoeaSvfvULUvvRxI->0I9G)m>7 zt3S{7#VH3mVdhsZTMMXs@sAKOLevLF0$pr0qzX3ROZ=yZ6DIr+gA=B=M-76zT;XSa z<}SHweb>6?_O80U312ThlKVN?{T!H{MOE+jzSAoe?UajlE}Tw!b}hh8wmRvqSjtUQ zHc9Sg+1UKo_k6-l#`zrKG<-aagu&&%fX3G?}+y*Obm z=3*1nDt*!5r2j8YAkedNvL(lx6NVcJSaezA+|`U`8tenGbg5o98X~kflCv`SUP2oa zy#m6k4~u(d30CydKvIGEK{{+xOm_@yXQrDI3Wr*PWIV6fRB9`fmc|nUn?|eF?p&4X z(EKBkm@-01wG&8%()BXqMOBhmq0W$p=$HuGAHMjby~xN(AI!<7Yzc|!y|(8t+q zlcI+Leaqtif6>NlA@&{}c!7i|!vja5@1ByVG!mKn5$!nwQf8 znf@7orL&@E$EjJ`P>@v$H$?)O&$k2AQ;7z})Ph?E0HzqmcOy&hjpQY#wzY10;2?mz zz~SCf$IJyZ4(3cS2-{cxcI4kPWX6f!!qV^PWd2!QDx?(6SGhUESe*@1D% z=wOCJa%Xp4A#fQNNhP@1=0WwN#(88fV>dPIAB$Y%#c!fZcb!bunf{yNA|*|+5h2OY zMs3B=84S>p;JqFo?j5PFadO#PJ9Q-zm}uYAF?BT(xN?QxUA=Opea{}~uIXt{P6M)h zw;{{IWeS$gJ`FGD!i59$h8Kf(?fRGP{4I*cyFDFBLLG5J^Vd^oz?2adCq~E_ zk0PFqVBi#BwFVIzr@X(UIf~{QOnJ4+beGCwJ&W~B#(+uL)UF0Yp9~%FF_Lj&z(suK z;LB-OlHlIh@iJv)Wrsx_2gj}fNTj9ry95Jin1PG4UvL%QzI5l(T7La%etn{$8y_jZ zN6znoJkRb<+FXm)C5L3ImTlF^y!^$w#p}0Q?zDVvGUS#&$!lC}_*V1V&9__cw65iO zSM$75UZb4XxY8x%?U(cRe{M16c7AR$lVk(|Bs`WJHuHXI@P29Vk&0i2j!EV4twJh? zZwylKRErIMD5?@W+=I)%1l(zR9%`zzliGWjZm~L%!&5eSils4~C69h$RIL7uF;mD8 zGtZkdI%aT`s+oMVDNs0BH7*$z{)2XMhcjGiQsvU?^}|Bq&vbDOPmTMD*496pTnLyH zs2}QLWzop#Sl@vY*z;P~wozDks8`JF60{E1sQ$G0L^bw9SJHk5=nZpVi*@3=L=Uiw zp6VA9{jbgKhlo3-k2epDh7LtF79X2CeATz$*MnYP;uesBU#E{pHJmqw{x4v1=Bbz@ zRZr#0ZZ#KkrK`1U%GMK6Vz|^CwrYi6Sqs2gOkYpb@zz%L(?On<4t+>l^Q@luU%Xzn zP3ol|&AIw||At{}dor>I{N}NkMQc^2vlPq1h0Yet9J7#@^q6s@uXHxbc4XQ*yEkkc zRpe)2-V*BnC1C+i`d0@9xY@J~*l-2%V#05OU;o>Nfc^eP$B@K>cKGW->?>3vY)&qR z!6ya@kro8Q-J%Nh^g9t^rRWfwYz>taRTYP;VjZu3(8jMrJ1I zO`2va#u76#7{*;=WvVs$nq^Wgzh;?yQDuc{NL^|Ns18qaW~)MaYbwksS&z;ZX9$}| zt>p<{%h@u$Y4*gjpjK1yOD(0=JJXUIP^%KJZ_I|#J5;WE#sVlqLa^{~B)nguQx$%EOvz{Ni^a-ltX#$C9^ z@=D2(?)4Os1z_=sVl&Ig1cUphxUg6*nN^@cK~IbgsnE7##}- zZXzNdglyLGHrxWp4f6;z!=lHlYgtnF#v}yeIR-N74LoFW9-ScFA+mz(p~+GU@dnqT zRKd)p)W=&(3|dXYWMa@=lZUE_FKP;P&D6U3OM! zJU|WvY>*Y18f83PkyefiZ+5LSm5zjGVPXh$fKAlnX=va+K-HY64^Bo#!-0U8Zg2QJ zx6-AkaTJ-S_r|V0K7MR~`er^;3_YS8fK}2(hEsem>(G}e+$>j&J}-MoCVvg^+FM`m z;lE)8*l-YvNE;!cLR4s=l*H5fTId!z__Cm**z=wsJhFa8R_(i+vUBU(JU1O~xY`Dl zqQxrBiPX)A?V@QXy|JLCQ8s0;)b8?9NArPn+U2F;?Th$mxWVb`F6v1UU!>Nvi0-XJZ>__AP8nQ=W|zUW|EDJ zA1|Qzf+%O0DHJ?t|3UE|SN>7u_p5$Tr7(g1K_C|Y8U_9`(Bfb-LHxIrco%~IwqV=; z-!N>wI@spUY}Sb}wwR@C#)-DttvR)z(u*3h5JUiTNIqv(NX9w4hN$orrJTAYN+cgC z8rzOz^m97}zl$K1cLXCYG8B#uhD74Iq>7FX9P2xOdU*8Z6NAG8qeo8koju1yj~GoP z6XFhe`zZsmX%ZPDvWjJuQP34VcmRJ(|B7P#6$SsAf`3B+G3~_r2-3cnRWYGmGib#B z1u_0LF(>~c&COnSkJPlWlwH z&jbX2=N8HuR!hNa?ZHPX?UhS=*9(M_s=LR3UMy^{`}UO&uY53dZ|Zv^$?}?b=?AXw zwaAU9r1DcxF>gf{2>zzDJ}U!oTDL#9bbRSJboPsDvY_2wAHVj&H|~8SQPT>(ZFSpc z+6NY6bsLOHw)?(UE&EO;&Ynxu3`;e`a?SAPR#WwP!{;UoRRO{0CM#6|!QbU?QUw>P zuyp+Ag~IlF;OTL7UHm1oV@*^wKh~DV0I2b9EDeBAX=W-70Z>P!A^1DTCZ#!fX>Oqi zf?z*TQ$$+*MO>>N^--NnCanbtYc);?dCvl4fTfotN0scTx<9wl_#h%Rc0GJqYCI}! zACR{XNRENOvL#-8Svv8GeBu?!@d`36fVB()7!Bm+EyB?wu$$|6&+^{oZC8oLE}plq1oDXw`O$fKGB zaz1tGTLQk~a^jj1qshm8+cuYz-J78ooD(ONtqs?r4c?auHu{0Wh_eO?xAJ&(+qSu< zsz7m|L=S14taUeBSu;Y$Y*-UhA7>**^-s3IM(JkQn77`x#d1a~)xz-0n)wy&RG%~D z4C~Y2KrTcXu?ybatP@6XzRTv$4wAAmw5-+Rg}?&>p$Ezj$MvOIXxhCFX=r9hKuGub zku*3H1~1so&A^OS=S-t5T`3cuerf3W($GfdfLaw6mH0mc4xMltvo+rfQB|=Q(%Ewd zj9k75KM&B5qp0G4pn&Q2Y|xM6;_hv**uEMZhEnLpJzoi^#%9t~Dw*i4Rf8YvElMF@Y%-y>py*doiy2^IG>$qXw z@P#<;HeNWleG9L>w+)+HP6SMtbpcOi?f+G&Ea^uv&35o*1IlOPl{F4^(2!cw5bf8Y z?!z2wd}-+V(%`|_F!s?==!uiCV{}wpLar$*)GDWdLpXw;jKcKlzr#be=Yd{Ds}dnX zLyqfJEHDknukQZ0r~{E9`7aiPr5*3LywgGldyKt*>77fT9Z3tCNIg}qS z(Me+|D{aJw{g>c0mSk?Y6Mu%%A~ZmVyGGYxuDF_;p3p=K_M$`7h(AMsM*Iv0?)5NV zx9*g!Fkd%YYLbQJuxc+TUoKr4Uuj4b?2!ug$OU^Aa~5-+6qdi+1e1205_9eT&6R!9 z_T5rpyIk15a0(|Ht_wAmyvJqUwX&AgvKFbVO)hI&D?7YecK9!HO{KJJZ;@IjcU)FMO}-elULOhu()B-*5Rri&XdAqh_gYNUAv_*PM}xUXY7k zkn&%Y^Iyc4(0P{Zsa@XR8eiHOw=7>zTwmhW0C^R1Toq_QTttZA*Rd$p|l$FECe zr{uCze-(J_D2g5+`*V}21iM27*q;`_WE}zar&Iw1 zpIdTKf#P4H<|Pg!tfZQ6b1F6exkqr9y?1>%dUyWa`S>-dtmT18D(iR{Ot_9puA{Q+ z=)#F7>EnG~TD~Ne?2^p&vbjECu4gakjGuKQwvaFl*9O?^T1Yd>!ZoAd1HfIrcmsyz zOUC!D?^u_u-*$cIS~0DhlgiuW^7ggz&eifxsr;Z^esHb)xz+OLr1CzwyiaoX%kF;3 z){ho+lMT8%=WlZIf8+Av_2n|j<&koB$T>UKErP{~&QMgjaQw|v@NBSf;?2{K%c_?z zFJJ!P%DpR6nNKeBEgYB4#qheYbRuD|!ihv|ok>|Slt}EVTUyK*Ic!r}i<|5%DU_x# zVlqnuCS#-j1w_xNh<+{Nhsnaoij4cj%%+4|JxoRiM~Q%xDUJrA)d;&4ZWRe`IrE|e z(L7EeW}NJ_rK)0F#3pw-lo`@CNTr!Wd_E77BycvQ-0Nhho2W`MLmP+|x}$+!<|S_u z-WOq)%Ve$He$QnncJ|a>jz(u9U2Scb0Oaf#4ilT!9POGGh_zjxygFIioBrM1=I;ey zS0|x1dMVi5h9WX@mYtAyX$^D~5eCf7R3&jOEtwWgYuJ-%vBS=^6qg~B36uA<;4s=L z)jK4lauDo|Lcf*C*|g<)Yx^{kE1bN0RkZ~7Ll&i&0I{TyQL)#AGA5{EPcy$@)o3L^ zCZxc@jhH8~hLOyfx=7k8KaDMl&J|V(*w%EFAkSza$BFDImAIuUYo>*8F7(&v8VrPE zaKuKd6uxqZaf*LM_db=c?-61i-YwE%Mw>)ve(n|=B}*?a2PJ!*Y_Ch0>o&6bzxEiP z`|;mrfWPvL<2xLJ4Wpu>!lwc@&f7ABJWEmz3&*sby(+EOW9K5n=CEi3lEmCBOgdRy z&>qb8O?2S(?`ja~=7qg;*eqyAU(NiC7gTUBj1#L)aqZzzHzKR*K`Pl;LX1 za80kdd<&(C6#RfH=EV&hh83LRpO2#PH&%9lg7v=RUGBKs@@`AKApMeWMI80s=U(W> zCImiQd&LOS&l!D(<_ft`pBn)4x4PO=O*OTR;-`9TZe{^4B>?1?exE?Koja>^Kc-j@ z(`7D*$5vY*@R^1PMDxrbnZYxO8K2GeST82YAt}zd#U`C(l3c4ECiD5s@Ns}u?s@-A z%5*6hh4VS~J9}H1DpHE##*#{;a&(zLCCn1*19YUlV$EK?YOh}Q-%~^rIK7CEKecxB zja2OVf}}L>3qfJT5D-SNWgo#&C?nDYQn)EF#o#wTbj*Z9f7I@%!MO9*14g zo3P~5_5%HZDX`Bs!9HI_i=gFf>-U257VUX!F{9Q)xt=tEwl}HHD_8dEa5$nH98UF$ znVvbHEUy9crmTE4JoPMiN}e@lqyoHutwy(z^F2AASU)-#pEf6ChnBZ47JshOq|Vae zJt{1jUVn+rK-PJ9WDl?-y93~EYi%rFGlLJDJD*3V8tCB9)#{UH)wEK3I>qK1*|98r zU7Syl7qD_Jl{k`Bl16_#s^KwC7_-VP(#Zm{N(k5#>j9TeMvxT?RsgvSC(il&Kwey< zxvlmUa4noT1ptF5Lk7>gLL~wF7O}HRn0EzmGQ_y?hVd%v?_v(>&F&%vAp?BwYx&!i0FqF8?BUY~=$22o!cP1GwHWLu}* zhz|}==s#t(V7mXH1^-slf~T^^Wn-pv{dkDDv?qgX9P6ycxmVKTI_BO8o35t0o5fI| ze_zuJUO_Kt)%Aj}${D?l=lv|bAmmr_{_0%a&y?RmO+V<+^#fLd(w1Lc8t*$_k%r?d z<`BDe?dZ_j=R9?OwFAO}D`je{#~lAXD49@6Y>U%Ya3&4rweO}^bx5Y%u>$l`th}4c zin8YxW*^~>x#x41Om|+1S&-JvylBvo;C95Skkt(avw z*m(eo8y8@Tvcem10N6n#49dw!WR^&EIxB@MZG*Kkd1Dl6fXrOD)pIV$H}UEQkD)GY z>&j0v#8KkxFkyZoir+IG1fd_AjKGl%?CAk0XnJVf^EQGTHmLFk32t})1Ye* zEYvhmREKjHM(lH*8apk6ooxXY8X#c(d6c^MDC^YC9>ix3C8vB0ouj;8`{=xCW`nJq zK%*Muu)I+@luLzX7$q7wsfzSc?MjEpJR#G$i9LgX=ZCpDnVwKNlfZ|1v&1(Zh@@+CkuwM=J3!OXjMqxtIed`H65bhpuIm*3={QFYV)S~(4W0@v z?BKb5hT0)I;H*cSR;_KQk@aAx$lz-7tUQXZ6hbYejwvr4#z>WKSDVM<*~46Gb*Nh2 zlznz9W$;ZWt;0ed(4%pHV?Ck?5SCWyLhu;`h8?+z)XZRX>bF|6bo0TGWr7_8!)9QZ zsjId1032m6+sgK&fQ7iRnWwa0#Zl%;kp#ZBBV|BmPc_?r>H^BVirF&lK#ZC*)0d!+ zNtPZQUM(gwQ9NGO5jB%?y7s*Nr-SUg7-hZ>Pftc+vIGMybg1lVe1zo(Tj9+hqw*eJ~DFkp1Zzq|fgs$TBR7`eCKIs-ovvs*gG{sR4 z>nD`ObgRznO|>dfi($F3p#*rJiYC6oBi641PsC8+c%r*s4o|-SGI-*}aNhnVQj?v; zpQYJTr5~u@W6^CG?;sG$Q}JuqRYvq*EXxVvlW>g4r9vrEgHo$SD|Ts*poZlaN&eD?CQfQKp%hn5Lc! z=`!h;x1j~{0{E}hO@Tgr60c(2)zIi^Yd{Cbgsw)XxpAx5O`evoj;%UZBVaPMY87X} z!G-}|#H%$yp-B6hIvV%u>wrhTtY*O-O$Mt1zt4nmzkphZm1@{@yGQE@V=4;7}_yMJ7QOe2C8)Vh=^87U4hJ+o=?) z^|-pPp>LHLoz0zJZoqj80u!?+<+6;c)A*A@(M zxTDZ-s~P;1Tytz+b!?B@R(48`R@u>-aI_|i zN|%jGor^<^dyMmhhH)gwHtYe#DhjG8pmSQX*wQHzP$t&nMFW+=1r?kr4SNB|*te04 zeba!msauhB&VCFo&v33vpdZ4DKEOHjQ$qYtktJuK&mG2s4HApdVm;_+;h6#Wwc$=C z89k|xdzpnA)SZ@=n9IF2e`}r*b8}YZhB4^p_NOT{l|WEUIC$f=L z2H}3)+u@trqfe($XK-1`Tyk$Dz95N#`Vv*C72g-xcSR~MQ+1B+15{@c35vvx600cq zn1VYLkb)?)5fN!S5B(^ja>Ye@dW-^M8L|U6xV)f-S_}t*Dw;mOOK+J@5V6>~7LgTn z#t^1LoV($nh&w2#rC=uo)IQ8o1U_)!hLx}`zK_IAgGW3XoFF$b^fYCmIqGIApVj{~ z2+uyE@KVMZKgFde?dr{*R4%n76No^u=<;NQ<@=||chf^TRO6IW38`s7ZW>?@;56_4YZD!!rR|;a_D-p&bJ4bFds0*tH^(C%<*f`$o_48d&!X+K((Q4pRO*#Wz3W1^ zrRsAEZs#o;7CVzIdmmhvT6!ND9~C?@%FRb4n{P2^$+Gn8aZzVpLr(Rcdt6exR-wVX2rJ}uZ5ss!XISYSmdU)(l>_4(U zdSms#iNt{uk4rtt;+LSzqC4z8NAT3ccw_PS(#uR)sByKtai#OYajCppF7I9(TpWB- zzGJQ2yISsDDV551%jLWA$mL!dSp3G~H{Qno@{1JG-{V3Yw0>SHd`T{RDdBkOiM`@G z4IelE(E0;sVn=VnP9GNKMXB(tTzEF&IQv=E&JPCf4X#zSu2!|K+?1*g%2fv!ZAp8@ z{g>~(mazNqNxF)c4R6ma&Lyk1FCW2dx1W$(wMVYn^TYEG4?LRq$xDA8k`4_^`_9Yz z&P!G2mvZmsCJRcJcf3=%RGBQQNEGc#dUnE{_KB5iQr*6XHmUBgQ`hQZ5y@1F6M_9$uD;kD-ieC|4o)thi#?`<+); zu0Jf7+WHD{}EGP&%uA)v%QN3#c09SKYsUZ$9B{ z#wU%N&&qbh>%X^CDr=R?TG3$&e2=R=uyVR^@50hCj<}qU?JJihk8&u>k9R%F`ANBS z_(iGftlV{0sye%ryY#C?+tLwqDXIk)Yxt75tK{_J-G%hQspS#~wk zfN4v*8<%orcjHQb!rjI{Puvx2?#5L-+atMKWp``B-I}zymnP$0skCveq+_+D8BrcV^sK*qsG;Ia(iFPmw**`nKT;lpMh4nGFeiP5xSPEn{7Jc5tUyo~~%9%6)t3Kwu?Q55n<#}g|as(s8xn9}xxSgtm0wx2B)`ziU+dp&;XNsQUk z=%3HqL$7H|dK#4f(D3QX&eOxWu}1Uun0<3e`l1P=EpMY$58`X|A2NM$(Si8(P2vli z`(}$)X3}mwUN=IF?TUSiUYaErf-J}Bzl#ZpZNv1AN=a-n7$PSmAnM`o@G6uT!SMsH z2Og#T0nYGLl!G)fAjXL#hF|vC=Af>T7n3aDv>W87xX)F2P25{NN@bj5MXJFfl4Dbt z79cg#KYZaPqJ})&83WXh0#7}6o#k*&&47s1Y<^M(;+uf)2C)d!1%g+lIQ(Z^Y6u%} zthmDOR5<*+UUKASPefZT>py6(TG=^)-qK@a;o21oP7e%Io!t& z5Sj%uZ{SQ-SS`lFVfe|Uvz{0uo7!3BWb>v{H(IxZ|Z z1ZF+sxn@ojATB7+3k|`zpiH8ZuDZ&y)H(`N4{T>B>!VW!;HXCf5ZL0(uM*UT0Y0&T zA%LeCR;Ve;f zcw(V39-AU6W0EhRu2o^sY{I`Ir$JeMU(iiGecm~pa&DiN3B*n^-@RMuHpEvsjx752 zXddW)bfn+(r|+ng{(i5&d8~O{S5$w$wk#g4&#Q|9xzLzj8;d>Amd_q!ianAp_GtQ! za>mp#?Y+@_Gb?uzb$WuAa8`mI3shBH#2im&LyWZyLyGrCv@~Y19?ymL%sEAo=rlQ5 zIu;h;(mmi+T7ZV3+UvfT`w zhE&3viRvQD1~V-LTY%9+=v4|$7si@cE$S$`P>dv3YDU^(HLb6xcPb98C=2x*v<$i!4{un6 zXdS+>xH>4s=S;hEj19;Tjk@$PFEsSEvopIcH1t#S9tzrb?}ld}Fk>$?98W*&+rytV&po>DQXia`*jhJ1q0JhMT}7}PQh0KjOj*!n4!Vb(BF^htGQ8fR!f4OCLIne?i8?b z#{kcQ{fHL!hNIeFo79A+A#D`3^cz%zo6k}WB~woW%~~1o(`}Zn1I=B8Xu247hsHCs zA3w&6$nY;}5xi%_c2Rd=05*w2K=@4~nE}#a9G@76e)^wrF-|W$|2ygYrr8;C)DE%> z&Yv@L1v9@~Sm0b~J84oxd9=A&-7J$~uxsM{HMWWo;&H-|FIiC^7v+k^Mf*}8{oT%A z#2;6{*6t`t=aE(AFR3ax0Xt@hf(NKx**lP{Oh-~QQnhsZ0s~^|H9>JA*=@7-90f(| zv~|OCws#c^v@|vOYQ|v#fb_d*X!RPJEQTpN20Q!2JS5Vo(Q__n0R=BX*PT4@V1b`= zLzl(_Wu_n~J66Qs3R2cXQr8w0J1#C|o@DxS)9H#bv|Y zigzm(bCULgr3>-GcSl!Y!(y*Xx=NPq@&0?RRaZm8)$q8qF8<<*A<@(=mG;P`JqdTu z<3dloAl{c~I4Bi%$%S1BoS1AC9J`SCDeX_paB6>D>px4Y^42T6ZH{aD4Kh=%SeBl+ zfeneTZfiQhhP7foZ?wqlnA&7?Mjvc@XJB~}V67&e*rajt8Pd$! zX#XoU&1t}nrrFR8r{czU&#b}%#=bM@C|h&XtU7AoCxs4ViKS@H^uSYEl6~nJMZ7VU z1Bd2Ztfip622aL>YSw-bdeIOQsnK|2eV=}A)?!Z96z7%Hb9GN^Fg4cyLG5)7IX=@+ zazmD3$nA>ftTZJ&`|wGRl><`YLAmf?!f}wso4%pHb>{6elA~I7R43FAEQTEzjoc7w z&Y0^-Anid*!aca;TyyVOb?=DRO72~< zdlz`CD|NqkG`t}2uFJ-_0v~31UJEinpjsG(+h%>YPz1Aly|aixL=-0wqzvOJLqHrL znDtZXv%zg4xXB&_aIailx%$cUr_&0EbC6{5;mtRizI^dCq3L(2SnFwMV-17?sbX4B zGY*HjM~;+DwYL|W2+~6ocqsUo0w&$-#$C!qsVDrCQ;OPADu??G6?5>`=S&sqH?T|s zN6QA{@$o>7CE`?3L42NqGxW|lbXt6YZp<$X44h5noM+uAl@pm}=^3u5%ASk(Q?A3D zK5(j4W*ZODk6doiaCikxgmb2Pr?!mR9_SK^H2fL)A19H)U zwW7Y&qCTnUh+K3;$~`LQ9$n~voL@x8b=^-aYo`++Sy-&9HEgXI9EWG{l zotM{~yH=gMAenRSm7ROnoIR_~o`+W?=b-EyTsQ_dd+UM&E(;1uA3I!2#@om59EUYO zIVC9hEFXf)`?HB%oznIL^7aE#`GFsIJQV+=^GC2&@0aqA$oWUe8^KZLji3a6<(wrj z+b@KJ00iVK;ph2~q@?qG{4DvQ;G>4m^5Kx-_SHLADSNn#GgF=j7IW6~1&e*nylvII zEomD}s2@mi$mAXYJEk3y7K&B5YOYLdJCy!N=5E>CoiKMN&82JR>Q!^~{Y&4oevbXnAss>4VZIv?`Ubc@LJ@xbFVi(*V58E=U}FZWHw2!jjfGy4$!bn z6%cBE!MTFAHe~(UYp;c37k=%v(Cf%JudOYeU%`>4rmP}NJCRAT%7@gJK8_)gzG#%v z6#NAZ=J$n5&^>v*0%urh;(++2=}o!x1nnP|#SC|icPcTtk;)1*4wy~>nQq|z2)@K3 zWTicr=F7Zp;xiK8sh9Z{*hLdqC!%6(3dROwCP?Plztgz#;t!otZLeJ03nvo|#-!Q8 zzB92H_F=6#HaiI>WQZwcMX4C~m?5LbsW9UDF-wg430YbhrkXxR!xPex$}nljT* zaTc-RapWc)qsG0e04z*EIMFJYGS5aQr`U`plEg!V=_0fuu-t}2Tz`TpoH7&VF=c~? zW<2*#i5(QRj)EQv&QS0Q1#eOCPbl~f1^<)+I?0S3)59F8FrS!QD}(I3Q?nQbm+r}g4~Tw1OkA|s*CPa!T1bq zDK%cZQ-xRj*Zf(}if0(VKI^F&>U)t?4)^{b1_+PNwCinxAEz^had>ht&?k!io2g=^ z82bXwFP;p~Mii~oRDtd(tzRh%Si5JS(n4o!=9mlT`}?C*(Cn$UleLQz8fB!%9@)}M8^ z;B896Cyl2LpLP3w!(OZ=wGHbox)anOnde$EExn#_*UEW2*G+i*1bQw-OVf!0_yMR} zw@^fAK@_fA>CPtPx$kUWE|PPr*K_GXp5}p4#u;aBOl zbr<^uMh2d-knoxFt}AYm-F5NtgxiOM#MVvp{t0ksVG(l#ck#NF-P(kLl601?qID;G znokjU)*OlKsiqWO*7~oTb{X21P&<6Z=h@do{)^pfg0lvpdH1?$kD(+vFvz~w1^i$E zLpHss^YR$I{p|aR1pup&GSSzs7|ez~!%_=$JMbNUo_}u==6eh|OF%5XR)AQ1We3%REJ6hw_A8r45`+DxY0Zrf#@WAtoltlRXeJVbW2sv~y`bQCKHCcCDM} z#S`5l3yX_xo9-)C_QWO>X7VqnQF6|w9^}eozpg22{jgc^?vCGhVESnOT_|EEVjK%(b$) zcFo+hYHnH?l+62O^L`ML+l?S3w;Pdu!Lc}v@mP4;0Jj(`(NE{)w*IxY6RT|}q_&fC z+eti?3Qoxdrxx;)C6!C(mwQ)^{Naf|IPu`uq~@b?^HFKr(MM5f+bOB!v|Ms}t>pY_ z$@!$Y9A%VJ8KuUAP`I9FG(a^k9pEQ9JKhj12A~XPAV*&6t31K8D`_qOYAwsb`121s z5_S9Ga_(Wt!}*_#C!TvzK6o}!b5<@tmoT6EnaSuuX;qlGs%w+x+@!4zzLRkZVA7U< z$F*#iZFTEbQ*QmwOcs#P4#AR_jOpa>gRIy$sG_=JpuS7nY z{&+fB->TlO=Z+a^zMv5JUpLXs6K6r9ut|1e&SG!j$Jwo!WUcI>P5+SR!{;*go@M#} zm31{O4Ff@RyVS2}GikaZ8b2y%n+i2r5LysX!CDj#p1cX-Z%|K`E}p6s%&|w09zFIa zc-##O*<){B{Rz&dy$NAXZ{N;j9_%cHmkIGSUe1uiQnNP?r!Xh*D@K&>YzkItn_7WGiu71d(KWitVMWm9W-m4L`tB z>|BtdCXF#$jXT&7-WJwWkRSLf;vG>xLKA6B%rl93^oLq6HL{U@knrx5#wfJ#(W8BOp=5r!ClYU$IZ9Gyn*+-#GM{fF~eij7rxz$I1vWg(ibd^=)bK2QJLdUS$0b&a)xHKcl!UXQ^V1<(>y9)dP D7(U-4 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/results.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/results.cpython-311.pyc deleted file mode 100755 index cfe87b006ef63df2ba358e4ce6268e0b0df5d618..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36314 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc deleted file mode 100755 index 4f193a790085d9ad25cff9f2f3727c770316882c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19510 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%0Ar1ruJpRruOXSUXfLgMz1LzMplddL)@U}L=P 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 Vpf=;;LG|U~W0wErQ{J*s{9kIbm!$vz diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc deleted file mode 100755 index 28528b726a8cc2a7326b0f5ca10183afcd577bbe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15368 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/actions.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/actions.py deleted file mode 100755 index f72c66e..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/actions.py +++ /dev/null @@ -1,207 +0,0 @@ -# actions.py - -from .exceptions import ParseException -from .util import col - - -class OnlyOnce: - """ - Wrapper for parse actions, to ensure they are only called once. - """ - - def __init__(self, method_call): - from .core import _trim_arity - - self.callable = _trim_arity(method_call) - self.called = False - - def __call__(self, s, l, t): - if not self.called: - results = self.callable(s, l, t) - self.called = True - return results - raise ParseException(s, l, "OnlyOnce obj called multiple times w/out reset") - - def reset(self): - """ - Allow the associated parse action to be called once more. - """ - - self.called = False - - -def match_only_at_col(n): - """ - Helper method for defining parse actions that require matching at - a specific column in the input text. - """ - - def verify_col(strg, locn, toks): - if col(locn, strg) != n: - raise ParseException(strg, locn, "matched token not at column {}".format(n)) - - return verify_col - - -def replace_with(repl_str): - """ - Helper method for common parse actions that simply return - a literal value. Especially useful when used with - :class:`transform_string` (). - - Example:: - - num = Word(nums).set_parse_action(lambda toks: int(toks[0])) - na = one_of("N/A NA").set_parse_action(replace_with(math.nan)) - term = na | num - - term[1, ...].parse_string("324 234 N/A 234") # -> [324, 234, nan, 234] - """ - return lambda s, l, t: [repl_str] - - -def remove_quotes(s, l, t): - """ - Helper parse action for removing quotation marks from parsed - quoted strings. - - Example:: - - # by default, quotation marks are included in parsed results - quoted_string.parse_string("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"] - - # use remove_quotes to strip quotation marks from parsed results - quoted_string.set_parse_action(remove_quotes) - quoted_string.parse_string("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"] - """ - return t[0][1:-1] - - -def with_attribute(*args, **attr_dict): - """ - Helper to create a validating parse action to be used with start - tags created with :class:`make_xml_tags` or - :class:`make_html_tags`. Use ``with_attribute`` to qualify - a starting tag with a required attribute value, to avoid false - matches on common tags such as ```` or ``

``. - - Call ``with_attribute`` with a series of attribute names and - values. Specify the list of filter attributes names and values as: - - - keyword arguments, as in ``(align="right")``, or - - as an explicit dict with ``**`` operator, when an attribute - name is also a Python reserved word, as in ``**{"class":"Customer", "align":"right"}`` - - a list of name-value tuples, as in ``(("ns1:class", "Customer"), ("ns2:align", "right"))`` - - For attribute names with a namespace prefix, you must use the second - form. Attribute names are matched insensitive to upper/lower case. - - If just testing for ``class`` (with or without a namespace), use - :class:`with_class`. - - To verify that the attribute exists, but without specifying a value, - pass ``with_attribute.ANY_VALUE`` as the value. - - Example:: - - html = ''' -
- Some text -
1 4 0 1 0
-
1,3 2,3 1,1
-
this has no type
-
- - ''' - div,div_end = make_html_tags("div") - - # only match div tag having a type attribute with value "grid" - div_grid = div().set_parse_action(with_attribute(type="grid")) - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.search_string(html): - print(grid_header.body) - - # construct a match with any div tag having a type attribute, regardless of the value - div_any_type = div().set_parse_action(with_attribute(type=with_attribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.search_string(html): - print(div_header.body) - - prints:: - - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - if args: - attrs = args[:] - else: - attrs = attr_dict.items() - attrs = [(k, v) for k, v in attrs] - - def pa(s, l, tokens): - for attrName, attrValue in attrs: - if attrName not in tokens: - raise ParseException(s, l, "no matching attribute " + attrName) - if attrValue != with_attribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException( - s, - l, - "attribute {!r} has value {!r}, must be {!r}".format( - attrName, tokens[attrName], attrValue - ), - ) - - return pa - - -with_attribute.ANY_VALUE = object() - - -def with_class(classname, namespace=""): - """ - Simplified version of :class:`with_attribute` when - matching on a div class - made difficult because ``class`` is - a reserved word in Python. - - Example:: - - html = ''' -
- Some text -
1 4 0 1 0
-
1,3 2,3 1,1
-
this <div> has no class
-
- - ''' - div,div_end = make_html_tags("div") - div_grid = div().set_parse_action(with_class("grid")) - - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.search_string(html): - print(grid_header.body) - - div_any_type = div().set_parse_action(with_class(withAttribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.search_string(html): - print(div_header.body) - - prints:: - - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - classattr = "{}:class".format(namespace) if namespace else "class" - return with_attribute(**{classattr: classname}) - - -# pre-PEP8 compatibility symbols -replaceWith = replace_with -removeQuotes = remove_quotes -withAttribute = with_attribute -withClass = with_class -matchOnlyAtCol = match_only_at_col diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/common.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/common.py deleted file mode 100755 index 1859fb7..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/common.py +++ /dev/null @@ -1,424 +0,0 @@ -# common.py -from .core import * -from .helpers import delimited_list, any_open_tag, any_close_tag -from datetime import datetime - - -# some other useful expressions - using lower-case class name since we are really using this as a namespace -class pyparsing_common: - """Here are some common low-level expressions that may be useful in - jump-starting parser development: - - - numeric forms (:class:`integers`, :class:`reals`, - :class:`scientific notation`) - - common :class:`programming identifiers` - - network addresses (:class:`MAC`, - :class:`IPv4`, :class:`IPv6`) - - ISO8601 :class:`dates` and - :class:`datetime` - - :class:`UUID` - - :class:`comma-separated list` - - :class:`url` - - Parse actions: - - - :class:`convertToInteger` - - :class:`convertToFloat` - - :class:`convertToDate` - - :class:`convertToDatetime` - - :class:`stripHTMLTags` - - :class:`upcaseTokens` - - :class:`downcaseTokens` - - Example:: - - pyparsing_common.number.runTests(''' - # any int or real number, returned as the appropriate type - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.fnumber.runTests(''' - # any int or real number, returned as float - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.hex_integer.runTests(''' - # hex numbers - 100 - FF - ''') - - pyparsing_common.fraction.runTests(''' - # fractions - 1/2 - -3/4 - ''') - - pyparsing_common.mixed_integer.runTests(''' - # mixed fractions - 1 - 1/2 - -3/4 - 1-3/4 - ''') - - import uuid - pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(''' - # uuid - 12345678-1234-5678-1234-567812345678 - ''') - - prints:: - - # any int or real number, returned as the appropriate type - 100 - [100] - - -100 - [-100] - - +100 - [100] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # any int or real number, returned as float - 100 - [100.0] - - -100 - [-100.0] - - +100 - [100.0] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # hex numbers - 100 - [256] - - FF - [255] - - # fractions - 1/2 - [0.5] - - -3/4 - [-0.75] - - # mixed fractions - 1 - [1] - - 1/2 - [0.5] - - -3/4 - [-0.75] - - 1-3/4 - [1.75] - - # uuid - 12345678-1234-5678-1234-567812345678 - [UUID('12345678-1234-5678-1234-567812345678')] - """ - - convert_to_integer = token_map(int) - """ - Parse action for converting parsed integers to Python int - """ - - convert_to_float = token_map(float) - """ - Parse action for converting parsed numbers to Python float - """ - - integer = Word(nums).set_name("integer").set_parse_action(convert_to_integer) - """expression that parses an unsigned integer, returns an int""" - - hex_integer = ( - Word(hexnums).set_name("hex integer").set_parse_action(token_map(int, 16)) - ) - """expression that parses a hexadecimal integer, returns an int""" - - signed_integer = ( - Regex(r"[+-]?\d+") - .set_name("signed integer") - .set_parse_action(convert_to_integer) - ) - """expression that parses an integer with optional leading sign, returns an int""" - - fraction = ( - signed_integer().set_parse_action(convert_to_float) - + "/" - + signed_integer().set_parse_action(convert_to_float) - ).set_name("fraction") - """fractional expression of an integer divided by an integer, returns a float""" - fraction.add_parse_action(lambda tt: tt[0] / tt[-1]) - - mixed_integer = ( - fraction | signed_integer + Opt(Opt("-").suppress() + fraction) - ).set_name("fraction or mixed integer-fraction") - """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" - mixed_integer.add_parse_action(sum) - - real = ( - Regex(r"[+-]?(?:\d+\.\d*|\.\d+)") - .set_name("real number") - .set_parse_action(convert_to_float) - ) - """expression that parses a floating point number and returns a float""" - - sci_real = ( - Regex(r"[+-]?(?:\d+(?:[eE][+-]?\d+)|(?:\d+\.\d*|\.\d+)(?:[eE][+-]?\d+)?)") - .set_name("real number with scientific notation") - .set_parse_action(convert_to_float) - ) - """expression that parses a floating point number with optional - scientific notation and returns a float""" - - # streamlining this expression makes the docs nicer-looking - number = (sci_real | real | signed_integer).setName("number").streamline() - """any numeric expression, returns the corresponding Python type""" - - fnumber = ( - Regex(r"[+-]?\d+\.?\d*([eE][+-]?\d+)?") - .set_name("fnumber") - .set_parse_action(convert_to_float) - ) - """any int or real number, returned as float""" - - identifier = Word(identchars, identbodychars).set_name("identifier") - """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" - - ipv4_address = Regex( - r"(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}" - ).set_name("IPv4 address") - "IPv4 address (``0.0.0.0 - 255.255.255.255``)" - - _ipv6_part = Regex(r"[0-9a-fA-F]{1,4}").set_name("hex_integer") - _full_ipv6_address = (_ipv6_part + (":" + _ipv6_part) * 7).set_name( - "full IPv6 address" - ) - _short_ipv6_address = ( - Opt(_ipv6_part + (":" + _ipv6_part) * (0, 6)) - + "::" - + Opt(_ipv6_part + (":" + _ipv6_part) * (0, 6)) - ).set_name("short IPv6 address") - _short_ipv6_address.add_condition( - lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8 - ) - _mixed_ipv6_address = ("::ffff:" + ipv4_address).set_name("mixed IPv6 address") - ipv6_address = Combine( - (_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).set_name( - "IPv6 address" - ) - ).set_name("IPv6 address") - "IPv6 address (long, short, or mixed form)" - - mac_address = Regex( - r"[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}" - ).set_name("MAC address") - "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" - - @staticmethod - def convert_to_date(fmt: str = "%Y-%m-%d"): - """ - Helper to create a parse action for converting parsed date string to Python datetime.date - - Params - - - fmt - format to be passed to datetime.strptime (default= ``"%Y-%m-%d"``) - - Example:: - - date_expr = pyparsing_common.iso8601_date.copy() - date_expr.setParseAction(pyparsing_common.convertToDate()) - print(date_expr.parseString("1999-12-31")) - - prints:: - - [datetime.date(1999, 12, 31)] - """ - - def cvt_fn(ss, ll, tt): - try: - return datetime.strptime(tt[0], fmt).date() - except ValueError as ve: - raise ParseException(ss, ll, str(ve)) - - return cvt_fn - - @staticmethod - def convert_to_datetime(fmt: str = "%Y-%m-%dT%H:%M:%S.%f"): - """Helper to create a parse action for converting parsed - datetime string to Python datetime.datetime - - Params - - - fmt - format to be passed to datetime.strptime (default= ``"%Y-%m-%dT%H:%M:%S.%f"``) - - Example:: - - dt_expr = pyparsing_common.iso8601_datetime.copy() - dt_expr.setParseAction(pyparsing_common.convertToDatetime()) - print(dt_expr.parseString("1999-12-31T23:59:59.999")) - - prints:: - - [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] - """ - - def cvt_fn(s, l, t): - try: - return datetime.strptime(t[0], fmt) - except ValueError as ve: - raise ParseException(s, l, str(ve)) - - return cvt_fn - - iso8601_date = Regex( - r"(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?" - ).set_name("ISO8601 date") - "ISO8601 date (``yyyy-mm-dd``)" - - iso8601_datetime = Regex( - r"(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?" - ).set_name("ISO8601 datetime") - "ISO8601 datetime (``yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)``) - trailing seconds, milliseconds, and timezone optional; accepts separating ``'T'`` or ``' '``" - - uuid = Regex(r"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}").set_name("UUID") - "UUID (``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx``)" - - _html_stripper = any_open_tag.suppress() | any_close_tag.suppress() - - @staticmethod - def strip_html_tags(s: str, l: int, tokens: ParseResults): - """Parse action to remove HTML tags from web page HTML source - - Example:: - - # strip HTML links from normal text - text = 'More info at the
pyparsing wiki page' - td, td_end = makeHTMLTags("TD") - table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end - print(table_text.parseString(text).body) - - Prints:: - - More info at the pyparsing wiki page - """ - return pyparsing_common._html_stripper.transform_string(tokens[0]) - - _commasepitem = ( - Combine( - OneOrMore( - ~Literal(",") - + ~LineEnd() - + Word(printables, exclude_chars=",") - + Opt(White(" \t") + ~FollowedBy(LineEnd() | ",")) - ) - ) - .streamline() - .set_name("commaItem") - ) - comma_separated_list = delimited_list( - Opt(quoted_string.copy() | _commasepitem, default="") - ).set_name("comma separated list") - """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" - - upcase_tokens = staticmethod(token_map(lambda t: t.upper())) - """Parse action to convert tokens to upper case.""" - - downcase_tokens = staticmethod(token_map(lambda t: t.lower())) - """Parse action to convert tokens to lower case.""" - - # fmt: off - url = Regex( - # https://mathiasbynens.be/demo/url-regex - # https://gist.github.com/dperini/729294 - r"^" + - # protocol identifier (optional) - # short syntax // still required - r"(?:(?:(?Phttps?|ftp):)?\/\/)" + - # user:pass BasicAuth (optional) - r"(?:(?P\S+(?::\S*)?)@)?" + - r"(?P" + - # IP address exclusion - # private & local networks - r"(?!(?:10|127)(?:\.\d{1,3}){3})" + - r"(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})" + - r"(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})" + - # IP address dotted notation octets - # excludes loopback network 0.0.0.0 - # excludes reserved space >= 224.0.0.0 - # excludes network & broadcast addresses - # (first & last IP address of each class) - r"(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])" + - r"(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}" + - r"(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))" + - r"|" + - # host & domain names, may end with dot - # can be replaced by a shortest alternative - # (?![-_])(?:[-\w\u00a1-\uffff]{0,63}[^-_]\.)+ - r"(?:" + - r"(?:" + - r"[a-z0-9\u00a1-\uffff]" + - r"[a-z0-9\u00a1-\uffff_-]{0,62}" + - r")?" + - r"[a-z0-9\u00a1-\uffff]\." + - r")+" + - # TLD identifier name, may end with dot - r"(?:[a-z\u00a1-\uffff]{2,}\.?)" + - r")" + - # port number (optional) - r"(:(?P\d{2,5}))?" + - # resource path (optional) - r"(?P\/[^?# ]*)?" + - # query string (optional) - r"(\?(?P[^#]*))?" + - # fragment (optional) - r"(#(?P\S*))?" + - r"$" - ).set_name("url") - # fmt: on - - # pre-PEP8 compatibility names - convertToInteger = convert_to_integer - convertToFloat = convert_to_float - convertToDate = convert_to_date - convertToDatetime = convert_to_datetime - stripHTMLTags = strip_html_tags - upcaseTokens = upcase_tokens - downcaseTokens = downcase_tokens - - -_builtin_exprs = [ - v for v in vars(pyparsing_common).values() if isinstance(v, ParserElement) -] diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/core.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/core.py deleted file mode 100755 index 9acba3f..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/core.py +++ /dev/null @@ -1,5814 +0,0 @@ -# -# core.py -# -import os -import typing -from typing import ( - NamedTuple, - Union, - Callable, - Any, - Generator, - Tuple, - List, - TextIO, - Set, - Sequence, -) -from abc import ABC, abstractmethod -from enum import Enum -import string -import copy -import warnings -import re -import sys -from collections.abc import Iterable -import traceback -import types -from operator import itemgetter -from functools import wraps -from threading import RLock -from pathlib import Path - -from .util import ( - _FifoCache, - _UnboundedCache, - __config_flags, - _collapse_string_to_ranges, - _escape_regex_range_chars, - _bslash, - _flatten, - LRUMemo as _LRUMemo, - UnboundedMemo as _UnboundedMemo, -) -from .exceptions import * -from .actions import * -from .results import ParseResults, _ParseResultsWithOffset -from .unicode import pyparsing_unicode - -_MAX_INT = sys.maxsize -str_type: Tuple[type, ...] = (str, bytes) - -# -# Copyright (c) 2003-2022 Paul T. McGuire -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - - -if sys.version_info >= (3, 8): - from functools import cached_property -else: - - class cached_property: - def __init__(self, func): - self._func = func - - def __get__(self, instance, owner=None): - ret = instance.__dict__[self._func.__name__] = self._func(instance) - return ret - - -class __compat__(__config_flags): - """ - A cross-version compatibility configuration for pyparsing features that will be - released in a future version. By setting values in this configuration to True, - those features can be enabled in prior versions for compatibility development - and testing. - - - ``collect_all_And_tokens`` - flag to enable fix for Issue #63 that fixes erroneous grouping - of results names when an :class:`And` expression is nested within an :class:`Or` or :class:`MatchFirst`; - maintained for compatibility, but setting to ``False`` no longer restores pre-2.3.1 - behavior - """ - - _type_desc = "compatibility" - - collect_all_And_tokens = True - - _all_names = [__ for __ in locals() if not __.startswith("_")] - _fixed_names = """ - collect_all_And_tokens - """.split() - - -class __diag__(__config_flags): - _type_desc = "diagnostic" - - warn_multiple_tokens_in_named_alternation = False - warn_ungrouped_named_tokens_in_collection = False - warn_name_set_on_empty_Forward = False - warn_on_parse_using_empty_Forward = False - warn_on_assignment_to_Forward = False - warn_on_multiple_string_args_to_oneof = False - warn_on_match_first_with_lshift_operator = False - enable_debug_on_named_expressions = False - - _all_names = [__ for __ in locals() if not __.startswith("_")] - _warning_names = [name for name in _all_names if name.startswith("warn")] - _debug_names = [name for name in _all_names if name.startswith("enable_debug")] - - @classmethod - def enable_all_warnings(cls) -> None: - for name in cls._warning_names: - cls.enable(name) - - -class Diagnostics(Enum): - """ - Diagnostic configuration (all default to disabled) - - ``warn_multiple_tokens_in_named_alternation`` - flag to enable warnings when a results - name is defined on a :class:`MatchFirst` or :class:`Or` expression with one or more :class:`And` subexpressions - - ``warn_ungrouped_named_tokens_in_collection`` - flag to enable warnings when a results - name is defined on a containing expression with ungrouped subexpressions that also - have results names - - ``warn_name_set_on_empty_Forward`` - flag to enable warnings when a :class:`Forward` is defined - with a results name, but has no contents defined - - ``warn_on_parse_using_empty_Forward`` - flag to enable warnings when a :class:`Forward` is - defined in a grammar but has never had an expression attached to it - - ``warn_on_assignment_to_Forward`` - flag to enable warnings when a :class:`Forward` is defined - but is overwritten by assigning using ``'='`` instead of ``'<<='`` or ``'<<'`` - - ``warn_on_multiple_string_args_to_oneof`` - flag to enable warnings when :class:`one_of` is - incorrectly called with multiple str arguments - - ``enable_debug_on_named_expressions`` - flag to auto-enable debug on all subsequent - calls to :class:`ParserElement.set_name` - - Diagnostics are enabled/disabled by calling :class:`enable_diag` and :class:`disable_diag`. - All warnings can be enabled by calling :class:`enable_all_warnings`. - """ - - warn_multiple_tokens_in_named_alternation = 0 - warn_ungrouped_named_tokens_in_collection = 1 - warn_name_set_on_empty_Forward = 2 - warn_on_parse_using_empty_Forward = 3 - warn_on_assignment_to_Forward = 4 - warn_on_multiple_string_args_to_oneof = 5 - warn_on_match_first_with_lshift_operator = 6 - enable_debug_on_named_expressions = 7 - - -def enable_diag(diag_enum: Diagnostics) -> None: - """ - Enable a global pyparsing diagnostic flag (see :class:`Diagnostics`). - """ - __diag__.enable(diag_enum.name) - - -def disable_diag(diag_enum: Diagnostics) -> None: - """ - Disable a global pyparsing diagnostic flag (see :class:`Diagnostics`). - """ - __diag__.disable(diag_enum.name) - - -def enable_all_warnings() -> None: - """ - Enable all global pyparsing diagnostic warnings (see :class:`Diagnostics`). - """ - __diag__.enable_all_warnings() - - -# hide abstract class -del __config_flags - - -def _should_enable_warnings( - cmd_line_warn_options: typing.Iterable[str], warn_env_var: typing.Optional[str] -) -> bool: - enable = bool(warn_env_var) - for warn_opt in cmd_line_warn_options: - w_action, w_message, w_category, w_module, w_line = (warn_opt + "::::").split( - ":" - )[:5] - if not w_action.lower().startswith("i") and ( - not (w_message or w_category or w_module) or w_module == "pyparsing" - ): - enable = True - elif w_action.lower().startswith("i") and w_module in ("pyparsing", ""): - enable = False - return enable - - -if _should_enable_warnings( - sys.warnoptions, os.environ.get("PYPARSINGENABLEALLWARNINGS") -): - enable_all_warnings() - - -# build list of single arg builtins, that can be used as parse actions -_single_arg_builtins = { - sum, - len, - sorted, - reversed, - list, - tuple, - set, - any, - all, - min, - max, -} - -_generatorType = types.GeneratorType -ParseAction = Union[ - Callable[[], Any], - Callable[[ParseResults], Any], - Callable[[int, ParseResults], Any], - Callable[[str, int, ParseResults], Any], -] -ParseCondition = Union[ - Callable[[], bool], - Callable[[ParseResults], bool], - Callable[[int, ParseResults], bool], - Callable[[str, int, ParseResults], bool], -] -ParseFailAction = Callable[[str, int, "ParserElement", Exception], None] -DebugStartAction = Callable[[str, int, "ParserElement", bool], None] -DebugSuccessAction = Callable[ - [str, int, int, "ParserElement", ParseResults, bool], None -] -DebugExceptionAction = Callable[[str, int, "ParserElement", Exception, bool], None] - - -alphas = string.ascii_uppercase + string.ascii_lowercase -identchars = pyparsing_unicode.Latin1.identchars -identbodychars = pyparsing_unicode.Latin1.identbodychars -nums = "0123456789" -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -printables = "".join([c for c in string.printable if c not in string.whitespace]) - -_trim_arity_call_line: traceback.StackSummary = None - - -def _trim_arity(func, max_limit=3): - """decorator to trim function calls to match the arity of the target""" - global _trim_arity_call_line - - if func in _single_arg_builtins: - return lambda s, l, t: func(t) - - limit = 0 - found_arity = False - - def extract_tb(tb, limit=0): - frames = traceback.extract_tb(tb, limit=limit) - frame_summary = frames[-1] - return [frame_summary[:2]] - - # synthesize what would be returned by traceback.extract_stack at the call to - # user's parse action 'func', so that we don't incur call penalty at parse time - - # fmt: off - LINE_DIFF = 7 - # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND - # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! - _trim_arity_call_line = (_trim_arity_call_line or traceback.extract_stack(limit=2)[-1]) - pa_call_line_synth = (_trim_arity_call_line[0], _trim_arity_call_line[1] + LINE_DIFF) - - def wrapper(*args): - nonlocal found_arity, limit - while 1: - try: - ret = func(*args[limit:]) - found_arity = True - return ret - except TypeError as te: - # re-raise TypeErrors if they did not come from our arity testing - if found_arity: - raise - else: - tb = te.__traceback__ - trim_arity_type_error = ( - extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth - ) - del tb - - if trim_arity_type_error: - if limit < max_limit: - limit += 1 - continue - - raise - # fmt: on - - # copy func name to wrapper for sensible debug output - # (can't use functools.wraps, since that messes with function signature) - func_name = getattr(func, "__name__", getattr(func, "__class__").__name__) - wrapper.__name__ = func_name - wrapper.__doc__ = func.__doc__ - - return wrapper - - -def condition_as_parse_action( - fn: ParseCondition, message: str = None, fatal: bool = False -) -> ParseAction: - """ - Function to convert a simple predicate function that returns ``True`` or ``False`` - into a parse action. Can be used in places when a parse action is required - and :class:`ParserElement.add_condition` cannot be used (such as when adding a condition - to an operator level in :class:`infix_notation`). - - Optional keyword arguments: - - - ``message`` - define a custom message to be used in the raised exception - - ``fatal`` - if True, will raise :class:`ParseFatalException` to stop parsing immediately; - otherwise will raise :class:`ParseException` - - """ - msg = message if message is not None else "failed user-defined condition" - exc_type = ParseFatalException if fatal else ParseException - fn = _trim_arity(fn) - - @wraps(fn) - def pa(s, l, t): - if not bool(fn(s, l, t)): - raise exc_type(s, l, msg) - - return pa - - -def _default_start_debug_action( - instring: str, loc: int, expr: "ParserElement", cache_hit: bool = False -): - cache_hit_str = "*" if cache_hit else "" - print( - ( - "{}Match {} at loc {}({},{})\n {}\n {}^".format( - cache_hit_str, - expr, - loc, - lineno(loc, instring), - col(loc, instring), - line(loc, instring), - " " * (col(loc, instring) - 1), - ) - ) - ) - - -def _default_success_debug_action( - instring: str, - startloc: int, - endloc: int, - expr: "ParserElement", - toks: ParseResults, - cache_hit: bool = False, -): - cache_hit_str = "*" if cache_hit else "" - print("{}Matched {} -> {}".format(cache_hit_str, expr, toks.as_list())) - - -def _default_exception_debug_action( - instring: str, - loc: int, - expr: "ParserElement", - exc: Exception, - cache_hit: bool = False, -): - cache_hit_str = "*" if cache_hit else "" - print( - "{}Match {} failed, {} raised: {}".format( - cache_hit_str, expr, type(exc).__name__, exc - ) - ) - - -def null_debug_action(*args): - """'Do-nothing' debug action, to suppress debugging output during parsing.""" - - -class ParserElement(ABC): - """Abstract base level parser element class.""" - - DEFAULT_WHITE_CHARS: str = " \n\t\r" - verbose_stacktrace: bool = False - _literalStringClass: typing.Optional[type] = None - - @staticmethod - def set_default_whitespace_chars(chars: str) -> None: - r""" - Overrides the default whitespace chars - - Example:: - - # default whitespace chars are space, and newline - Word(alphas)[1, ...].parse_string("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] - - # change to just treat newline as significant - ParserElement.set_default_whitespace_chars(" \t") - Word(alphas)[1, ...].parse_string("abc def\nghi jkl") # -> ['abc', 'def'] - """ - ParserElement.DEFAULT_WHITE_CHARS = chars - - # update whitespace all parse expressions defined in this module - for expr in _builtin_exprs: - if expr.copyDefaultWhiteChars: - expr.whiteChars = set(chars) - - @staticmethod - def inline_literals_using(cls: type) -> None: - """ - Set class to be used for inclusion of string literals into a parser. - - Example:: - - # default literal class used is Literal - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parse_string("1999/12/31") # -> ['1999', '/', '12', '/', '31'] - - - # change to Suppress - ParserElement.inline_literals_using(Suppress) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parse_string("1999/12/31") # -> ['1999', '12', '31'] - """ - ParserElement._literalStringClass = cls - - class DebugActions(NamedTuple): - debug_try: typing.Optional[DebugStartAction] - debug_match: typing.Optional[DebugSuccessAction] - debug_fail: typing.Optional[DebugExceptionAction] - - def __init__(self, savelist: bool = False): - self.parseAction: List[ParseAction] = list() - self.failAction: typing.Optional[ParseFailAction] = None - self.customName = None - self._defaultName = None - self.resultsName = None - self.saveAsList = savelist - self.skipWhitespace = True - self.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS) - self.copyDefaultWhiteChars = True - # used when checking for left-recursion - self.mayReturnEmpty = False - self.keepTabs = False - self.ignoreExprs: List["ParserElement"] = list() - self.debug = False - self.streamlined = False - # optimize exception handling for subclasses that don't advance parse index - self.mayIndexError = True - self.errmsg = "" - # mark results names as modal (report only last) or cumulative (list all) - self.modalResults = True - # custom debug actions - self.debugActions = self.DebugActions(None, None, None) - # avoid redundant calls to preParse - self.callPreparse = True - self.callDuringTry = False - self.suppress_warnings_: List[Diagnostics] = [] - - def suppress_warning(self, warning_type: Diagnostics) -> "ParserElement": - """ - Suppress warnings emitted for a particular diagnostic on this expression. - - Example:: - - base = pp.Forward() - base.suppress_warning(Diagnostics.warn_on_parse_using_empty_Forward) - - # statement would normally raise a warning, but is now suppressed - print(base.parseString("x")) - - """ - self.suppress_warnings_.append(warning_type) - return self - - def copy(self) -> "ParserElement": - """ - Make a copy of this :class:`ParserElement`. Useful for defining - different parse actions for the same parsing pattern, using copies of - the original parse element. - - Example:: - - integer = Word(nums).set_parse_action(lambda toks: int(toks[0])) - integerK = integer.copy().add_parse_action(lambda toks: toks[0] * 1024) + Suppress("K") - integerM = integer.copy().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M") - - print((integerK | integerM | integer)[1, ...].parse_string("5K 100 640K 256M")) - - prints:: - - [5120, 100, 655360, 268435456] - - Equivalent form of ``expr.copy()`` is just ``expr()``:: - - integerM = integer().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M") - """ - cpy = copy.copy(self) - cpy.parseAction = self.parseAction[:] - cpy.ignoreExprs = self.ignoreExprs[:] - if self.copyDefaultWhiteChars: - cpy.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS) - return cpy - - def set_results_name( - self, name: str, list_all_matches: bool = False, *, listAllMatches: bool = False - ) -> "ParserElement": - """ - Define name for referencing matching tokens as a nested attribute - of the returned parse results. - - Normally, results names are assigned as you would assign keys in a dict: - any existing value is overwritten by later values. If it is necessary to - keep all values captured for a particular results name, call ``set_results_name`` - with ``list_all_matches`` = True. - - NOTE: ``set_results_name`` returns a *copy* of the original :class:`ParserElement` object; - this is so that the client can define a basic element, such as an - integer, and reference it in multiple places with different names. - - You can also set results names using the abbreviated syntax, - ``expr("name")`` in place of ``expr.set_results_name("name")`` - - see :class:`__call__`. If ``list_all_matches`` is required, use - ``expr("name*")``. - - Example:: - - date_str = (integer.set_results_name("year") + '/' - + integer.set_results_name("month") + '/' - + integer.set_results_name("day")) - - # equivalent form: - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - """ - listAllMatches = listAllMatches or list_all_matches - return self._setResultsName(name, listAllMatches) - - def _setResultsName(self, name, listAllMatches=False): - if name is None: - return self - newself = self.copy() - if name.endswith("*"): - name = name[:-1] - listAllMatches = True - newself.resultsName = name - newself.modalResults = not listAllMatches - return newself - - def set_break(self, break_flag: bool = True) -> "ParserElement": - """ - Method to invoke the Python pdb debugger when this element is - about to be parsed. Set ``break_flag`` to ``True`` to enable, ``False`` to - disable. - """ - if break_flag: - _parseMethod = self._parse - - def breaker(instring, loc, doActions=True, callPreParse=True): - import pdb - - # this call to pdb.set_trace() is intentional, not a checkin error - pdb.set_trace() - return _parseMethod(instring, loc, doActions, callPreParse) - - breaker._originalParseMethod = _parseMethod - self._parse = breaker - else: - if hasattr(self._parse, "_originalParseMethod"): - self._parse = self._parse._originalParseMethod - return self - - def set_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement": - """ - Define one or more actions to perform when successfully matching parse element definition. - - Parse actions can be called to perform data conversions, do extra validation, - update external data structures, or enhance or replace the parsed tokens. - Each parse action ``fn`` is a callable method with 0-3 arguments, called as - ``fn(s, loc, toks)`` , ``fn(loc, toks)`` , ``fn(toks)`` , or just ``fn()`` , where: - - - s = the original string being parsed (see note below) - - loc = the location of the matching substring - - toks = a list of the matched tokens, packaged as a :class:`ParseResults` object - - The parsed tokens are passed to the parse action as ParseResults. They can be - modified in place using list-style append, extend, and pop operations to update - the parsed list elements; and with dictionary-style item set and del operations - to add, update, or remove any named results. If the tokens are modified in place, - it is not necessary to return them with a return statement. - - Parse actions can also completely replace the given tokens, with another ``ParseResults`` - object, or with some entirely different object (common for parse actions that perform data - conversions). A convenient way to build a new parse result is to define the values - using a dict, and then create the return value using :class:`ParseResults.from_dict`. - - If None is passed as the ``fn`` parse action, all previously added parse actions for this - expression are cleared. - - Optional keyword arguments: - - - call_during_try = (default= ``False``) indicate if parse action should be run during - lookaheads and alternate testing. For parse actions that have side effects, it is - important to only call the parse action once it is determined that it is being - called as part of a successful parse. For parse actions that perform additional - validation, then call_during_try should be passed as True, so that the validation - code is included in the preliminary "try" parses. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See :class:`parse_string` for more - information on parsing strings containing ```` s, and suggested - methods to maintain a consistent view of the parsed string, the parse - location, and line and column positions within the parsed string. - - Example:: - - # parse dates in the form YYYY/MM/DD - - # use parse action to convert toks from str to int at parse time - def convert_to_int(toks): - return int(toks[0]) - - # use a parse action to verify that the date is a valid date - def is_valid_date(instring, loc, toks): - from datetime import date - year, month, day = toks[::2] - try: - date(year, month, day) - except ValueError: - raise ParseException(instring, loc, "invalid date given") - - integer = Word(nums) - date_str = integer + '/' + integer + '/' + integer - - # add parse actions - integer.set_parse_action(convert_to_int) - date_str.set_parse_action(is_valid_date) - - # note that integer fields are now ints, not strings - date_str.run_tests(''' - # successful parse - note that integer fields were converted to ints - 1999/12/31 - - # fail - invalid date - 1999/13/31 - ''') - """ - if list(fns) == [None]: - self.parseAction = [] - else: - if not all(callable(fn) for fn in fns): - raise TypeError("parse actions must be callable") - self.parseAction = [_trim_arity(fn) for fn in fns] - self.callDuringTry = kwargs.get( - "call_during_try", kwargs.get("callDuringTry", False) - ) - return self - - def add_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement": - """ - Add one or more parse actions to expression's list of parse actions. See :class:`set_parse_action`. - - See examples in :class:`copy`. - """ - self.parseAction += [_trim_arity(fn) for fn in fns] - self.callDuringTry = self.callDuringTry or kwargs.get( - "call_during_try", kwargs.get("callDuringTry", False) - ) - return self - - def add_condition(self, *fns: ParseCondition, **kwargs) -> "ParserElement": - """Add a boolean predicate function to expression's list of parse actions. See - :class:`set_parse_action` for function call signatures. Unlike ``set_parse_action``, - functions passed to ``add_condition`` need to return boolean success/fail of the condition. - - Optional keyword arguments: - - - message = define a custom message to be used in the raised exception - - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise - ParseException - - call_during_try = boolean to indicate if this method should be called during internal tryParse calls, - default=False - - Example:: - - integer = Word(nums).set_parse_action(lambda toks: int(toks[0])) - year_int = integer.copy() - year_int.add_condition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") - date_str = year_int + '/' + integer + '/' + integer - - result = date_str.parse_string("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), - (line:1, col:1) - """ - for fn in fns: - self.parseAction.append( - condition_as_parse_action( - fn, message=kwargs.get("message"), fatal=kwargs.get("fatal", False) - ) - ) - - self.callDuringTry = self.callDuringTry or kwargs.get( - "call_during_try", kwargs.get("callDuringTry", False) - ) - return self - - def set_fail_action(self, fn: ParseFailAction) -> "ParserElement": - """ - Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - ``fn(s, loc, expr, err)`` where: - - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - - The function returns no value. It may throw :class:`ParseFatalException` - if it is desired to stop parsing immediately.""" - self.failAction = fn - return self - - def _skipIgnorables(self, instring, loc): - exprsFound = True - while exprsFound: - exprsFound = False - for e in self.ignoreExprs: - try: - while 1: - loc, dummy = e._parse(instring, loc) - exprsFound = True - except ParseException: - pass - return loc - - def preParse(self, instring, loc): - if self.ignoreExprs: - loc = self._skipIgnorables(instring, loc) - - if self.skipWhitespace: - instrlen = len(instring) - white_chars = self.whiteChars - while loc < instrlen and instring[loc] in white_chars: - loc += 1 - - return loc - - def parseImpl(self, instring, loc, doActions=True): - return loc, [] - - def postParse(self, instring, loc, tokenlist): - return tokenlist - - # @profile - def _parseNoCache( - self, instring, loc, doActions=True, callPreParse=True - ) -> Tuple[int, ParseResults]: - TRY, MATCH, FAIL = 0, 1, 2 - debugging = self.debug # and doActions) - len_instring = len(instring) - - if debugging or self.failAction: - # print("Match {} at loc {}({}, {})".format(self, loc, lineno(loc, instring), col(loc, instring))) - try: - if callPreParse and self.callPreparse: - pre_loc = self.preParse(instring, loc) - else: - pre_loc = loc - tokens_start = pre_loc - if self.debugActions.debug_try: - self.debugActions.debug_try(instring, tokens_start, self, False) - if self.mayIndexError or pre_loc >= len_instring: - try: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) - except IndexError: - raise ParseException(instring, len_instring, self.errmsg, self) - else: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) - except Exception as err: - # print("Exception raised:", err) - if self.debugActions.debug_fail: - self.debugActions.debug_fail( - instring, tokens_start, self, err, False - ) - if self.failAction: - self.failAction(instring, tokens_start, self, err) - raise - else: - if callPreParse and self.callPreparse: - pre_loc = self.preParse(instring, loc) - else: - pre_loc = loc - tokens_start = pre_loc - if self.mayIndexError or pre_loc >= len_instring: - try: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) - except IndexError: - raise ParseException(instring, len_instring, self.errmsg, self) - else: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) - - tokens = self.postParse(instring, loc, tokens) - - ret_tokens = ParseResults( - tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults - ) - if self.parseAction and (doActions or self.callDuringTry): - if debugging: - try: - for fn in self.parseAction: - try: - tokens = fn(instring, tokens_start, ret_tokens) - except IndexError as parse_action_exc: - exc = ParseException("exception raised in parse action") - raise exc from parse_action_exc - - if tokens is not None and tokens is not ret_tokens: - ret_tokens = ParseResults( - tokens, - self.resultsName, - asList=self.saveAsList - and isinstance(tokens, (ParseResults, list)), - modal=self.modalResults, - ) - except Exception as err: - # print "Exception raised in user parse action:", err - if self.debugActions.debug_fail: - self.debugActions.debug_fail( - instring, tokens_start, self, err, False - ) - raise - else: - for fn in self.parseAction: - try: - tokens = fn(instring, tokens_start, ret_tokens) - except IndexError as parse_action_exc: - exc = ParseException("exception raised in parse action") - raise exc from parse_action_exc - - if tokens is not None and tokens is not ret_tokens: - ret_tokens = ParseResults( - tokens, - self.resultsName, - asList=self.saveAsList - and isinstance(tokens, (ParseResults, list)), - modal=self.modalResults, - ) - if debugging: - # print("Matched", self, "->", ret_tokens.as_list()) - if self.debugActions.debug_match: - self.debugActions.debug_match( - instring, tokens_start, loc, self, ret_tokens, False - ) - - return loc, ret_tokens - - def try_parse(self, instring: str, loc: int, raise_fatal: bool = False) -> int: - try: - return self._parse(instring, loc, doActions=False)[0] - except ParseFatalException: - if raise_fatal: - raise - raise ParseException(instring, loc, self.errmsg, self) - - def can_parse_next(self, instring: str, loc: int) -> bool: - try: - self.try_parse(instring, loc) - except (ParseException, IndexError): - return False - else: - return True - - # cache for left-recursion in Forward references - recursion_lock = RLock() - recursion_memos: typing.Dict[ - Tuple[int, "Forward", bool], Tuple[int, Union[ParseResults, Exception]] - ] = {} - - # argument cache for optimizing repeated calls when backtracking through recursive expressions - packrat_cache = ( - {} - ) # this is set later by enabled_packrat(); this is here so that reset_cache() doesn't fail - packrat_cache_lock = RLock() - packrat_cache_stats = [0, 0] - - # this method gets repeatedly called during backtracking with the same arguments - - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( - self, instring, loc, doActions=True, callPreParse=True - ) -> Tuple[int, ParseResults]: - HIT, MISS = 0, 1 - TRY, MATCH, FAIL = 0, 1, 2 - lookup = (self, instring, loc, callPreParse, doActions) - with ParserElement.packrat_cache_lock: - cache = ParserElement.packrat_cache - value = cache.get(lookup) - if value is cache.not_in_cache: - ParserElement.packrat_cache_stats[MISS] += 1 - try: - value = self._parseNoCache(instring, loc, doActions, callPreParse) - except ParseBaseException as pe: - # cache a copy of the exception, without the traceback - cache.set(lookup, pe.__class__(*pe.args)) - raise - else: - cache.set(lookup, (value[0], value[1].copy(), loc)) - return value - else: - ParserElement.packrat_cache_stats[HIT] += 1 - if self.debug and self.debugActions.debug_try: - try: - self.debugActions.debug_try(instring, loc, self, cache_hit=True) - except TypeError: - pass - if isinstance(value, Exception): - if self.debug and self.debugActions.debug_fail: - try: - self.debugActions.debug_fail( - instring, loc, self, value, cache_hit=True - ) - except TypeError: - pass - raise value - - loc_, result, endloc = value[0], value[1].copy(), value[2] - if self.debug and self.debugActions.debug_match: - try: - self.debugActions.debug_match( - instring, loc_, endloc, self, result, cache_hit=True - ) - except TypeError: - pass - - return loc_, result - - _parse = _parseNoCache - - @staticmethod - def reset_cache() -> None: - ParserElement.packrat_cache.clear() - ParserElement.packrat_cache_stats[:] = [0] * len( - ParserElement.packrat_cache_stats - ) - ParserElement.recursion_memos.clear() - - _packratEnabled = False - _left_recursion_enabled = False - - @staticmethod - def disable_memoization() -> None: - """ - Disables active Packrat or Left Recursion parsing and their memoization - - This method also works if neither Packrat nor Left Recursion are enabled. - This makes it safe to call before activating Packrat nor Left Recursion - to clear any previous settings. - """ - ParserElement.reset_cache() - ParserElement._left_recursion_enabled = False - ParserElement._packratEnabled = False - ParserElement._parse = ParserElement._parseNoCache - - @staticmethod - def enable_left_recursion( - cache_size_limit: typing.Optional[int] = None, *, force=False - ) -> None: - """ - Enables "bounded recursion" parsing, which allows for both direct and indirect - left-recursion. During parsing, left-recursive :class:`Forward` elements are - repeatedly matched with a fixed recursion depth that is gradually increased - until finding the longest match. - - Example:: - - import pyparsing as pp - pp.ParserElement.enable_left_recursion() - - E = pp.Forward("E") - num = pp.Word(pp.nums) - # match `num`, or `num '+' num`, or `num '+' num '+' num`, ... - E <<= E + '+' - num | num - - print(E.parse_string("1+2+3")) - - Recursion search naturally memoizes matches of ``Forward`` elements and may - thus skip reevaluation of parse actions during backtracking. This may break - programs with parse actions which rely on strict ordering of side-effects. - - Parameters: - - - cache_size_limit - (default=``None``) - memoize at most this many - ``Forward`` elements during matching; if ``None`` (the default), - memoize all ``Forward`` elements. - - Bounded Recursion parsing works similar but not identical to Packrat parsing, - thus the two cannot be used together. Use ``force=True`` to disable any - previous, conflicting settings. - """ - if force: - ParserElement.disable_memoization() - elif ParserElement._packratEnabled: - raise RuntimeError("Packrat and Bounded Recursion are not compatible") - if cache_size_limit is None: - ParserElement.recursion_memos = _UnboundedMemo() - elif cache_size_limit > 0: - ParserElement.recursion_memos = _LRUMemo(capacity=cache_size_limit) - else: - raise NotImplementedError("Memo size of %s" % cache_size_limit) - ParserElement._left_recursion_enabled = True - - @staticmethod - def enable_packrat(cache_size_limit: int = 128, *, force: bool = False) -> None: - """ - Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - Parameters: - - - cache_size_limit - (default= ``128``) - if an integer value is provided - will limit the size of the packrat cache; if None is passed, then - the cache size will be unbounded; if 0 is passed, the cache will - be effectively disabled. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method :class:`ParserElement.enable_packrat`. - For best results, call ``enable_packrat()`` immediately after - importing pyparsing. - - Example:: - - import pyparsing - pyparsing.ParserElement.enable_packrat() - - Packrat parsing works similar but not identical to Bounded Recursion parsing, - thus the two cannot be used together. Use ``force=True`` to disable any - previous, conflicting settings. - """ - if force: - ParserElement.disable_memoization() - elif ParserElement._left_recursion_enabled: - raise RuntimeError("Packrat and Bounded Recursion are not compatible") - if not ParserElement._packratEnabled: - ParserElement._packratEnabled = True - if cache_size_limit is None: - ParserElement.packrat_cache = _UnboundedCache() - else: - ParserElement.packrat_cache = _FifoCache(cache_size_limit) - ParserElement._parse = ParserElement._parseCache - - def parse_string( - self, instring: str, parse_all: bool = False, *, parseAll: bool = False - ) -> ParseResults: - """ - Parse a string with respect to the parser definition. This function is intended as the primary interface to the - client code. - - :param instring: The input string to be parsed. - :param parse_all: If set, the entire input string must match the grammar. - :param parseAll: retained for pre-PEP8 compatibility, will be removed in a future release. - :raises ParseException: Raised if ``parse_all`` is set and the input string does not match the whole grammar. - :returns: the parsed data as a :class:`ParseResults` object, which may be accessed as a `list`, a `dict`, or - an object with attributes if the given parser includes results names. - - If the input string is required to match the entire grammar, ``parse_all`` flag must be set to ``True``. This - is also equivalent to ending the grammar with :class:`StringEnd`(). - - To report proper column numbers, ``parse_string`` operates on a copy of the input string where all tabs are - converted to spaces (8 spaces per tab, as per the default in ``string.expandtabs``). If the input string - contains tabs and the grammar uses parse actions that use the ``loc`` argument to index into the string - being parsed, one can ensure a consistent view of the input string by doing one of the following: - - - calling ``parse_with_tabs`` on your grammar before calling ``parse_string`` (see :class:`parse_with_tabs`), - - define your parse action using the full ``(s,loc,toks)`` signature, and reference the input string using the - parse action's ``s`` argument, or - - explicitly expand the tabs in your input string before calling ``parse_string``. - - Examples: - - By default, partial matches are OK. - - >>> res = Word('a').parse_string('aaaaabaaa') - >>> print(res) - ['aaaaa'] - - The parsing behavior varies by the inheriting class of this abstract class. Please refer to the children - directly to see more examples. - - It raises an exception if parse_all flag is set and instring does not match the whole grammar. - - >>> res = Word('a').parse_string('aaaaabaaa', parse_all=True) - Traceback (most recent call last): - ... - pyparsing.ParseException: Expected end of text, found 'b' (at char 5), (line:1, col:6) - """ - parseAll = parse_all or parseAll - - ParserElement.reset_cache() - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - if not self.keepTabs: - instring = instring.expandtabs() - try: - loc, tokens = self._parse(instring, 0) - if parseAll: - loc = self.preParse(instring, loc) - se = Empty() + StringEnd() - se._parse(instring, loc) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clearing out pyparsing internal stack trace - raise exc.with_traceback(None) - else: - return tokens - - def scan_string( - self, - instring: str, - max_matches: int = _MAX_INT, - overlap: bool = False, - *, - debug: bool = False, - maxMatches: int = _MAX_INT, - ) -> Generator[Tuple[ParseResults, int, int], None, None]: - """ - Scan the input string for expression matches. Each match will return the - matching tokens, start location, and end location. May be called with optional - ``max_matches`` argument, to clip scanning after 'n' matches are found. If - ``overlap`` is specified, then overlapping matches will be reported. - - Note that the start and end locations are reported relative to the string - being parsed. See :class:`parse_string` for more information on parsing - strings with embedded tabs. - - Example:: - - source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" - print(source) - for tokens, start, end in Word(alphas).scan_string(source): - print(' '*start + '^'*(end-start)) - print(' '*start + tokens[0]) - - prints:: - - sldjf123lsdjjkf345sldkjf879lkjsfd987 - ^^^^^ - sldjf - ^^^^^^^ - lsdjjkf - ^^^^^^ - sldkjf - ^^^^^^ - lkjsfd - """ - maxMatches = min(maxMatches, max_matches) - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - - if not self.keepTabs: - instring = str(instring).expandtabs() - instrlen = len(instring) - loc = 0 - preparseFn = self.preParse - parseFn = self._parse - ParserElement.resetCache() - matches = 0 - try: - while loc <= instrlen and matches < maxMatches: - try: - preloc = preparseFn(instring, loc) - nextLoc, tokens = parseFn(instring, preloc, callPreParse=False) - except ParseException: - loc = preloc + 1 - else: - if nextLoc > loc: - matches += 1 - if debug: - print( - { - "tokens": tokens.asList(), - "start": preloc, - "end": nextLoc, - } - ) - yield tokens, preloc, nextLoc - if overlap: - nextloc = preparseFn(instring, loc) - if nextloc > loc: - loc = nextLoc - else: - loc += 1 - else: - loc = nextLoc - else: - loc = preloc + 1 - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc.with_traceback(None) - - def transform_string(self, instring: str, *, debug: bool = False) -> str: - """ - Extension to :class:`scan_string`, to modify matching text with modified tokens that may - be returned from a parse action. To use ``transform_string``, define a grammar and - attach a parse action to it that modifies the returned token list. - Invoking ``transform_string()`` on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. ``transform_string()`` returns the resulting transformed string. - - Example:: - - wd = Word(alphas) - wd.set_parse_action(lambda toks: toks[0].title()) - - print(wd.transform_string("now is the winter of our discontent made glorious summer by this sun of york.")) - - prints:: - - Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. - """ - out: List[str] = [] - lastE = 0 - # force preservation of s, to minimize unwanted transformation of string, and to - # keep string locs straight between transform_string and scan_string - self.keepTabs = True - try: - for t, s, e in self.scan_string(instring, debug=debug): - out.append(instring[lastE:s]) - if t: - if isinstance(t, ParseResults): - out += t.as_list() - elif isinstance(t, Iterable) and not isinstance(t, str_type): - out.extend(t) - else: - out.append(t) - lastE = e - out.append(instring[lastE:]) - out = [o for o in out if o] - return "".join([str(s) for s in _flatten(out)]) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc.with_traceback(None) - - def search_string( - self, - instring: str, - max_matches: int = _MAX_INT, - *, - debug: bool = False, - maxMatches: int = _MAX_INT, - ) -> ParseResults: - """ - Another extension to :class:`scan_string`, simplifying the access to the tokens found - to match the given parse expression. May be called with optional - ``max_matches`` argument, to clip searching after 'n' matches are found. - - Example:: - - # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters - cap_word = Word(alphas.upper(), alphas.lower()) - - print(cap_word.search_string("More than Iron, more than Lead, more than Gold I need Electricity")) - - # the sum() builtin can be used to merge results into a single ParseResults object - print(sum(cap_word.search_string("More than Iron, more than Lead, more than Gold I need Electricity"))) - - prints:: - - [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']] - ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] - """ - maxMatches = min(maxMatches, max_matches) - try: - return ParseResults( - [t for t, s, e in self.scan_string(instring, maxMatches, debug=debug)] - ) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc.with_traceback(None) - - def split( - self, - instring: str, - maxsplit: int = _MAX_INT, - include_separators: bool = False, - *, - includeSeparators=False, - ) -> Generator[str, None, None]: - """ - Generator method to split a string using the given expression as a separator. - May be called with optional ``maxsplit`` argument, to limit the number of splits; - and the optional ``include_separators`` argument (default= ``False``), if the separating - matching text should be included in the split results. - - Example:: - - punc = one_of(list(".,;:/-!?")) - print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) - - prints:: - - ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] - """ - includeSeparators = includeSeparators or include_separators - last = 0 - for t, s, e in self.scan_string(instring, max_matches=maxsplit): - yield instring[last:s] - if includeSeparators: - yield t[0] - last = e - yield instring[last:] - - def __add__(self, other) -> "ParserElement": - """ - Implementation of ``+`` operator - returns :class:`And`. Adding strings to a :class:`ParserElement` - converts them to :class:`Literal`s by default. - - Example:: - - greet = Word(alphas) + "," + Word(alphas) + "!" - hello = "Hello, World!" - print(hello, "->", greet.parse_string(hello)) - - prints:: - - Hello, World! -> ['Hello', ',', 'World', '!'] - - ``...`` may be used as a parse expression as a short form of :class:`SkipTo`. - - Literal('start') + ... + Literal('end') - - is equivalent to: - - Literal('start') + SkipTo('end')("_skipped*") + Literal('end') - - Note that the skipped text is returned with '_skipped' as a results name, - and to support having multiple skips in the same parser, the value returned is - a list of all skipped text. - """ - if other is Ellipsis: - return _PendingSkip(self) - - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return And([self, other]) - - def __radd__(self, other) -> "ParserElement": - """ - Implementation of ``+`` operator when left operand is not a :class:`ParserElement` - """ - if other is Ellipsis: - return SkipTo(self)("_skipped*") + self - - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other + self - - def __sub__(self, other) -> "ParserElement": - """ - Implementation of ``-`` operator, returns :class:`And` with error stop - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return self + And._ErrorStop() + other - - def __rsub__(self, other) -> "ParserElement": - """ - Implementation of ``-`` operator when left operand is not a :class:`ParserElement` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other - self - - def __mul__(self, other) -> "ParserElement": - """ - Implementation of ``*`` operator, allows use of ``expr * 3`` in place of - ``expr + expr + expr``. Expressions may also be multiplied by a 2-integer - tuple, similar to ``{min, max}`` multipliers in regular expressions. Tuples - may also include ``None`` as in: - - ``expr*(n, None)`` or ``expr*(n, )`` is equivalent - to ``expr*n + ZeroOrMore(expr)`` - (read as "at least n instances of ``expr``") - - ``expr*(None, n)`` is equivalent to ``expr*(0, n)`` - (read as "0 to n instances of ``expr``") - - ``expr*(None, None)`` is equivalent to ``ZeroOrMore(expr)`` - - ``expr*(1, None)`` is equivalent to ``OneOrMore(expr)`` - - Note that ``expr*(None, n)`` does not raise an exception if - more than n exprs exist in the input stream; that is, - ``expr*(None, n)`` does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - ``expr*(None, n) + ~expr`` - """ - if other is Ellipsis: - other = (0, None) - elif isinstance(other, tuple) and other[:1] == (Ellipsis,): - other = ((0,) + other[1:] + (None,))[:2] - - if isinstance(other, int): - minElements, optElements = other, 0 - elif isinstance(other, tuple): - other = tuple(o if o is not Ellipsis else None for o in other) - other = (other + (None, None))[:2] - if other[0] is None: - other = (0, other[1]) - if isinstance(other[0], int) and other[1] is None: - if other[0] == 0: - return ZeroOrMore(self) - if other[0] == 1: - return OneOrMore(self) - else: - return self * other[0] + ZeroOrMore(self) - elif isinstance(other[0], int) and isinstance(other[1], int): - minElements, optElements = other - optElements -= minElements - else: - raise TypeError( - "cannot multiply ParserElement and ({}) objects".format( - ",".join(type(item).__name__ for item in other) - ) - ) - else: - raise TypeError( - "cannot multiply ParserElement and {} objects".format( - type(other).__name__ - ) - ) - - if minElements < 0: - raise ValueError("cannot multiply ParserElement by negative value") - if optElements < 0: - raise ValueError( - "second tuple value must be greater or equal to first tuple value" - ) - if minElements == optElements == 0: - return And([]) - - if optElements: - - def makeOptionalList(n): - if n > 1: - return Opt(self + makeOptionalList(n - 1)) - else: - return Opt(self) - - if minElements: - if minElements == 1: - ret = self + makeOptionalList(optElements) - else: - ret = And([self] * minElements) + makeOptionalList(optElements) - else: - ret = makeOptionalList(optElements) - else: - if minElements == 1: - ret = self - else: - ret = And([self] * minElements) - return ret - - def __rmul__(self, other) -> "ParserElement": - return self.__mul__(other) - - def __or__(self, other) -> "ParserElement": - """ - Implementation of ``|`` operator - returns :class:`MatchFirst` - """ - if other is Ellipsis: - return _PendingSkip(self, must_skip=True) - - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return MatchFirst([self, other]) - - def __ror__(self, other) -> "ParserElement": - """ - Implementation of ``|`` operator when left operand is not a :class:`ParserElement` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other | self - - def __xor__(self, other) -> "ParserElement": - """ - Implementation of ``^`` operator - returns :class:`Or` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return Or([self, other]) - - def __rxor__(self, other) -> "ParserElement": - """ - Implementation of ``^`` operator when left operand is not a :class:`ParserElement` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other ^ self - - def __and__(self, other) -> "ParserElement": - """ - Implementation of ``&`` operator - returns :class:`Each` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return Each([self, other]) - - def __rand__(self, other) -> "ParserElement": - """ - Implementation of ``&`` operator when left operand is not a :class:`ParserElement` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other & self - - def __invert__(self) -> "ParserElement": - """ - Implementation of ``~`` operator - returns :class:`NotAny` - """ - return NotAny(self) - - # disable __iter__ to override legacy use of sequential access to __getitem__ to - # iterate over a sequence - __iter__ = None - - def __getitem__(self, key): - """ - use ``[]`` indexing notation as a short form for expression repetition: - - - ``expr[n]`` is equivalent to ``expr*n`` - - ``expr[m, n]`` is equivalent to ``expr*(m, n)`` - - ``expr[n, ...]`` or ``expr[n,]`` is equivalent - to ``expr*n + ZeroOrMore(expr)`` - (read as "at least n instances of ``expr``") - - ``expr[..., n]`` is equivalent to ``expr*(0, n)`` - (read as "0 to n instances of ``expr``") - - ``expr[...]`` and ``expr[0, ...]`` are equivalent to ``ZeroOrMore(expr)`` - - ``expr[1, ...]`` is equivalent to ``OneOrMore(expr)`` - - ``None`` may be used in place of ``...``. - - Note that ``expr[..., n]`` and ``expr[m, n]``do not raise an exception - if more than ``n`` ``expr``s exist in the input stream. If this behavior is - desired, then write ``expr[..., n] + ~expr``. - """ - - # convert single arg keys to tuples - try: - if isinstance(key, str_type): - key = (key,) - iter(key) - except TypeError: - key = (key, key) - - if len(key) > 2: - raise TypeError( - "only 1 or 2 index arguments supported ({}{})".format( - key[:5], "... [{}]".format(len(key)) if len(key) > 5 else "" - ) - ) - - # clip to 2 elements - ret = self * tuple(key[:2]) - return ret - - def __call__(self, name: str = None) -> "ParserElement": - """ - Shortcut for :class:`set_results_name`, with ``list_all_matches=False``. - - If ``name`` is given with a trailing ``'*'`` character, then ``list_all_matches`` will be - passed as ``True``. - - If ``name` is omitted, same as calling :class:`copy`. - - Example:: - - # these are equivalent - userdata = Word(alphas).set_results_name("name") + Word(nums + "-").set_results_name("socsecno") - userdata = Word(alphas)("name") + Word(nums + "-")("socsecno") - """ - if name is not None: - return self._setResultsName(name) - else: - return self.copy() - - def suppress(self) -> "ParserElement": - """ - Suppresses the output of this :class:`ParserElement`; useful to keep punctuation from - cluttering up returned output. - """ - return Suppress(self) - - def ignore_whitespace(self, recursive: bool = True) -> "ParserElement": - """ - Enables the skipping of whitespace before matching the characters in the - :class:`ParserElement`'s defined pattern. - - :param recursive: If ``True`` (the default), also enable whitespace skipping in child elements (if any) - """ - self.skipWhitespace = True - return self - - def leave_whitespace(self, recursive: bool = True) -> "ParserElement": - """ - Disables the skipping of whitespace before matching the characters in the - :class:`ParserElement`'s defined pattern. This is normally only used internally by - the pyparsing module, but may be needed in some whitespace-sensitive grammars. - - :param recursive: If true (the default), also disable whitespace skipping in child elements (if any) - """ - self.skipWhitespace = False - return self - - def set_whitespace_chars( - self, chars: Union[Set[str], str], copy_defaults: bool = False - ) -> "ParserElement": - """ - Overrides the default whitespace chars - """ - self.skipWhitespace = True - self.whiteChars = set(chars) - self.copyDefaultWhiteChars = copy_defaults - return self - - def parse_with_tabs(self) -> "ParserElement": - """ - Overrides default behavior to expand ```` s to spaces before parsing the input string. - Must be called before ``parse_string`` when the input grammar contains elements that - match ```` characters. - """ - self.keepTabs = True - return self - - def ignore(self, other: "ParserElement") -> "ParserElement": - """ - Define expression to be ignored (e.g., comments) while doing pattern - matching; may be called repeatedly, to define multiple comment or other - ignorable patterns. - - Example:: - - patt = Word(alphas)[1, ...] - patt.parse_string('ablaj /* comment */ lskjd') - # -> ['ablaj'] - - patt.ignore(c_style_comment) - patt.parse_string('ablaj /* comment */ lskjd') - # -> ['ablaj', 'lskjd'] - """ - import typing - - if isinstance(other, str_type): - other = Suppress(other) - - if isinstance(other, Suppress): - if other not in self.ignoreExprs: - self.ignoreExprs.append(other) - else: - self.ignoreExprs.append(Suppress(other.copy())) - return self - - def set_debug_actions( - self, - start_action: DebugStartAction, - success_action: DebugSuccessAction, - exception_action: DebugExceptionAction, - ) -> "ParserElement": - """ - Customize display of debugging messages while doing pattern matching: - - - ``start_action`` - method to be called when an expression is about to be parsed; - should have the signature ``fn(input_string: str, location: int, expression: ParserElement, cache_hit: bool)`` - - - ``success_action`` - method to be called when an expression has successfully parsed; - should have the signature ``fn(input_string: str, start_location: int, end_location: int, expression: ParserELement, parsed_tokens: ParseResults, cache_hit: bool)`` - - - ``exception_action`` - method to be called when expression fails to parse; - should have the signature ``fn(input_string: str, location: int, expression: ParserElement, exception: Exception, cache_hit: bool)`` - """ - self.debugActions = self.DebugActions( - start_action or _default_start_debug_action, - success_action or _default_success_debug_action, - exception_action or _default_exception_debug_action, - ) - self.debug = True - return self - - def set_debug(self, flag: bool = True) -> "ParserElement": - """ - Enable display of debugging messages while doing pattern matching. - Set ``flag`` to ``True`` to enable, ``False`` to disable. - - Example:: - - wd = Word(alphas).set_name("alphaword") - integer = Word(nums).set_name("numword") - term = wd | integer - - # turn on debugging for wd - wd.set_debug() - - term[1, ...].parse_string("abc 123 xyz 890") - - prints:: - - Match alphaword at loc 0(1,1) - Matched alphaword -> ['abc'] - Match alphaword at loc 3(1,4) - Exception raised:Expected alphaword (at char 4), (line:1, col:5) - Match alphaword at loc 7(1,8) - Matched alphaword -> ['xyz'] - Match alphaword at loc 11(1,12) - Exception raised:Expected alphaword (at char 12), (line:1, col:13) - Match alphaword at loc 15(1,16) - Exception raised:Expected alphaword (at char 15), (line:1, col:16) - - The output shown is that produced by the default debug actions - custom debug actions can be - specified using :class:`set_debug_actions`. Prior to attempting - to match the ``wd`` expression, the debugging message ``"Match at loc (,)"`` - is shown. Then if the parse succeeds, a ``"Matched"`` message is shown, or an ``"Exception raised"`` - message is shown. Also note the use of :class:`set_name` to assign a human-readable name to the expression, - which makes debugging and exception messages easier to understand - for instance, the default - name created for the :class:`Word` expression without calling ``set_name`` is ``"W:(A-Za-z)"``. - """ - if flag: - self.set_debug_actions( - _default_start_debug_action, - _default_success_debug_action, - _default_exception_debug_action, - ) - else: - self.debug = False - return self - - @property - def default_name(self) -> str: - if self._defaultName is None: - self._defaultName = self._generateDefaultName() - return self._defaultName - - @abstractmethod - def _generateDefaultName(self): - """ - Child classes must define this method, which defines how the ``default_name`` is set. - """ - - def set_name(self, name: str) -> "ParserElement": - """ - Define name for this expression, makes debugging and exception messages clearer. - Example:: - Word(nums).parse_string("ABC") # -> Exception: Expected W:(0-9) (at char 0), (line:1, col:1) - Word(nums).set_name("integer").parse_string("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) - """ - self.customName = name - self.errmsg = "Expected " + self.name - if __diag__.enable_debug_on_named_expressions: - self.set_debug() - return self - - @property - def name(self) -> str: - # This will use a user-defined name if available, but otherwise defaults back to the auto-generated name - return self.customName if self.customName is not None else self.default_name - - def __str__(self) -> str: - return self.name - - def __repr__(self) -> str: - return str(self) - - def streamline(self) -> "ParserElement": - self.streamlined = True - self._defaultName = None - return self - - def recurse(self) -> Sequence["ParserElement"]: - return [] - - def _checkRecursion(self, parseElementList): - subRecCheckList = parseElementList[:] + [self] - for e in self.recurse(): - e._checkRecursion(subRecCheckList) - - def validate(self, validateTrace=None) -> None: - """ - Check defined expressions for valid structure, check for infinite recursive definitions. - """ - self._checkRecursion([]) - - def parse_file( - self, - file_or_filename: Union[str, Path, TextIO], - encoding: str = "utf-8", - parse_all: bool = False, - *, - parseAll: bool = False, - ) -> ParseResults: - """ - Execute the parse expression on the given file or filename. - If a filename is specified (instead of a file object), - the entire file is opened, read, and closed before parsing. - """ - parseAll = parseAll or parse_all - try: - file_contents = file_or_filename.read() - except AttributeError: - with open(file_or_filename, "r", encoding=encoding) as f: - file_contents = f.read() - try: - return self.parse_string(file_contents, parseAll) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc.with_traceback(None) - - def __eq__(self, other): - if self is other: - return True - elif isinstance(other, str_type): - return self.matches(other, parse_all=True) - elif isinstance(other, ParserElement): - return vars(self) == vars(other) - return False - - def __hash__(self): - return id(self) - - def matches( - self, test_string: str, parse_all: bool = True, *, parseAll: bool = True - ) -> bool: - """ - Method for quick testing of a parser against a test string. Good for simple - inline microtests of sub expressions while building up larger parser. - - Parameters: - - ``test_string`` - to test against this expression for a match - - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests - - Example:: - - expr = Word(nums) - assert expr.matches("100") - """ - parseAll = parseAll and parse_all - try: - self.parse_string(str(test_string), parse_all=parseAll) - return True - except ParseBaseException: - return False - - def run_tests( - self, - tests: Union[str, List[str]], - parse_all: bool = True, - comment: typing.Optional[Union["ParserElement", str]] = "#", - full_dump: bool = True, - print_results: bool = True, - failure_tests: bool = False, - post_parse: Callable[[str, ParseResults], str] = None, - file: typing.Optional[TextIO] = None, - with_line_numbers: bool = False, - *, - parseAll: bool = True, - fullDump: bool = True, - printResults: bool = True, - failureTests: bool = False, - postParse: Callable[[str, ParseResults], str] = None, - ) -> Tuple[bool, List[Tuple[str, Union[ParseResults, Exception]]]]: - """ - Execute the parse expression on a series of test strings, showing each - test, the parsed results or where the parse failed. Quick and easy way to - run a parse expression against a list of sample strings. - - Parameters: - - ``tests`` - a list of separate test strings, or a multiline string of test strings - - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests - - ``comment`` - (default= ``'#'``) - expression for indicating embedded comments in the test - string; pass None to disable comment filtering - - ``full_dump`` - (default= ``True``) - dump results as list followed by results names in nested outline; - if False, only dump nested list - - ``print_results`` - (default= ``True``) prints test output to stdout - - ``failure_tests`` - (default= ``False``) indicates if these tests are expected to fail parsing - - ``post_parse`` - (default= ``None``) optional callback for successful parse results; called as - `fn(test_string, parse_results)` and returns a string to be added to the test output - - ``file`` - (default= ``None``) optional file-like object to which test output will be written; - if None, will default to ``sys.stdout`` - - ``with_line_numbers`` - default= ``False``) show test strings with line and column numbers - - Returns: a (success, results) tuple, where success indicates that all tests succeeded - (or failed if ``failure_tests`` is True), and the results contain a list of lines of each - test's output - - Example:: - - number_expr = pyparsing_common.number.copy() - - result = number_expr.run_tests(''' - # unsigned integer - 100 - # negative integer - -100 - # float with scientific notation - 6.02e23 - # integer with scientific notation - 1e-12 - ''') - print("Success" if result[0] else "Failed!") - - result = number_expr.run_tests(''' - # stray character - 100Z - # missing leading digit before '.' - -.100 - # too many '.' - 3.14.159 - ''', failure_tests=True) - print("Success" if result[0] else "Failed!") - - prints:: - - # unsigned integer - 100 - [100] - - # negative integer - -100 - [-100] - - # float with scientific notation - 6.02e23 - [6.02e+23] - - # integer with scientific notation - 1e-12 - [1e-12] - - Success - - # stray character - 100Z - ^ - FAIL: Expected end of text (at char 3), (line:1, col:4) - - # missing leading digit before '.' - -.100 - ^ - FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1) - - # too many '.' - 3.14.159 - ^ - FAIL: Expected end of text (at char 4), (line:1, col:5) - - Success - - Each test string must be on a single line. If you want to test a string that spans multiple - lines, create a test like this:: - - expr.run_tests(r"this is a test\\n of strings that spans \\n 3 lines") - - (Note that this is a raw string literal, you must include the leading ``'r'``.) - """ - from .testing import pyparsing_test - - parseAll = parseAll and parse_all - fullDump = fullDump and full_dump - printResults = printResults and print_results - failureTests = failureTests or failure_tests - postParse = postParse or post_parse - if isinstance(tests, str_type): - line_strip = type(tests).strip - tests = [line_strip(test_line) for test_line in tests.rstrip().splitlines()] - if isinstance(comment, str_type): - comment = Literal(comment) - if file is None: - file = sys.stdout - print_ = file.write - - result: Union[ParseResults, Exception] - allResults = [] - comments = [] - success = True - NL = Literal(r"\n").add_parse_action(replace_with("\n")).ignore(quoted_string) - BOM = "\ufeff" - for t in tests: - if comment is not None and comment.matches(t, False) or comments and not t: - comments.append( - pyparsing_test.with_line_numbers(t) if with_line_numbers else t - ) - continue - if not t: - continue - out = [ - "\n" + "\n".join(comments) if comments else "", - pyparsing_test.with_line_numbers(t) if with_line_numbers else t, - ] - comments = [] - try: - # convert newline marks to actual newlines, and strip leading BOM if present - t = NL.transform_string(t.lstrip(BOM)) - result = self.parse_string(t, parse_all=parseAll) - except ParseBaseException as pe: - fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" - out.append(pe.explain()) - out.append("FAIL: " + str(pe)) - if ParserElement.verbose_stacktrace: - out.extend(traceback.format_tb(pe.__traceback__)) - success = success and failureTests - result = pe - except Exception as exc: - out.append("FAIL-EXCEPTION: {}: {}".format(type(exc).__name__, exc)) - if ParserElement.verbose_stacktrace: - out.extend(traceback.format_tb(exc.__traceback__)) - success = success and failureTests - result = exc - else: - success = success and not failureTests - if postParse is not None: - try: - pp_value = postParse(t, result) - if pp_value is not None: - if isinstance(pp_value, ParseResults): - out.append(pp_value.dump()) - else: - out.append(str(pp_value)) - else: - out.append(result.dump()) - except Exception as e: - out.append(result.dump(full=fullDump)) - out.append( - "{} failed: {}: {}".format( - postParse.__name__, type(e).__name__, e - ) - ) - else: - out.append(result.dump(full=fullDump)) - out.append("") - - if printResults: - print_("\n".join(out)) - - allResults.append((t, result)) - - return success, allResults - - def create_diagram( - self, - output_html: Union[TextIO, Path, str], - vertical: int = 3, - show_results_names: bool = False, - show_groups: bool = False, - **kwargs, - ) -> None: - """ - Create a railroad diagram for the parser. - - Parameters: - - output_html (str or file-like object) - output target for generated - diagram HTML - - vertical (int) - threshold for formatting multiple alternatives vertically - instead of horizontally (default=3) - - show_results_names - bool flag whether diagram should show annotations for - defined results names - - show_groups - bool flag whether groups should be highlighted with an unlabeled surrounding box - Additional diagram-formatting keyword arguments can also be included; - see railroad.Diagram class. - """ - - try: - from .diagram import to_railroad, railroad_to_html - except ImportError as ie: - raise Exception( - "must ``pip install pyparsing[diagrams]`` to generate parser railroad diagrams" - ) from ie - - self.streamline() - - railroad = to_railroad( - self, - vertical=vertical, - show_results_names=show_results_names, - show_groups=show_groups, - diagram_kwargs=kwargs, - ) - if isinstance(output_html, (str, Path)): - with open(output_html, "w", encoding="utf-8") as diag_file: - diag_file.write(railroad_to_html(railroad)) - else: - # we were passed a file-like object, just write to it - output_html.write(railroad_to_html(railroad)) - - setDefaultWhitespaceChars = set_default_whitespace_chars - inlineLiteralsUsing = inline_literals_using - setResultsName = set_results_name - setBreak = set_break - setParseAction = set_parse_action - addParseAction = add_parse_action - addCondition = add_condition - setFailAction = set_fail_action - tryParse = try_parse - canParseNext = can_parse_next - resetCache = reset_cache - enableLeftRecursion = enable_left_recursion - enablePackrat = enable_packrat - parseString = parse_string - scanString = scan_string - searchString = search_string - transformString = transform_string - setWhitespaceChars = set_whitespace_chars - parseWithTabs = parse_with_tabs - setDebugActions = set_debug_actions - setDebug = set_debug - defaultName = default_name - setName = set_name - parseFile = parse_file - runTests = run_tests - ignoreWhitespace = ignore_whitespace - leaveWhitespace = leave_whitespace - - -class _PendingSkip(ParserElement): - # internal placeholder class to hold a place were '...' is added to a parser element, - # once another ParserElement is added, this placeholder will be replaced with a SkipTo - def __init__(self, expr: ParserElement, must_skip: bool = False): - super().__init__() - self.anchor = expr - self.must_skip = must_skip - - def _generateDefaultName(self): - return str(self.anchor + Empty()).replace("Empty", "...") - - def __add__(self, other) -> "ParserElement": - skipper = SkipTo(other).set_name("...")("_skipped*") - if self.must_skip: - - def must_skip(t): - if not t._skipped or t._skipped.as_list() == [""]: - del t[0] - t.pop("_skipped", None) - - def show_skip(t): - if t._skipped.as_list()[-1:] == [""]: - t.pop("_skipped") - t["_skipped"] = "missing <" + repr(self.anchor) + ">" - - return ( - self.anchor + skipper().add_parse_action(must_skip) - | skipper().add_parse_action(show_skip) - ) + other - - return self.anchor + skipper + other - - def __repr__(self): - return self.defaultName - - def parseImpl(self, *args): - raise Exception( - "use of `...` expression without following SkipTo target expression" - ) - - -class Token(ParserElement): - """Abstract :class:`ParserElement` subclass, for defining atomic - matching patterns. - """ - - def __init__(self): - super().__init__(savelist=False) - - def _generateDefaultName(self): - return type(self).__name__ - - -class Empty(Token): - """ - An empty token, will always match. - """ - - def __init__(self): - super().__init__() - self.mayReturnEmpty = True - self.mayIndexError = False - - -class NoMatch(Token): - """ - A token that will never match. - """ - - def __init__(self): - super().__init__() - self.mayReturnEmpty = True - self.mayIndexError = False - self.errmsg = "Unmatchable token" - - def parseImpl(self, instring, loc, doActions=True): - raise ParseException(instring, loc, self.errmsg, self) - - -class Literal(Token): - """ - Token to exactly match a specified string. - - Example:: - - Literal('blah').parse_string('blah') # -> ['blah'] - Literal('blah').parse_string('blahfooblah') # -> ['blah'] - Literal('blah').parse_string('bla') # -> Exception: Expected "blah" - - For case-insensitive matching, use :class:`CaselessLiteral`. - - For keyword matching (force word break before and after the matched string), - use :class:`Keyword` or :class:`CaselessKeyword`. - """ - - def __init__(self, match_string: str = "", *, matchString: str = ""): - super().__init__() - match_string = matchString or match_string - self.match = match_string - self.matchLen = len(match_string) - try: - self.firstMatchChar = match_string[0] - except IndexError: - raise ValueError("null string passed to Literal; use Empty() instead") - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - self.mayIndexError = False - - # Performance tuning: modify __class__ to select - # a parseImpl optimized for single-character check - if self.matchLen == 1 and type(self) is Literal: - self.__class__ = _SingleCharLiteral - - def _generateDefaultName(self): - return repr(self.match) - - def parseImpl(self, instring, loc, doActions=True): - if instring[loc] == self.firstMatchChar and instring.startswith( - self.match, loc - ): - return loc + self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) - - -class _SingleCharLiteral(Literal): - def parseImpl(self, instring, loc, doActions=True): - if instring[loc] == self.firstMatchChar: - return loc + 1, self.match - raise ParseException(instring, loc, self.errmsg, self) - - -ParserElement._literalStringClass = Literal - - -class Keyword(Token): - """ - Token to exactly match a specified string as a keyword, that is, - it must be immediately followed by a non-keyword character. Compare - with :class:`Literal`: - - - ``Literal("if")`` will match the leading ``'if'`` in - ``'ifAndOnlyIf'``. - - ``Keyword("if")`` will not; it will only match the leading - ``'if'`` in ``'if x=1'``, or ``'if(y==2)'`` - - Accepts two optional constructor arguments in addition to the - keyword string: - - - ``identChars`` is a string of characters that would be valid - identifier characters, defaulting to all alphanumerics + "_" and - "$" - - ``caseless`` allows case-insensitive matching, default is ``False``. - - Example:: - - Keyword("start").parse_string("start") # -> ['start'] - Keyword("start").parse_string("starting") # -> Exception - - For case-insensitive matching, use :class:`CaselessKeyword`. - """ - - DEFAULT_KEYWORD_CHARS = alphanums + "_$" - - def __init__( - self, - match_string: str = "", - ident_chars: typing.Optional[str] = None, - caseless: bool = False, - *, - matchString: str = "", - identChars: typing.Optional[str] = None, - ): - super().__init__() - identChars = identChars or ident_chars - if identChars is None: - identChars = Keyword.DEFAULT_KEYWORD_CHARS - match_string = matchString or match_string - self.match = match_string - self.matchLen = len(match_string) - try: - self.firstMatchChar = match_string[0] - except IndexError: - raise ValueError("null string passed to Keyword; use Empty() instead") - self.errmsg = "Expected {} {}".format(type(self).__name__, self.name) - self.mayReturnEmpty = False - self.mayIndexError = False - self.caseless = caseless - if caseless: - self.caselessmatch = match_string.upper() - identChars = identChars.upper() - self.identChars = set(identChars) - - def _generateDefaultName(self): - return repr(self.match) - - def parseImpl(self, instring, loc, doActions=True): - errmsg = self.errmsg - errloc = loc - if self.caseless: - if instring[loc : loc + self.matchLen].upper() == self.caselessmatch: - if loc == 0 or instring[loc - 1].upper() not in self.identChars: - if ( - loc >= len(instring) - self.matchLen - or instring[loc + self.matchLen].upper() not in self.identChars - ): - return loc + self.matchLen, self.match - else: - # followed by keyword char - errmsg += ", was immediately followed by keyword character" - errloc = loc + self.matchLen - else: - # preceded by keyword char - errmsg += ", keyword was immediately preceded by keyword character" - errloc = loc - 1 - # else no match just raise plain exception - - else: - if ( - instring[loc] == self.firstMatchChar - and self.matchLen == 1 - or instring.startswith(self.match, loc) - ): - if loc == 0 or instring[loc - 1] not in self.identChars: - if ( - loc >= len(instring) - self.matchLen - or instring[loc + self.matchLen] not in self.identChars - ): - return loc + self.matchLen, self.match - else: - # followed by keyword char - errmsg += ( - ", keyword was immediately followed by keyword character" - ) - errloc = loc + self.matchLen - else: - # preceded by keyword char - errmsg += ", keyword was immediately preceded by keyword character" - errloc = loc - 1 - # else no match just raise plain exception - - raise ParseException(instring, errloc, errmsg, self) - - @staticmethod - def set_default_keyword_chars(chars) -> None: - """ - Overrides the default characters used by :class:`Keyword` expressions. - """ - Keyword.DEFAULT_KEYWORD_CHARS = chars - - setDefaultKeywordChars = set_default_keyword_chars - - -class CaselessLiteral(Literal): - """ - Token to match a specified string, ignoring case of letters. - Note: the matched results will always be in the case of the given - match string, NOT the case of the input text. - - Example:: - - CaselessLiteral("CMD")[1, ...].parse_string("cmd CMD Cmd10") - # -> ['CMD', 'CMD', 'CMD'] - - (Contrast with example for :class:`CaselessKeyword`.) - """ - - def __init__(self, match_string: str = "", *, matchString: str = ""): - match_string = matchString or match_string - super().__init__(match_string.upper()) - # Preserve the defining literal. - self.returnString = match_string - self.errmsg = "Expected " + self.name - - def parseImpl(self, instring, loc, doActions=True): - if instring[loc : loc + self.matchLen].upper() == self.match: - return loc + self.matchLen, self.returnString - raise ParseException(instring, loc, self.errmsg, self) - - -class CaselessKeyword(Keyword): - """ - Caseless version of :class:`Keyword`. - - Example:: - - CaselessKeyword("CMD")[1, ...].parse_string("cmd CMD Cmd10") - # -> ['CMD', 'CMD'] - - (Contrast with example for :class:`CaselessLiteral`.) - """ - - def __init__( - self, - match_string: str = "", - ident_chars: typing.Optional[str] = None, - *, - matchString: str = "", - identChars: typing.Optional[str] = None, - ): - identChars = identChars or ident_chars - match_string = matchString or match_string - super().__init__(match_string, identChars, caseless=True) - - -class CloseMatch(Token): - """A variation on :class:`Literal` which matches "close" matches, - that is, strings with at most 'n' mismatching characters. - :class:`CloseMatch` takes parameters: - - - ``match_string`` - string to be matched - - ``caseless`` - a boolean indicating whether to ignore casing when comparing characters - - ``max_mismatches`` - (``default=1``) maximum number of - mismatches allowed to count as a match - - The results from a successful parse will contain the matched text - from the input string and the following named results: - - - ``mismatches`` - a list of the positions within the - match_string where mismatches were found - - ``original`` - the original match_string used to compare - against the input string - - If ``mismatches`` is an empty list, then the match was an exact - match. - - Example:: - - patt = CloseMatch("ATCATCGAATGGA") - patt.parse_string("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) - patt.parse_string("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1) - - # exact match - patt.parse_string("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']}) - - # close match allowing up to 2 mismatches - patt = CloseMatch("ATCATCGAATGGA", max_mismatches=2) - patt.parse_string("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) - """ - - def __init__( - self, - match_string: str, - max_mismatches: int = None, - *, - maxMismatches: int = 1, - caseless=False, - ): - maxMismatches = max_mismatches if max_mismatches is not None else maxMismatches - super().__init__() - self.match_string = match_string - self.maxMismatches = maxMismatches - self.errmsg = "Expected {!r} (with up to {} mismatches)".format( - self.match_string, self.maxMismatches - ) - self.caseless = caseless - self.mayIndexError = False - self.mayReturnEmpty = False - - def _generateDefaultName(self): - return "{}:{!r}".format(type(self).__name__, self.match_string) - - def parseImpl(self, instring, loc, doActions=True): - start = loc - instrlen = len(instring) - maxloc = start + len(self.match_string) - - if maxloc <= instrlen: - match_string = self.match_string - match_stringloc = 0 - mismatches = [] - maxMismatches = self.maxMismatches - - for match_stringloc, s_m in enumerate( - zip(instring[loc:maxloc], match_string) - ): - src, mat = s_m - if self.caseless: - src, mat = src.lower(), mat.lower() - - if src != mat: - mismatches.append(match_stringloc) - if len(mismatches) > maxMismatches: - break - else: - loc = start + match_stringloc + 1 - results = ParseResults([instring[start:loc]]) - results["original"] = match_string - results["mismatches"] = mismatches - return loc, results - - raise ParseException(instring, loc, self.errmsg, self) - - -class Word(Token): - """Token for matching words composed of allowed character sets. - Parameters: - - ``init_chars`` - string of all characters that should be used to - match as a word; "ABC" will match "AAA", "ABAB", "CBAC", etc.; - if ``body_chars`` is also specified, then this is the string of - initial characters - - ``body_chars`` - string of characters that - can be used for matching after a matched initial character as - given in ``init_chars``; if omitted, same as the initial characters - (default=``None``) - - ``min`` - minimum number of characters to match (default=1) - - ``max`` - maximum number of characters to match (default=0) - - ``exact`` - exact number of characters to match (default=0) - - ``as_keyword`` - match as a keyword (default=``False``) - - ``exclude_chars`` - characters that might be - found in the input ``body_chars`` string but which should not be - accepted for matching ;useful to define a word of all - printables except for one or two characters, for instance - (default=``None``) - - :class:`srange` is useful for defining custom character set strings - for defining :class:`Word` expressions, using range notation from - regular expression character sets. - - A common mistake is to use :class:`Word` to match a specific literal - string, as in ``Word("Address")``. Remember that :class:`Word` - uses the string argument to define *sets* of matchable characters. - This expression would match "Add", "AAA", "dAred", or any other word - made up of the characters 'A', 'd', 'r', 'e', and 's'. To match an - exact literal string, use :class:`Literal` or :class:`Keyword`. - - pyparsing includes helper strings for building Words: - - - :class:`alphas` - - :class:`nums` - - :class:`alphanums` - - :class:`hexnums` - - :class:`alphas8bit` (alphabetic characters in ASCII range 128-255 - - accented, tilded, umlauted, etc.) - - :class:`punc8bit` (non-alphabetic characters in ASCII range - 128-255 - currency, symbols, superscripts, diacriticals, etc.) - - :class:`printables` (any non-whitespace character) - - ``alphas``, ``nums``, and ``printables`` are also defined in several - Unicode sets - see :class:`pyparsing_unicode``. - - Example:: - - # a word composed of digits - integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) - - # a word with a leading capital, and zero or more lowercase - capital_word = Word(alphas.upper(), alphas.lower()) - - # hostnames are alphanumeric, with leading alpha, and '-' - hostname = Word(alphas, alphanums + '-') - - # roman numeral (not a strict parser, accepts invalid mix of characters) - roman = Word("IVXLCDM") - - # any string of non-whitespace characters, except for ',' - csv_value = Word(printables, exclude_chars=",") - """ - - def __init__( - self, - init_chars: str = "", - body_chars: typing.Optional[str] = None, - min: int = 1, - max: int = 0, - exact: int = 0, - as_keyword: bool = False, - exclude_chars: typing.Optional[str] = None, - *, - initChars: typing.Optional[str] = None, - bodyChars: typing.Optional[str] = None, - asKeyword: bool = False, - excludeChars: typing.Optional[str] = None, - ): - initChars = initChars or init_chars - bodyChars = bodyChars or body_chars - asKeyword = asKeyword or as_keyword - excludeChars = excludeChars or exclude_chars - super().__init__() - if not initChars: - raise ValueError( - "invalid {}, initChars cannot be empty string".format( - type(self).__name__ - ) - ) - - initChars = set(initChars) - self.initChars = initChars - if excludeChars: - excludeChars = set(excludeChars) - initChars -= excludeChars - if bodyChars: - bodyChars = set(bodyChars) - excludeChars - self.initCharsOrig = "".join(sorted(initChars)) - - if bodyChars: - self.bodyCharsOrig = "".join(sorted(bodyChars)) - self.bodyChars = set(bodyChars) - else: - self.bodyCharsOrig = "".join(sorted(initChars)) - self.bodyChars = set(initChars) - - self.maxSpecified = max > 0 - - if min < 1: - raise ValueError( - "cannot specify a minimum length < 1; use Opt(Word()) if zero-length word is permitted" - ) - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.asKeyword = asKeyword - - # see if we can make a regex for this Word - if " " not in self.initChars | self.bodyChars and (min == 1 and exact == 0): - if self.bodyChars == self.initChars: - if max == 0: - repeat = "+" - elif max == 1: - repeat = "" - else: - repeat = "{{{},{}}}".format( - self.minLen, "" if self.maxLen == _MAX_INT else self.maxLen - ) - self.reString = "[{}]{}".format( - _collapse_string_to_ranges(self.initChars), - repeat, - ) - elif len(self.initChars) == 1: - if max == 0: - repeat = "*" - else: - repeat = "{{0,{}}}".format(max - 1) - self.reString = "{}[{}]{}".format( - re.escape(self.initCharsOrig), - _collapse_string_to_ranges(self.bodyChars), - repeat, - ) - else: - if max == 0: - repeat = "*" - elif max == 2: - repeat = "" - else: - repeat = "{{0,{}}}".format(max - 1) - self.reString = "[{}][{}]{}".format( - _collapse_string_to_ranges(self.initChars), - _collapse_string_to_ranges(self.bodyChars), - repeat, - ) - if self.asKeyword: - self.reString = r"\b" + self.reString + r"\b" - - try: - self.re = re.compile(self.reString) - except re.error: - self.re = None - else: - self.re_match = self.re.match - self.__class__ = _WordRegex - - def _generateDefaultName(self): - def charsAsStr(s): - max_repr_len = 16 - s = _collapse_string_to_ranges(s, re_escape=False) - if len(s) > max_repr_len: - return s[: max_repr_len - 3] + "..." - else: - return s - - if self.initChars != self.bodyChars: - base = "W:({}, {})".format( - charsAsStr(self.initChars), charsAsStr(self.bodyChars) - ) - else: - base = "W:({})".format(charsAsStr(self.initChars)) - - # add length specification - if self.minLen > 1 or self.maxLen != _MAX_INT: - if self.minLen == self.maxLen: - if self.minLen == 1: - return base[2:] - else: - return base + "{{{}}}".format(self.minLen) - elif self.maxLen == _MAX_INT: - return base + "{{{},...}}".format(self.minLen) - else: - return base + "{{{},{}}}".format(self.minLen, self.maxLen) - return base - - def parseImpl(self, instring, loc, doActions=True): - if instring[loc] not in self.initChars: - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - instrlen = len(instring) - bodychars = self.bodyChars - maxloc = start + self.maxLen - maxloc = min(maxloc, instrlen) - while loc < maxloc and instring[loc] in bodychars: - loc += 1 - - throwException = False - if loc - start < self.minLen: - throwException = True - elif self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True - elif self.asKeyword: - if ( - start > 0 - and instring[start - 1] in bodychars - or loc < instrlen - and instring[loc] in bodychars - ): - throwException = True - - if throwException: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class _WordRegex(Word): - def parseImpl(self, instring, loc, doActions=True): - result = self.re_match(instring, loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - return loc, result.group() - - -class Char(_WordRegex): - """A short-cut class for defining :class:`Word` ``(characters, exact=1)``, - when defining a match of any single character in a string of - characters. - """ - - def __init__( - self, - charset: str, - as_keyword: bool = False, - exclude_chars: typing.Optional[str] = None, - *, - asKeyword: bool = False, - excludeChars: typing.Optional[str] = None, - ): - asKeyword = asKeyword or as_keyword - excludeChars = excludeChars or exclude_chars - super().__init__( - charset, exact=1, asKeyword=asKeyword, excludeChars=excludeChars - ) - self.reString = "[{}]".format(_collapse_string_to_ranges(self.initChars)) - if asKeyword: - self.reString = r"\b{}\b".format(self.reString) - self.re = re.compile(self.reString) - self.re_match = self.re.match - - -class Regex(Token): - r"""Token for matching strings that match a given regular - expression. Defined with string specifying the regular expression in - a form recognized by the stdlib Python `re module `_. - If the given regex contains named groups (defined using ``(?P...)``), - these will be preserved as named :class:`ParseResults`. - - If instead of the Python stdlib ``re`` module you wish to use a different RE module - (such as the ``regex`` module), you can do so by building your ``Regex`` object with - a compiled RE that was compiled using ``regex``. - - Example:: - - realnum = Regex(r"[+-]?\d+\.\d*") - # ref: https://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression - roman = Regex(r"M{0,4}(CM|CD|D?{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") - - # named fields in a regex will be returned as named results - date = Regex(r'(?P\d{4})-(?P\d\d?)-(?P\d\d?)') - - # the Regex class will accept re's compiled using the regex module - import regex - parser = pp.Regex(regex.compile(r'[0-9]')) - """ - - def __init__( - self, - pattern: Any, - flags: Union[re.RegexFlag, int] = 0, - as_group_list: bool = False, - as_match: bool = False, - *, - asGroupList: bool = False, - asMatch: bool = False, - ): - """The parameters ``pattern`` and ``flags`` are passed - to the ``re.compile()`` function as-is. See the Python - `re module `_ module for an - explanation of the acceptable patterns and flags. - """ - super().__init__() - asGroupList = asGroupList or as_group_list - asMatch = asMatch or as_match - - if isinstance(pattern, str_type): - if not pattern: - raise ValueError("null string passed to Regex; use Empty() instead") - - self._re = None - self.reString = self.pattern = pattern - self.flags = flags - - elif hasattr(pattern, "pattern") and hasattr(pattern, "match"): - self._re = pattern - self.pattern = self.reString = pattern.pattern - self.flags = flags - - else: - raise TypeError( - "Regex may only be constructed with a string or a compiled RE object" - ) - - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.asGroupList = asGroupList - self.asMatch = asMatch - if self.asGroupList: - self.parseImpl = self.parseImplAsGroupList - if self.asMatch: - self.parseImpl = self.parseImplAsMatch - - @cached_property - def re(self): - if self._re: - return self._re - else: - try: - return re.compile(self.pattern, self.flags) - except re.error: - raise ValueError( - "invalid pattern ({!r}) passed to Regex".format(self.pattern) - ) - - @cached_property - def re_match(self): - return self.re.match - - @cached_property - def mayReturnEmpty(self): - return self.re_match("") is not None - - def _generateDefaultName(self): - return "Re:({})".format(repr(self.pattern).replace("\\\\", "\\")) - - def parseImpl(self, instring, loc, doActions=True): - result = self.re_match(instring, loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = ParseResults(result.group()) - d = result.groupdict() - if d: - for k, v in d.items(): - ret[k] = v - return loc, ret - - def parseImplAsGroupList(self, instring, loc, doActions=True): - result = self.re_match(instring, loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result.groups() - return loc, ret - - def parseImplAsMatch(self, instring, loc, doActions=True): - result = self.re_match(instring, loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result - return loc, ret - - def sub(self, repl: str) -> ParserElement: - r""" - Return :class:`Regex` with an attached parse action to transform the parsed - result as if called using `re.sub(expr, repl, string) `_. - - Example:: - - make_html = Regex(r"(\w+):(.*?):").sub(r"<\1>\2") - print(make_html.transform_string("h1:main title:")) - # prints "

main title

" - """ - if self.asGroupList: - raise TypeError("cannot use sub() with Regex(asGroupList=True)") - - if self.asMatch and callable(repl): - raise TypeError("cannot use sub() with a callable with Regex(asMatch=True)") - - if self.asMatch: - - def pa(tokens): - return tokens[0].expand(repl) - - else: - - def pa(tokens): - return self.re.sub(repl, tokens[0]) - - return self.add_parse_action(pa) - - -class QuotedString(Token): - r""" - Token for matching strings that are delimited by quoting characters. - - Defined with the following parameters: - - - ``quote_char`` - string of one or more characters defining the - quote delimiting string - - ``esc_char`` - character to re_escape quotes, typically backslash - (default= ``None``) - - ``esc_quote`` - special quote sequence to re_escape an embedded quote - string (such as SQL's ``""`` to re_escape an embedded ``"``) - (default= ``None``) - - ``multiline`` - boolean indicating whether quotes can span - multiple lines (default= ``False``) - - ``unquote_results`` - boolean indicating whether the matched text - should be unquoted (default= ``True``) - - ``end_quote_char`` - string of one or more characters defining the - end of the quote delimited string (default= ``None`` => same as - quote_char) - - ``convert_whitespace_escapes`` - convert escaped whitespace - (``'\t'``, ``'\n'``, etc.) to actual whitespace - (default= ``True``) - - Example:: - - qs = QuotedString('"') - print(qs.search_string('lsjdf "This is the quote" sldjf')) - complex_qs = QuotedString('{{', end_quote_char='}}') - print(complex_qs.search_string('lsjdf {{This is the "quote"}} sldjf')) - sql_qs = QuotedString('"', esc_quote='""') - print(sql_qs.search_string('lsjdf "This is the quote with ""embedded"" quotes" sldjf')) - - prints:: - - [['This is the quote']] - [['This is the "quote"']] - [['This is the quote with "embedded" quotes']] - """ - ws_map = ((r"\t", "\t"), (r"\n", "\n"), (r"\f", "\f"), (r"\r", "\r")) - - def __init__( - self, - quote_char: str = "", - esc_char: typing.Optional[str] = None, - esc_quote: typing.Optional[str] = None, - multiline: bool = False, - unquote_results: bool = True, - end_quote_char: typing.Optional[str] = None, - convert_whitespace_escapes: bool = True, - *, - quoteChar: str = "", - escChar: typing.Optional[str] = None, - escQuote: typing.Optional[str] = None, - unquoteResults: bool = True, - endQuoteChar: typing.Optional[str] = None, - convertWhitespaceEscapes: bool = True, - ): - super().__init__() - escChar = escChar or esc_char - escQuote = escQuote or esc_quote - unquoteResults = unquoteResults and unquote_results - endQuoteChar = endQuoteChar or end_quote_char - convertWhitespaceEscapes = ( - convertWhitespaceEscapes and convert_whitespace_escapes - ) - quote_char = quoteChar or quote_char - - # remove white space from quote chars - wont work anyway - quote_char = quote_char.strip() - if not quote_char: - raise ValueError("quote_char cannot be the empty string") - - if endQuoteChar is None: - endQuoteChar = quote_char - else: - endQuoteChar = endQuoteChar.strip() - if not endQuoteChar: - raise ValueError("endQuoteChar cannot be the empty string") - - self.quoteChar = quote_char - self.quoteCharLen = len(quote_char) - self.firstQuoteChar = quote_char[0] - self.endQuoteChar = endQuoteChar - self.endQuoteCharLen = len(endQuoteChar) - self.escChar = escChar - self.escQuote = escQuote - self.unquoteResults = unquoteResults - self.convertWhitespaceEscapes = convertWhitespaceEscapes - - sep = "" - inner_pattern = "" - - if escQuote: - inner_pattern += r"{}(?:{})".format(sep, re.escape(escQuote)) - sep = "|" - - if escChar: - inner_pattern += r"{}(?:{}.)".format(sep, re.escape(escChar)) - sep = "|" - self.escCharReplacePattern = re.escape(self.escChar) + "(.)" - - if len(self.endQuoteChar) > 1: - inner_pattern += ( - "{}(?:".format(sep) - + "|".join( - "(?:{}(?!{}))".format( - re.escape(self.endQuoteChar[:i]), - re.escape(self.endQuoteChar[i:]), - ) - for i in range(len(self.endQuoteChar) - 1, 0, -1) - ) - + ")" - ) - sep = "|" - - if multiline: - self.flags = re.MULTILINE | re.DOTALL - inner_pattern += r"{}(?:[^{}{}])".format( - sep, - _escape_regex_range_chars(self.endQuoteChar[0]), - (_escape_regex_range_chars(escChar) if escChar is not None else ""), - ) - else: - self.flags = 0 - inner_pattern += r"{}(?:[^{}\n\r{}])".format( - sep, - _escape_regex_range_chars(self.endQuoteChar[0]), - (_escape_regex_range_chars(escChar) if escChar is not None else ""), - ) - - self.pattern = "".join( - [ - re.escape(self.quoteChar), - "(?:", - inner_pattern, - ")*", - re.escape(self.endQuoteChar), - ] - ) - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - self.re_match = self.re.match - except re.error: - raise ValueError( - "invalid pattern {!r} passed to Regex".format(self.pattern) - ) - - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.mayReturnEmpty = True - - def _generateDefaultName(self): - if self.quoteChar == self.endQuoteChar and isinstance(self.quoteChar, str_type): - return "string enclosed in {!r}".format(self.quoteChar) - - return "quoted string, starting with {} ending with {}".format( - self.quoteChar, self.endQuoteChar - ) - - def parseImpl(self, instring, loc, doActions=True): - result = ( - instring[loc] == self.firstQuoteChar - and self.re_match(instring, loc) - or None - ) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result.group() - - if self.unquoteResults: - - # strip off quotes - ret = ret[self.quoteCharLen : -self.endQuoteCharLen] - - if isinstance(ret, str_type): - # replace escaped whitespace - if "\\" in ret and self.convertWhitespaceEscapes: - for wslit, wschar in self.ws_map: - ret = ret.replace(wslit, wschar) - - # replace escaped characters - if self.escChar: - ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret) - - # replace escaped quotes - if self.escQuote: - ret = ret.replace(self.escQuote, self.endQuoteChar) - - return loc, ret - - -class CharsNotIn(Token): - """Token for matching words composed of characters *not* in a given - set (will include whitespace in matched characters if not listed in - the provided exclusion set - see example). Defined with string - containing all disallowed characters, and an optional minimum, - maximum, and/or exact length. The default value for ``min`` is - 1 (a minimum value < 1 is not valid); the default values for - ``max`` and ``exact`` are 0, meaning no maximum or exact - length restriction. - - Example:: - - # define a comma-separated-value as anything that is not a ',' - csv_value = CharsNotIn(',') - print(delimited_list(csv_value).parse_string("dkls,lsdkjf,s12 34,@!#,213")) - - prints:: - - ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] - """ - - def __init__( - self, - not_chars: str = "", - min: int = 1, - max: int = 0, - exact: int = 0, - *, - notChars: str = "", - ): - super().__init__() - self.skipWhitespace = False - self.notChars = not_chars or notChars - self.notCharsSet = set(self.notChars) - - if min < 1: - raise ValueError( - "cannot specify a minimum length < 1; use " - "Opt(CharsNotIn()) if zero-length char group is permitted" - ) - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = self.minLen == 0 - self.mayIndexError = False - - def _generateDefaultName(self): - not_chars_str = _collapse_string_to_ranges(self.notChars) - if len(not_chars_str) > 16: - return "!W:({}...)".format(self.notChars[: 16 - 3]) - else: - return "!W:({})".format(self.notChars) - - def parseImpl(self, instring, loc, doActions=True): - notchars = self.notCharsSet - if instring[loc] in notchars: - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - maxlen = min(start + self.maxLen, len(instring)) - while loc < maxlen and instring[loc] not in notchars: - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class White(Token): - """Special matching class for matching whitespace. Normally, - whitespace is ignored by pyparsing grammars. This class is included - when some whitespace structures are significant. Define with - a string containing the whitespace characters to be matched; default - is ``" \\t\\r\\n"``. Also takes optional ``min``, - ``max``, and ``exact`` arguments, as defined for the - :class:`Word` class. - """ - - whiteStrs = { - " ": "", - "\t": "", - "\n": "", - "\r": "", - "\f": "", - "\u00A0": "", - "\u1680": "", - "\u180E": "", - "\u2000": "", - "\u2001": "", - "\u2002": "", - "\u2003": "", - "\u2004": "", - "\u2005": "", - "\u2006": "", - "\u2007": "", - "\u2008": "", - "\u2009": "", - "\u200A": "", - "\u200B": "", - "\u202F": "", - "\u205F": "", - "\u3000": "", - } - - def __init__(self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0): - super().__init__() - self.matchWhite = ws - self.set_whitespace_chars( - "".join(c for c in self.whiteStrs if c not in self.matchWhite), - copy_defaults=True, - ) - # self.leave_whitespace() - self.mayReturnEmpty = True - self.errmsg = "Expected " + self.name - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - def _generateDefaultName(self): - return "".join(White.whiteStrs[c] for c in self.matchWhite) - - def parseImpl(self, instring, loc, doActions=True): - if instring[loc] not in self.matchWhite: - raise ParseException(instring, loc, self.errmsg, self) - start = loc - loc += 1 - maxloc = start + self.maxLen - maxloc = min(maxloc, len(instring)) - while loc < maxloc and instring[loc] in self.matchWhite: - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class PositionToken(Token): - def __init__(self): - super().__init__() - self.mayReturnEmpty = True - self.mayIndexError = False - - -class GoToColumn(PositionToken): - """Token to advance to a specific column of input text; useful for - tabular report scraping. - """ - - def __init__(self, colno: int): - super().__init__() - self.col = colno - - def preParse(self, instring, loc): - if col(loc, instring) != self.col: - instrlen = len(instring) - if self.ignoreExprs: - loc = self._skipIgnorables(instring, loc) - while ( - loc < instrlen - and instring[loc].isspace() - and col(loc, instring) != self.col - ): - loc += 1 - return loc - - def parseImpl(self, instring, loc, doActions=True): - thiscol = col(loc, instring) - if thiscol > self.col: - raise ParseException(instring, loc, "Text not in expected column", self) - newloc = loc + self.col - thiscol - ret = instring[loc:newloc] - return newloc, ret - - -class LineStart(PositionToken): - r"""Matches if current position is at the beginning of a line within - the parse string - - Example:: - - test = '''\ - AAA this line - AAA and this line - AAA but not this one - B AAA and definitely not this one - ''' - - for t in (LineStart() + 'AAA' + restOfLine).search_string(test): - print(t) - - prints:: - - ['AAA', ' this line'] - ['AAA', ' and this line'] - - """ - - def __init__(self): - super().__init__() - self.leave_whitespace() - self.orig_whiteChars = set() | self.whiteChars - self.whiteChars.discard("\n") - self.skipper = Empty().set_whitespace_chars(self.whiteChars) - self.errmsg = "Expected start of line" - - def preParse(self, instring, loc): - if loc == 0: - return loc - else: - ret = self.skipper.preParse(instring, loc) - if "\n" in self.orig_whiteChars: - while instring[ret : ret + 1] == "\n": - ret = self.skipper.preParse(instring, ret + 1) - return ret - - def parseImpl(self, instring, loc, doActions=True): - if col(loc, instring) == 1: - return loc, [] - raise ParseException(instring, loc, self.errmsg, self) - - -class LineEnd(PositionToken): - """Matches if current position is at the end of a line within the - parse string - """ - - def __init__(self): - super().__init__() - self.whiteChars.discard("\n") - self.set_whitespace_chars(self.whiteChars, copy_defaults=False) - self.errmsg = "Expected end of line" - - def parseImpl(self, instring, loc, doActions=True): - if loc < len(instring): - if instring[loc] == "\n": - return loc + 1, "\n" - else: - raise ParseException(instring, loc, self.errmsg, self) - elif loc == len(instring): - return loc + 1, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - - -class StringStart(PositionToken): - """Matches if current position is at the beginning of the parse - string - """ - - def __init__(self): - super().__init__() - self.errmsg = "Expected start of text" - - def parseImpl(self, instring, loc, doActions=True): - if loc != 0: - # see if entire string up to here is just whitespace and ignoreables - if loc != self.preParse(instring, 0): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - -class StringEnd(PositionToken): - """ - Matches if current position is at the end of the parse string - """ - - def __init__(self): - super().__init__() - self.errmsg = "Expected end of text" - - def parseImpl(self, instring, loc, doActions=True): - if loc < len(instring): - raise ParseException(instring, loc, self.errmsg, self) - elif loc == len(instring): - return loc + 1, [] - elif loc > len(instring): - return loc, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - - -class WordStart(PositionToken): - """Matches if the current position is at the beginning of a - :class:`Word`, and is not preceded by any character in a given - set of ``word_chars`` (default= ``printables``). To emulate the - ``\b`` behavior of regular expressions, use - ``WordStart(alphanums)``. ``WordStart`` will also match at - the beginning of the string being parsed, or at the beginning of - a line. - """ - - def __init__(self, word_chars: str = printables, *, wordChars: str = printables): - wordChars = word_chars if wordChars == printables else wordChars - super().__init__() - self.wordChars = set(wordChars) - self.errmsg = "Not at the start of a word" - - def parseImpl(self, instring, loc, doActions=True): - if loc != 0: - if ( - instring[loc - 1] in self.wordChars - or instring[loc] not in self.wordChars - ): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - -class WordEnd(PositionToken): - """Matches if the current position is at the end of a :class:`Word`, - and is not followed by any character in a given set of ``word_chars`` - (default= ``printables``). To emulate the ``\b`` behavior of - regular expressions, use ``WordEnd(alphanums)``. ``WordEnd`` - will also match at the end of the string being parsed, or at the end - of a line. - """ - - def __init__(self, word_chars: str = printables, *, wordChars: str = printables): - wordChars = word_chars if wordChars == printables else wordChars - super().__init__() - self.wordChars = set(wordChars) - self.skipWhitespace = False - self.errmsg = "Not at the end of a word" - - def parseImpl(self, instring, loc, doActions=True): - instrlen = len(instring) - if instrlen > 0 and loc < instrlen: - if ( - instring[loc] in self.wordChars - or instring[loc - 1] not in self.wordChars - ): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - -class ParseExpression(ParserElement): - """Abstract subclass of ParserElement, for combining and - post-processing parsed tokens. - """ - - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): - super().__init__(savelist) - self.exprs: List[ParserElement] - if isinstance(exprs, _generatorType): - exprs = list(exprs) - - if isinstance(exprs, str_type): - self.exprs = [self._literalStringClass(exprs)] - elif isinstance(exprs, ParserElement): - self.exprs = [exprs] - elif isinstance(exprs, Iterable): - exprs = list(exprs) - # if sequence of strings provided, wrap with Literal - if any(isinstance(expr, str_type) for expr in exprs): - exprs = ( - self._literalStringClass(e) if isinstance(e, str_type) else e - for e in exprs - ) - self.exprs = list(exprs) - else: - try: - self.exprs = list(exprs) - except TypeError: - self.exprs = [exprs] - self.callPreparse = False - - def recurse(self) -> Sequence[ParserElement]: - return self.exprs[:] - - def append(self, other) -> ParserElement: - self.exprs.append(other) - self._defaultName = None - return self - - def leave_whitespace(self, recursive: bool = True) -> ParserElement: - """ - Extends ``leave_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on - all contained expressions. - """ - super().leave_whitespace(recursive) - - if recursive: - self.exprs = [e.copy() for e in self.exprs] - for e in self.exprs: - e.leave_whitespace(recursive) - return self - - def ignore_whitespace(self, recursive: bool = True) -> ParserElement: - """ - Extends ``ignore_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on - all contained expressions. - """ - super().ignore_whitespace(recursive) - if recursive: - self.exprs = [e.copy() for e in self.exprs] - for e in self.exprs: - e.ignore_whitespace(recursive) - return self - - def ignore(self, other) -> ParserElement: - if isinstance(other, Suppress): - if other not in self.ignoreExprs: - super().ignore(other) - for e in self.exprs: - e.ignore(self.ignoreExprs[-1]) - else: - super().ignore(other) - for e in self.exprs: - e.ignore(self.ignoreExprs[-1]) - return self - - def _generateDefaultName(self): - return "{}:({})".format(self.__class__.__name__, str(self.exprs)) - - def streamline(self) -> ParserElement: - if self.streamlined: - return self - - super().streamline() - - for e in self.exprs: - e.streamline() - - # collapse nested :class:`And`'s of the form ``And(And(And(a, b), c), d)`` to ``And(a, b, c, d)`` - # but only if there are no parse actions or resultsNames on the nested And's - # (likewise for :class:`Or`'s and :class:`MatchFirst`'s) - if len(self.exprs) == 2: - other = self.exprs[0] - if ( - isinstance(other, self.__class__) - and not other.parseAction - and other.resultsName is None - and not other.debug - ): - self.exprs = other.exprs[:] + [self.exprs[1]] - self._defaultName = None - self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError - - other = self.exprs[-1] - if ( - isinstance(other, self.__class__) - and not other.parseAction - and other.resultsName is None - and not other.debug - ): - self.exprs = self.exprs[:-1] + other.exprs[:] - self._defaultName = None - self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError - - self.errmsg = "Expected " + str(self) - - return self - - def validate(self, validateTrace=None) -> None: - tmp = (validateTrace if validateTrace is not None else [])[:] + [self] - for e in self.exprs: - e.validate(tmp) - self._checkRecursion([]) - - def copy(self) -> ParserElement: - ret = super().copy() - ret.exprs = [e.copy() for e in self.exprs] - return ret - - def _setResultsName(self, name, listAllMatches=False): - if ( - __diag__.warn_ungrouped_named_tokens_in_collection - and Diagnostics.warn_ungrouped_named_tokens_in_collection - not in self.suppress_warnings_ - ): - for e in self.exprs: - if ( - isinstance(e, ParserElement) - and e.resultsName - and Diagnostics.warn_ungrouped_named_tokens_in_collection - not in e.suppress_warnings_ - ): - warnings.warn( - "{}: setting results name {!r} on {} expression " - "collides with {!r} on contained expression".format( - "warn_ungrouped_named_tokens_in_collection", - name, - type(self).__name__, - e.resultsName, - ), - stacklevel=3, - ) - - return super()._setResultsName(name, listAllMatches) - - ignoreWhitespace = ignore_whitespace - leaveWhitespace = leave_whitespace - - -class And(ParseExpression): - """ - Requires all given :class:`ParseExpression` s to be found in the given order. - Expressions may be separated by whitespace. - May be constructed using the ``'+'`` operator. - May also be constructed using the ``'-'`` operator, which will - suppress backtracking. - - Example:: - - integer = Word(nums) - name_expr = Word(alphas)[1, ...] - - expr = And([integer("id"), name_expr("name"), integer("age")]) - # more easily written as: - expr = integer("id") + name_expr("name") + integer("age") - """ - - class _ErrorStop(Empty): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.leave_whitespace() - - def _generateDefaultName(self): - return "-" - - def __init__( - self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True - ): - exprs: List[ParserElement] = list(exprs_arg) - if exprs and Ellipsis in exprs: - tmp = [] - for i, expr in enumerate(exprs): - if expr is Ellipsis: - if i < len(exprs) - 1: - skipto_arg: ParserElement = (Empty() + exprs[i + 1]).exprs[-1] - tmp.append(SkipTo(skipto_arg)("_skipped*")) - else: - raise Exception( - "cannot construct And with sequence ending in ..." - ) - else: - tmp.append(expr) - exprs[:] = tmp - super().__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - if not isinstance(self.exprs[0], White): - self.set_whitespace_chars( - self.exprs[0].whiteChars, - copy_defaults=self.exprs[0].copyDefaultWhiteChars, - ) - self.skipWhitespace = self.exprs[0].skipWhitespace - else: - self.skipWhitespace = False - else: - self.mayReturnEmpty = True - self.callPreparse = True - - def streamline(self) -> ParserElement: - # collapse any _PendingSkip's - if self.exprs: - if any( - isinstance(e, ParseExpression) - and e.exprs - and isinstance(e.exprs[-1], _PendingSkip) - for e in self.exprs[:-1] - ): - for i, e in enumerate(self.exprs[:-1]): - if e is None: - continue - if ( - isinstance(e, ParseExpression) - and e.exprs - and isinstance(e.exprs[-1], _PendingSkip) - ): - e.exprs[-1] = e.exprs[-1] + self.exprs[i + 1] - self.exprs[i + 1] = None - self.exprs = [e for e in self.exprs if e is not None] - - super().streamline() - - # link any IndentedBlocks to the prior expression - for prev, cur in zip(self.exprs, self.exprs[1:]): - # traverse cur or any first embedded expr of cur looking for an IndentedBlock - # (but watch out for recursive grammar) - seen = set() - while cur: - if id(cur) in seen: - break - seen.add(id(cur)) - if isinstance(cur, IndentedBlock): - prev.add_parse_action( - lambda s, l, t, cur_=cur: setattr( - cur_, "parent_anchor", col(l, s) - ) - ) - break - subs = cur.recurse() - cur = next(iter(subs), None) - - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - return self - - def parseImpl(self, instring, loc, doActions=True): - # pass False as callPreParse arg to _parse for first element, since we already - # pre-parsed the string as part of our And pre-parsing - loc, resultlist = self.exprs[0]._parse( - instring, loc, doActions, callPreParse=False - ) - errorStop = False - for e in self.exprs[1:]: - # if isinstance(e, And._ErrorStop): - if type(e) is And._ErrorStop: - errorStop = True - continue - if errorStop: - try: - loc, exprtokens = e._parse(instring, loc, doActions) - except ParseSyntaxException: - raise - except ParseBaseException as pe: - pe.__traceback__ = None - raise ParseSyntaxException._from_exception(pe) - except IndexError: - raise ParseSyntaxException( - instring, len(instring), self.errmsg, self - ) - else: - loc, exprtokens = e._parse(instring, loc, doActions) - if exprtokens or exprtokens.haskeys(): - resultlist += exprtokens - return loc, resultlist - - def __iadd__(self, other): - if isinstance(other, str_type): - other = self._literalStringClass(other) - return self.append(other) # And([self, other]) - - def _checkRecursion(self, parseElementList): - subRecCheckList = parseElementList[:] + [self] - for e in self.exprs: - e._checkRecursion(subRecCheckList) - if not e.mayReturnEmpty: - break - - def _generateDefaultName(self): - inner = " ".join(str(e) for e in self.exprs) - # strip off redundant inner {}'s - while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}": - inner = inner[1:-1] - return "{" + inner + "}" - - -class Or(ParseExpression): - """Requires that at least one :class:`ParseExpression` is found. If - two expressions match, the expression that matches the longest - string will be used. May be constructed using the ``'^'`` - operator. - - Example:: - - # construct Or using '^' operator - - number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) - print(number.search_string("123 3.1416 789")) - - prints:: - - [['123'], ['3.1416'], ['789']] - """ - - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): - super().__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) - else: - self.mayReturnEmpty = True - - def streamline(self) -> ParserElement: - super().streamline() - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - self.saveAsList = any(e.saveAsList for e in self.exprs) - self.skipWhitespace = all( - e.skipWhitespace and not isinstance(e, White) for e in self.exprs - ) - else: - self.saveAsList = False - return self - - def parseImpl(self, instring, loc, doActions=True): - maxExcLoc = -1 - maxException = None - matches = [] - fatals = [] - if all(e.callPreparse for e in self.exprs): - loc = self.preParse(instring, loc) - for e in self.exprs: - try: - loc2 = e.try_parse(instring, loc, raise_fatal=True) - except ParseFatalException as pfe: - pfe.__traceback__ = None - pfe.parserElement = e - fatals.append(pfe) - maxException = None - maxExcLoc = -1 - except ParseException as err: - if not fatals: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException( - instring, len(instring), e.errmsg, self - ) - maxExcLoc = len(instring) - else: - # save match among all matches, to retry longest to shortest - matches.append((loc2, e)) - - if matches: - # re-evaluate all matches in descending order of length of match, in case attached actions - # might change whether or how much they match of the input. - matches.sort(key=itemgetter(0), reverse=True) - - if not doActions: - # no further conditions or parse actions to change the selection of - # alternative, so the first match will be the best match - best_expr = matches[0][1] - return best_expr._parse(instring, loc, doActions) - - longest = -1, None - for loc1, expr1 in matches: - if loc1 <= longest[0]: - # already have a longer match than this one will deliver, we are done - return longest - - try: - loc2, toks = expr1._parse(instring, loc, doActions) - except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - else: - if loc2 >= loc1: - return loc2, toks - # didn't match as much as before - elif loc2 > longest[0]: - longest = loc2, toks - - if longest != (-1, None): - return longest - - if fatals: - if len(fatals) > 1: - fatals.sort(key=lambda e: -e.loc) - if fatals[0].loc == fatals[1].loc: - fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement)))) - max_fatal = fatals[0] - raise max_fatal - - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException( - instring, loc, "no defined alternatives to match", self - ) - - def __ixor__(self, other): - if isinstance(other, str_type): - other = self._literalStringClass(other) - return self.append(other) # Or([self, other]) - - def _generateDefaultName(self): - return "{" + " ^ ".join(str(e) for e in self.exprs) + "}" - - def _setResultsName(self, name, listAllMatches=False): - if ( - __diag__.warn_multiple_tokens_in_named_alternation - and Diagnostics.warn_multiple_tokens_in_named_alternation - not in self.suppress_warnings_ - ): - if any( - isinstance(e, And) - and Diagnostics.warn_multiple_tokens_in_named_alternation - not in e.suppress_warnings_ - for e in self.exprs - ): - warnings.warn( - "{}: setting results name {!r} on {} expression " - "will return a list of all parsed tokens in an And alternative, " - "in prior versions only the first token was returned; enclose " - "contained argument in Group".format( - "warn_multiple_tokens_in_named_alternation", - name, - type(self).__name__, - ), - stacklevel=3, - ) - - return super()._setResultsName(name, listAllMatches) - - -class MatchFirst(ParseExpression): - """Requires that at least one :class:`ParseExpression` is found. If - more than one expression matches, the first one listed is the one that will - match. May be constructed using the ``'|'`` operator. - - Example:: - - # construct MatchFirst using '|' operator - - # watch the order of expressions to match - number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) - print(number.search_string("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] - - # put more selective expression first - number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) - print(number.search_string("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] - """ - - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): - super().__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) - else: - self.mayReturnEmpty = True - - def streamline(self) -> ParserElement: - if self.streamlined: - return self - - super().streamline() - if self.exprs: - self.saveAsList = any(e.saveAsList for e in self.exprs) - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = all( - e.skipWhitespace and not isinstance(e, White) for e in self.exprs - ) - else: - self.saveAsList = False - self.mayReturnEmpty = True - return self - - def parseImpl(self, instring, loc, doActions=True): - maxExcLoc = -1 - maxException = None - - for e in self.exprs: - try: - return e._parse( - instring, - loc, - doActions, - ) - except ParseFatalException as pfe: - pfe.__traceback__ = None - pfe.parserElement = e - raise - except ParseException as err: - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException( - instring, len(instring), e.errmsg, self - ) - maxExcLoc = len(instring) - - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException( - instring, loc, "no defined alternatives to match", self - ) - - def __ior__(self, other): - if isinstance(other, str_type): - other = self._literalStringClass(other) - return self.append(other) # MatchFirst([self, other]) - - def _generateDefaultName(self): - return "{" + " | ".join(str(e) for e in self.exprs) + "}" - - def _setResultsName(self, name, listAllMatches=False): - if ( - __diag__.warn_multiple_tokens_in_named_alternation - and Diagnostics.warn_multiple_tokens_in_named_alternation - not in self.suppress_warnings_ - ): - if any( - isinstance(e, And) - and Diagnostics.warn_multiple_tokens_in_named_alternation - not in e.suppress_warnings_ - for e in self.exprs - ): - warnings.warn( - "{}: setting results name {!r} on {} expression " - "will return a list of all parsed tokens in an And alternative, " - "in prior versions only the first token was returned; enclose " - "contained argument in Group".format( - "warn_multiple_tokens_in_named_alternation", - name, - type(self).__name__, - ), - stacklevel=3, - ) - - return super()._setResultsName(name, listAllMatches) - - -class Each(ParseExpression): - """Requires all given :class:`ParseExpression` s to be found, but in - any order. Expressions may be separated by whitespace. - - May be constructed using the ``'&'`` operator. - - Example:: - - color = one_of("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") - shape_type = one_of("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") - integer = Word(nums) - shape_attr = "shape:" + shape_type("shape") - posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") - color_attr = "color:" + color("color") - size_attr = "size:" + integer("size") - - # use Each (using operator '&') to accept attributes in any order - # (shape and posn are required, color and size are optional) - shape_spec = shape_attr & posn_attr & Opt(color_attr) & Opt(size_attr) - - shape_spec.run_tests(''' - shape: SQUARE color: BLACK posn: 100, 120 - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - color:GREEN size:20 shape:TRIANGLE posn:20,40 - ''' - ) - - prints:: - - shape: SQUARE color: BLACK posn: 100, 120 - ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] - - color: BLACK - - posn: ['100', ',', '120'] - - x: 100 - - y: 120 - - shape: SQUARE - - - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] - - color: BLUE - - posn: ['50', ',', '80'] - - x: 50 - - y: 80 - - shape: CIRCLE - - size: 50 - - - color: GREEN size: 20 shape: TRIANGLE posn: 20,40 - ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] - - color: GREEN - - posn: ['20', ',', '40'] - - x: 20 - - y: 40 - - shape: TRIANGLE - - size: 20 - """ - - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True): - super().__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - self.skipWhitespace = True - self.initExprGroups = True - self.saveAsList = True - - def streamline(self) -> ParserElement: - super().streamline() - if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - return self - - def parseImpl(self, instring, loc, doActions=True): - if self.initExprGroups: - self.opt1map = dict( - (id(e.expr), e) for e in self.exprs if isinstance(e, Opt) - ) - opt1 = [e.expr for e in self.exprs if isinstance(e, Opt)] - opt2 = [ - e - for e in self.exprs - if e.mayReturnEmpty and not isinstance(e, (Opt, Regex, ZeroOrMore)) - ] - self.optionals = opt1 + opt2 - self.multioptionals = [ - e.expr.set_results_name(e.resultsName, list_all_matches=True) - for e in self.exprs - if isinstance(e, _MultipleMatch) - ] - self.multirequired = [ - e.expr.set_results_name(e.resultsName, list_all_matches=True) - for e in self.exprs - if isinstance(e, OneOrMore) - ] - self.required = [ - e for e in self.exprs if not isinstance(e, (Opt, ZeroOrMore, OneOrMore)) - ] - self.required += self.multirequired - self.initExprGroups = False - - tmpLoc = loc - tmpReqd = self.required[:] - tmpOpt = self.optionals[:] - multis = self.multioptionals[:] - matchOrder = [] - - keepMatching = True - failed = [] - fatals = [] - while keepMatching: - tmpExprs = tmpReqd + tmpOpt + multis - failed.clear() - fatals.clear() - for e in tmpExprs: - try: - tmpLoc = e.try_parse(instring, tmpLoc, raise_fatal=True) - except ParseFatalException as pfe: - pfe.__traceback__ = None - pfe.parserElement = e - fatals.append(pfe) - failed.append(e) - except ParseException: - failed.append(e) - else: - matchOrder.append(self.opt1map.get(id(e), e)) - if e in tmpReqd: - tmpReqd.remove(e) - elif e in tmpOpt: - tmpOpt.remove(e) - if len(failed) == len(tmpExprs): - keepMatching = False - - # look for any ParseFatalExceptions - if fatals: - if len(fatals) > 1: - fatals.sort(key=lambda e: -e.loc) - if fatals[0].loc == fatals[1].loc: - fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement)))) - max_fatal = fatals[0] - raise max_fatal - - if tmpReqd: - missing = ", ".join([str(e) for e in tmpReqd]) - raise ParseException( - instring, - loc, - "Missing one or more required elements ({})".format(missing), - ) - - # add any unmatched Opts, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e, Opt) and e.expr in tmpOpt] - - total_results = ParseResults([]) - for e in matchOrder: - loc, results = e._parse(instring, loc, doActions) - total_results += results - - return loc, total_results - - def _generateDefaultName(self): - return "{" + " & ".join(str(e) for e in self.exprs) + "}" - - -class ParseElementEnhance(ParserElement): - """Abstract subclass of :class:`ParserElement`, for combining and - post-processing parsed tokens. - """ - - def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): - super().__init__(savelist) - if isinstance(expr, str_type): - if issubclass(self._literalStringClass, Token): - expr = self._literalStringClass(expr) - elif issubclass(type(self), self._literalStringClass): - expr = Literal(expr) - else: - expr = self._literalStringClass(Literal(expr)) - self.expr = expr - if expr is not None: - self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty - self.set_whitespace_chars( - expr.whiteChars, copy_defaults=expr.copyDefaultWhiteChars - ) - self.skipWhitespace = expr.skipWhitespace - self.saveAsList = expr.saveAsList - self.callPreparse = expr.callPreparse - self.ignoreExprs.extend(expr.ignoreExprs) - - def recurse(self) -> Sequence[ParserElement]: - return [self.expr] if self.expr is not None else [] - - def parseImpl(self, instring, loc, doActions=True): - if self.expr is not None: - return self.expr._parse(instring, loc, doActions, callPreParse=False) - else: - raise ParseException(instring, loc, "No expression defined", self) - - def leave_whitespace(self, recursive: bool = True) -> ParserElement: - super().leave_whitespace(recursive) - - if recursive: - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.leave_whitespace(recursive) - return self - - def ignore_whitespace(self, recursive: bool = True) -> ParserElement: - super().ignore_whitespace(recursive) - - if recursive: - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.ignore_whitespace(recursive) - return self - - def ignore(self, other) -> ParserElement: - if isinstance(other, Suppress): - if other not in self.ignoreExprs: - super().ignore(other) - if self.expr is not None: - self.expr.ignore(self.ignoreExprs[-1]) - else: - super().ignore(other) - if self.expr is not None: - self.expr.ignore(self.ignoreExprs[-1]) - return self - - def streamline(self) -> ParserElement: - super().streamline() - if self.expr is not None: - self.expr.streamline() - return self - - def _checkRecursion(self, parseElementList): - if self in parseElementList: - raise RecursiveGrammarException(parseElementList + [self]) - subRecCheckList = parseElementList[:] + [self] - if self.expr is not None: - self.expr._checkRecursion(subRecCheckList) - - def validate(self, validateTrace=None) -> None: - if validateTrace is None: - validateTrace = [] - tmp = validateTrace[:] + [self] - if self.expr is not None: - self.expr.validate(tmp) - self._checkRecursion([]) - - def _generateDefaultName(self): - return "{}:({})".format(self.__class__.__name__, str(self.expr)) - - ignoreWhitespace = ignore_whitespace - leaveWhitespace = leave_whitespace - - -class IndentedBlock(ParseElementEnhance): - """ - Expression to match one or more expressions at a given indentation level. - Useful for parsing text where structure is implied by indentation (like Python source code). - """ - - class _Indent(Empty): - def __init__(self, ref_col: int): - super().__init__() - self.errmsg = "expected indent at column {}".format(ref_col) - self.add_condition(lambda s, l, t: col(l, s) == ref_col) - - class _IndentGreater(Empty): - def __init__(self, ref_col: int): - super().__init__() - self.errmsg = "expected indent at column greater than {}".format(ref_col) - self.add_condition(lambda s, l, t: col(l, s) > ref_col) - - def __init__( - self, expr: ParserElement, *, recursive: bool = False, grouped: bool = True - ): - super().__init__(expr, savelist=True) - # if recursive: - # raise NotImplementedError("IndentedBlock with recursive is not implemented") - self._recursive = recursive - self._grouped = grouped - self.parent_anchor = 1 - - def parseImpl(self, instring, loc, doActions=True): - # advance parse position to non-whitespace by using an Empty() - # this should be the column to be used for all subsequent indented lines - anchor_loc = Empty().preParse(instring, loc) - - # see if self.expr matches at the current location - if not it will raise an exception - # and no further work is necessary - self.expr.try_parse(instring, anchor_loc, doActions) - - indent_col = col(anchor_loc, instring) - peer_detect_expr = self._Indent(indent_col) - - inner_expr = Empty() + peer_detect_expr + self.expr - if self._recursive: - sub_indent = self._IndentGreater(indent_col) - nested_block = IndentedBlock( - self.expr, recursive=self._recursive, grouped=self._grouped - ) - nested_block.set_debug(self.debug) - nested_block.parent_anchor = indent_col - inner_expr += Opt(sub_indent + nested_block) - - inner_expr.set_name(f"inner {hex(id(inner_expr))[-4:].upper()}@{indent_col}") - block = OneOrMore(inner_expr) - - trailing_undent = self._Indent(self.parent_anchor) | StringEnd() - - if self._grouped: - wrapper = Group - else: - wrapper = lambda expr: expr - return (wrapper(block) + Optional(trailing_undent)).parseImpl( - instring, anchor_loc, doActions - ) - - -class AtStringStart(ParseElementEnhance): - """Matches if expression matches at the beginning of the parse - string:: - - AtStringStart(Word(nums)).parse_string("123") - # prints ["123"] - - AtStringStart(Word(nums)).parse_string(" 123") - # raises ParseException - """ - - def __init__(self, expr: Union[ParserElement, str]): - super().__init__(expr) - self.callPreparse = False - - def parseImpl(self, instring, loc, doActions=True): - if loc != 0: - raise ParseException(instring, loc, "not found at string start") - return super().parseImpl(instring, loc, doActions) - - -class AtLineStart(ParseElementEnhance): - r"""Matches if an expression matches at the beginning of a line within - the parse string - - Example:: - - test = '''\ - AAA this line - AAA and this line - AAA but not this one - B AAA and definitely not this one - ''' - - for t in (AtLineStart('AAA') + restOfLine).search_string(test): - print(t) - - prints:: - - ['AAA', ' this line'] - ['AAA', ' and this line'] - - """ - - def __init__(self, expr: Union[ParserElement, str]): - super().__init__(expr) - self.callPreparse = False - - def parseImpl(self, instring, loc, doActions=True): - if col(loc, instring) != 1: - raise ParseException(instring, loc, "not found at line start") - return super().parseImpl(instring, loc, doActions) - - -class FollowedBy(ParseElementEnhance): - """Lookahead matching of the given parse expression. - ``FollowedBy`` does *not* advance the parsing position within - the input string, it only verifies that the specified parse - expression matches at the current position. ``FollowedBy`` - always returns a null token list. If any results names are defined - in the lookahead expression, those *will* be returned for access by - name. - - Example:: - - # use FollowedBy to match a label only if it is followed by a ':' - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - - attr_expr[1, ...].parse_string("shape: SQUARE color: BLACK posn: upper left").pprint() - - prints:: - - [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] - """ - - def __init__(self, expr: Union[ParserElement, str]): - super().__init__(expr) - self.mayReturnEmpty = True - - def parseImpl(self, instring, loc, doActions=True): - # by using self._expr.parse and deleting the contents of the returned ParseResults list - # we keep any named results that were defined in the FollowedBy expression - _, ret = self.expr._parse(instring, loc, doActions=doActions) - del ret[:] - - return loc, ret - - -class PrecededBy(ParseElementEnhance): - """Lookbehind matching of the given parse expression. - ``PrecededBy`` does not advance the parsing position within the - input string, it only verifies that the specified parse expression - matches prior to the current position. ``PrecededBy`` always - returns a null token list, but if a results name is defined on the - given expression, it is returned. - - Parameters: - - - expr - expression that must match prior to the current parse - location - - retreat - (default= ``None``) - (int) maximum number of characters - to lookbehind prior to the current parse location - - If the lookbehind expression is a string, :class:`Literal`, - :class:`Keyword`, or a :class:`Word` or :class:`CharsNotIn` - with a specified exact or maximum length, then the retreat - parameter is not required. Otherwise, retreat must be specified to - give a maximum number of characters to look back from - the current parse position for a lookbehind match. - - Example:: - - # VB-style variable names with type prefixes - int_var = PrecededBy("#") + pyparsing_common.identifier - str_var = PrecededBy("$") + pyparsing_common.identifier - - """ - - def __init__( - self, expr: Union[ParserElement, str], retreat: typing.Optional[int] = None - ): - super().__init__(expr) - self.expr = self.expr().leave_whitespace() - self.mayReturnEmpty = True - self.mayIndexError = False - self.exact = False - if isinstance(expr, str_type): - retreat = len(expr) - self.exact = True - elif isinstance(expr, (Literal, Keyword)): - retreat = expr.matchLen - self.exact = True - elif isinstance(expr, (Word, CharsNotIn)) and expr.maxLen != _MAX_INT: - retreat = expr.maxLen - self.exact = True - elif isinstance(expr, PositionToken): - retreat = 0 - self.exact = True - self.retreat = retreat - self.errmsg = "not preceded by " + str(expr) - self.skipWhitespace = False - self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None))) - - def parseImpl(self, instring, loc=0, doActions=True): - if self.exact: - if loc < self.retreat: - raise ParseException(instring, loc, self.errmsg) - start = loc - self.retreat - _, ret = self.expr._parse(instring, start) - else: - # retreat specified a maximum lookbehind window, iterate - test_expr = self.expr + StringEnd() - instring_slice = instring[max(0, loc - self.retreat) : loc] - last_expr = ParseException(instring, loc, self.errmsg) - for offset in range(1, min(loc, self.retreat + 1) + 1): - try: - # print('trying', offset, instring_slice, repr(instring_slice[loc - offset:])) - _, ret = test_expr._parse( - instring_slice, len(instring_slice) - offset - ) - except ParseBaseException as pbe: - last_expr = pbe - else: - break - else: - raise last_expr - return loc, ret - - -class Located(ParseElementEnhance): - """ - Decorates a returned token with its starting and ending - locations in the input string. - - This helper adds the following results names: - - - ``locn_start`` - location where matched expression begins - - ``locn_end`` - location where matched expression ends - - ``value`` - the actual parsed results - - Be careful if the input text contains ```` characters, you - may want to call :class:`ParserElement.parse_with_tabs` - - Example:: - - wd = Word(alphas) - for match in Located(wd).search_string("ljsdf123lksdjjf123lkkjj1222"): - print(match) - - prints:: - - [0, ['ljsdf'], 5] - [8, ['lksdjjf'], 15] - [18, ['lkkjj'], 23] - - """ - - def parseImpl(self, instring, loc, doActions=True): - start = loc - loc, tokens = self.expr._parse(instring, start, doActions, callPreParse=False) - ret_tokens = ParseResults([start, tokens, loc]) - ret_tokens["locn_start"] = start - ret_tokens["value"] = tokens - ret_tokens["locn_end"] = loc - if self.resultsName: - # must return as a list, so that the name will be attached to the complete group - return loc, [ret_tokens] - else: - return loc, ret_tokens - - -class NotAny(ParseElementEnhance): - """ - Lookahead to disallow matching with the given parse expression. - ``NotAny`` does *not* advance the parsing position within the - input string, it only verifies that the specified parse expression - does *not* match at the current position. Also, ``NotAny`` does - *not* skip over leading whitespace. ``NotAny`` always returns - a null token list. May be constructed using the ``'~'`` operator. - - Example:: - - AND, OR, NOT = map(CaselessKeyword, "AND OR NOT".split()) - - # take care not to mistake keywords for identifiers - ident = ~(AND | OR | NOT) + Word(alphas) - boolean_term = Opt(NOT) + ident - - # very crude boolean expression - to support parenthesis groups and - # operation hierarchy, use infix_notation - boolean_expr = boolean_term + ((AND | OR) + boolean_term)[...] - - # integers that are followed by "." are actually floats - integer = Word(nums) + ~Char(".") - """ - - def __init__(self, expr: Union[ParserElement, str]): - super().__init__(expr) - # do NOT use self.leave_whitespace(), don't want to propagate to exprs - # self.leave_whitespace() - self.skipWhitespace = False - - self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, " + str(self.expr) - - def parseImpl(self, instring, loc, doActions=True): - if self.expr.can_parse_next(instring, loc): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - def _generateDefaultName(self): - return "~{" + str(self.expr) + "}" - - -class _MultipleMatch(ParseElementEnhance): - def __init__( - self, - expr: ParserElement, - stop_on: typing.Optional[Union[ParserElement, str]] = None, - *, - stopOn: typing.Optional[Union[ParserElement, str]] = None, - ): - super().__init__(expr) - stopOn = stopOn or stop_on - self.saveAsList = True - ender = stopOn - if isinstance(ender, str_type): - ender = self._literalStringClass(ender) - self.stopOn(ender) - - def stopOn(self, ender) -> ParserElement: - if isinstance(ender, str_type): - ender = self._literalStringClass(ender) - self.not_ender = ~ender if ender is not None else None - return self - - def parseImpl(self, instring, loc, doActions=True): - self_expr_parse = self.expr._parse - self_skip_ignorables = self._skipIgnorables - check_ender = self.not_ender is not None - if check_ender: - try_not_ender = self.not_ender.tryParse - - # must be at least one (but first see if we are the stopOn sentinel; - # if so, fail) - if check_ender: - try_not_ender(instring, loc) - loc, tokens = self_expr_parse(instring, loc, doActions) - try: - hasIgnoreExprs = not not self.ignoreExprs - while 1: - if check_ender: - try_not_ender(instring, loc) - if hasIgnoreExprs: - preloc = self_skip_ignorables(instring, loc) - else: - preloc = loc - loc, tmptokens = self_expr_parse(instring, preloc, doActions) - if tmptokens or tmptokens.haskeys(): - tokens += tmptokens - except (ParseException, IndexError): - pass - - return loc, tokens - - def _setResultsName(self, name, listAllMatches=False): - if ( - __diag__.warn_ungrouped_named_tokens_in_collection - and Diagnostics.warn_ungrouped_named_tokens_in_collection - not in self.suppress_warnings_ - ): - for e in [self.expr] + self.expr.recurse(): - if ( - isinstance(e, ParserElement) - and e.resultsName - and Diagnostics.warn_ungrouped_named_tokens_in_collection - not in e.suppress_warnings_ - ): - warnings.warn( - "{}: setting results name {!r} on {} expression " - "collides with {!r} on contained expression".format( - "warn_ungrouped_named_tokens_in_collection", - name, - type(self).__name__, - e.resultsName, - ), - stacklevel=3, - ) - - return super()._setResultsName(name, listAllMatches) - - -class OneOrMore(_MultipleMatch): - """ - Repetition of one or more of the given expression. - - Parameters: - - expr - expression that must match one or more times - - stop_on - (default= ``None``) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - - Example:: - - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).set_parse_action(' '.join)) - - text = "shape: SQUARE posn: upper left color: BLACK" - attr_expr[1, ...].parse_string(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] - - # use stop_on attribute for OneOrMore to avoid reading label string as part of the data - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - OneOrMore(attr_expr).parse_string(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] - - # could also be written as - (attr_expr * (1,)).parse_string(text).pprint() - """ - - def _generateDefaultName(self): - return "{" + str(self.expr) + "}..." - - -class ZeroOrMore(_MultipleMatch): - """ - Optional repetition of zero or more of the given expression. - - Parameters: - - ``expr`` - expression that must match zero or more times - - ``stop_on`` - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - (default= ``None``) - - Example: similar to :class:`OneOrMore` - """ - - def __init__( - self, - expr: ParserElement, - stop_on: typing.Optional[Union[ParserElement, str]] = None, - *, - stopOn: typing.Optional[Union[ParserElement, str]] = None, - ): - super().__init__(expr, stopOn=stopOn or stop_on) - self.mayReturnEmpty = True - - def parseImpl(self, instring, loc, doActions=True): - try: - return super().parseImpl(instring, loc, doActions) - except (ParseException, IndexError): - return loc, ParseResults([], name=self.resultsName) - - def _generateDefaultName(self): - return "[" + str(self.expr) + "]..." - - -class _NullToken: - def __bool__(self): - return False - - def __str__(self): - return "" - - -class Opt(ParseElementEnhance): - """ - Optional matching of the given expression. - - Parameters: - - ``expr`` - expression that must match zero or more times - - ``default`` (optional) - value to be returned if the optional expression is not found. - - Example:: - - # US postal code can be a 5-digit zip, plus optional 4-digit qualifier - zip = Combine(Word(nums, exact=5) + Opt('-' + Word(nums, exact=4))) - zip.run_tests(''' - # traditional ZIP code - 12345 - - # ZIP+4 form - 12101-0001 - - # invalid ZIP - 98765- - ''') - - prints:: - - # traditional ZIP code - 12345 - ['12345'] - - # ZIP+4 form - 12101-0001 - ['12101-0001'] - - # invalid ZIP - 98765- - ^ - FAIL: Expected end of text (at char 5), (line:1, col:6) - """ - - __optionalNotMatched = _NullToken() - - def __init__( - self, expr: Union[ParserElement, str], default: Any = __optionalNotMatched - ): - super().__init__(expr, savelist=False) - self.saveAsList = self.expr.saveAsList - self.defaultValue = default - self.mayReturnEmpty = True - - def parseImpl(self, instring, loc, doActions=True): - self_expr = self.expr - try: - loc, tokens = self_expr._parse(instring, loc, doActions, callPreParse=False) - except (ParseException, IndexError): - default_value = self.defaultValue - if default_value is not self.__optionalNotMatched: - if self_expr.resultsName: - tokens = ParseResults([default_value]) - tokens[self_expr.resultsName] = default_value - else: - tokens = [default_value] - else: - tokens = [] - return loc, tokens - - def _generateDefaultName(self): - inner = str(self.expr) - # strip off redundant inner {}'s - while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}": - inner = inner[1:-1] - return "[" + inner + "]" - - -Optional = Opt - - -class SkipTo(ParseElementEnhance): - """ - Token for skipping over all undefined text until the matched - expression is found. - - Parameters: - - ``expr`` - target expression marking the end of the data to be skipped - - ``include`` - if ``True``, the target expression is also parsed - (the skipped text and target expression are returned as a 2-element - list) (default= ``False``). - - ``ignore`` - (default= ``None``) used to define grammars (typically quoted strings and - comments) that might contain false matches to the target expression - - ``fail_on`` - (default= ``None``) define expressions that are not allowed to be - included in the skipped test; if found before the target expression is found, - the :class:`SkipTo` is not a match - - Example:: - - report = ''' - Outstanding Issues Report - 1 Jan 2000 - - # | Severity | Description | Days Open - -----+----------+-------------------------------------------+----------- - 101 | Critical | Intermittent system crash | 6 - 94 | Cosmetic | Spelling error on Login ('log|n') | 14 - 79 | Minor | System slow when running too many reports | 47 - ''' - integer = Word(nums) - SEP = Suppress('|') - # use SkipTo to simply match everything up until the next SEP - # - ignore quoted strings, so that a '|' character inside a quoted string does not match - # - parse action will call token.strip() for each matched token, i.e., the description body - string_data = SkipTo(SEP, ignore=quoted_string) - string_data.set_parse_action(token_map(str.strip)) - ticket_expr = (integer("issue_num") + SEP - + string_data("sev") + SEP - + string_data("desc") + SEP - + integer("days_open")) - - for tkt in ticket_expr.search_string(report): - print tkt.dump() - - prints:: - - ['101', 'Critical', 'Intermittent system crash', '6'] - - days_open: '6' - - desc: 'Intermittent system crash' - - issue_num: '101' - - sev: 'Critical' - ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] - - days_open: '14' - - desc: "Spelling error on Login ('log|n')" - - issue_num: '94' - - sev: 'Cosmetic' - ['79', 'Minor', 'System slow when running too many reports', '47'] - - days_open: '47' - - desc: 'System slow when running too many reports' - - issue_num: '79' - - sev: 'Minor' - """ - - def __init__( - self, - other: Union[ParserElement, str], - include: bool = False, - ignore: bool = None, - fail_on: typing.Optional[Union[ParserElement, str]] = None, - *, - failOn: Union[ParserElement, str] = None, - ): - super().__init__(other) - failOn = failOn or fail_on - self.ignoreExpr = ignore - self.mayReturnEmpty = True - self.mayIndexError = False - self.includeMatch = include - self.saveAsList = False - if isinstance(failOn, str_type): - self.failOn = self._literalStringClass(failOn) - else: - self.failOn = failOn - self.errmsg = "No match found for " + str(self.expr) - - def parseImpl(self, instring, loc, doActions=True): - startloc = loc - instrlen = len(instring) - self_expr_parse = self.expr._parse - self_failOn_canParseNext = ( - self.failOn.canParseNext if self.failOn is not None else None - ) - self_ignoreExpr_tryParse = ( - self.ignoreExpr.tryParse if self.ignoreExpr is not None else None - ) - - tmploc = loc - while tmploc <= instrlen: - if self_failOn_canParseNext is not None: - # break if failOn expression matches - if self_failOn_canParseNext(instring, tmploc): - break - - if self_ignoreExpr_tryParse is not None: - # advance past ignore expressions - while 1: - try: - tmploc = self_ignoreExpr_tryParse(instring, tmploc) - except ParseBaseException: - break - - try: - self_expr_parse(instring, tmploc, doActions=False, callPreParse=False) - except (ParseException, IndexError): - # no match, advance loc in string - tmploc += 1 - else: - # matched skipto expr, done - break - - else: - # ran off the end of the input string without matching skipto expr, fail - raise ParseException(instring, loc, self.errmsg, self) - - # build up return values - loc = tmploc - skiptext = instring[startloc:loc] - skipresult = ParseResults(skiptext) - - if self.includeMatch: - loc, mat = self_expr_parse(instring, loc, doActions, callPreParse=False) - skipresult += mat - - return loc, skipresult - - -class Forward(ParseElementEnhance): - """ - Forward declaration of an expression to be defined later - - used for recursive grammars, such as algebraic infix notation. - When the expression is known, it is assigned to the ``Forward`` - variable using the ``'<<'`` operator. - - Note: take care when assigning to ``Forward`` not to overlook - precedence of operators. - - Specifically, ``'|'`` has a lower precedence than ``'<<'``, so that:: - - fwd_expr << a | b | c - - will actually be evaluated as:: - - (fwd_expr << a) | b | c - - thereby leaving b and c out as parseable alternatives. It is recommended that you - explicitly group the values inserted into the ``Forward``:: - - fwd_expr << (a | b | c) - - Converting to use the ``'<<='`` operator instead will avoid this problem. - - See :class:`ParseResults.pprint` for an example of a recursive - parser created using ``Forward``. - """ - - def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None): - self.caller_frame = traceback.extract_stack(limit=2)[0] - super().__init__(other, savelist=False) - self.lshift_line = None - - def __lshift__(self, other): - if hasattr(self, "caller_frame"): - del self.caller_frame - if isinstance(other, str_type): - other = self._literalStringClass(other) - self.expr = other - self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty - self.set_whitespace_chars( - self.expr.whiteChars, copy_defaults=self.expr.copyDefaultWhiteChars - ) - self.skipWhitespace = self.expr.skipWhitespace - self.saveAsList = self.expr.saveAsList - self.ignoreExprs.extend(self.expr.ignoreExprs) - self.lshift_line = traceback.extract_stack(limit=2)[-2] - return self - - def __ilshift__(self, other): - return self << other - - def __or__(self, other): - caller_line = traceback.extract_stack(limit=2)[-2] - if ( - __diag__.warn_on_match_first_with_lshift_operator - and caller_line == self.lshift_line - and Diagnostics.warn_on_match_first_with_lshift_operator - not in self.suppress_warnings_ - ): - warnings.warn( - "using '<<' operator with '|' is probably an error, use '<<='", - stacklevel=2, - ) - ret = super().__or__(other) - return ret - - def __del__(self): - # see if we are getting dropped because of '=' reassignment of var instead of '<<=' or '<<' - if ( - self.expr is None - and __diag__.warn_on_assignment_to_Forward - and Diagnostics.warn_on_assignment_to_Forward not in self.suppress_warnings_ - ): - warnings.warn_explicit( - "Forward defined here but no expression attached later using '<<=' or '<<'", - UserWarning, - filename=self.caller_frame.filename, - lineno=self.caller_frame.lineno, - ) - - def parseImpl(self, instring, loc, doActions=True): - if ( - self.expr is None - and __diag__.warn_on_parse_using_empty_Forward - and Diagnostics.warn_on_parse_using_empty_Forward - not in self.suppress_warnings_ - ): - # walk stack until parse_string, scan_string, search_string, or transform_string is found - parse_fns = [ - "parse_string", - "scan_string", - "search_string", - "transform_string", - ] - tb = traceback.extract_stack(limit=200) - for i, frm in enumerate(reversed(tb), start=1): - if frm.name in parse_fns: - stacklevel = i + 1 - break - else: - stacklevel = 2 - warnings.warn( - "Forward expression was never assigned a value, will not parse any input", - stacklevel=stacklevel, - ) - if not ParserElement._left_recursion_enabled: - return super().parseImpl(instring, loc, doActions) - # ## Bounded Recursion algorithm ## - # Recursion only needs to be processed at ``Forward`` elements, since they are - # the only ones that can actually refer to themselves. The general idea is - # to handle recursion stepwise: We start at no recursion, then recurse once, - # recurse twice, ..., until more recursion offers no benefit (we hit the bound). - # - # The "trick" here is that each ``Forward`` gets evaluated in two contexts - # - to *match* a specific recursion level, and - # - to *search* the bounded recursion level - # and the two run concurrently. The *search* must *match* each recursion level - # to find the best possible match. This is handled by a memo table, which - # provides the previous match to the next level match attempt. - # - # See also "Left Recursion in Parsing Expression Grammars", Medeiros et al. - # - # There is a complication since we not only *parse* but also *transform* via - # actions: We do not want to run the actions too often while expanding. Thus, - # we expand using `doActions=False` and only run `doActions=True` if the next - # recursion level is acceptable. - with ParserElement.recursion_lock: - memo = ParserElement.recursion_memos - try: - # we are parsing at a specific recursion expansion - use it as-is - prev_loc, prev_result = memo[loc, self, doActions] - if isinstance(prev_result, Exception): - raise prev_result - return prev_loc, prev_result.copy() - except KeyError: - act_key = (loc, self, True) - peek_key = (loc, self, False) - # we are searching for the best recursion expansion - keep on improving - # both `doActions` cases must be tracked separately here! - prev_loc, prev_peek = memo[peek_key] = ( - loc - 1, - ParseException( - instring, loc, "Forward recursion without base case", self - ), - ) - if doActions: - memo[act_key] = memo[peek_key] - while True: - try: - new_loc, new_peek = super().parseImpl(instring, loc, False) - except ParseException: - # we failed before getting any match – do not hide the error - if isinstance(prev_peek, Exception): - raise - new_loc, new_peek = prev_loc, prev_peek - # the match did not get better: we are done - if new_loc <= prev_loc: - if doActions: - # replace the match for doActions=False as well, - # in case the action did backtrack - prev_loc, prev_result = memo[peek_key] = memo[act_key] - del memo[peek_key], memo[act_key] - return prev_loc, prev_result.copy() - del memo[peek_key] - return prev_loc, prev_peek.copy() - # the match did get better: see if we can improve further - else: - if doActions: - try: - memo[act_key] = super().parseImpl(instring, loc, True) - except ParseException as e: - memo[peek_key] = memo[act_key] = (new_loc, e) - raise - prev_loc, prev_peek = memo[peek_key] = new_loc, new_peek - - def leave_whitespace(self, recursive: bool = True) -> ParserElement: - self.skipWhitespace = False - return self - - def ignore_whitespace(self, recursive: bool = True) -> ParserElement: - self.skipWhitespace = True - return self - - def streamline(self) -> ParserElement: - if not self.streamlined: - self.streamlined = True - if self.expr is not None: - self.expr.streamline() - return self - - def validate(self, validateTrace=None) -> None: - if validateTrace is None: - validateTrace = [] - - if self not in validateTrace: - tmp = validateTrace[:] + [self] - if self.expr is not None: - self.expr.validate(tmp) - self._checkRecursion([]) - - def _generateDefaultName(self): - # Avoid infinite recursion by setting a temporary _defaultName - self._defaultName = ": ..." - - # Use the string representation of main expression. - retString = "..." - try: - if self.expr is not None: - retString = str(self.expr)[:1000] - else: - retString = "None" - finally: - return self.__class__.__name__ + ": " + retString - - def copy(self) -> ParserElement: - if self.expr is not None: - return super().copy() - else: - ret = Forward() - ret <<= self - return ret - - def _setResultsName(self, name, list_all_matches=False): - if ( - __diag__.warn_name_set_on_empty_Forward - and Diagnostics.warn_name_set_on_empty_Forward - not in self.suppress_warnings_ - ): - if self.expr is None: - warnings.warn( - "{}: setting results name {!r} on {} expression " - "that has no contained expression".format( - "warn_name_set_on_empty_Forward", name, type(self).__name__ - ), - stacklevel=3, - ) - - return super()._setResultsName(name, list_all_matches) - - ignoreWhitespace = ignore_whitespace - leaveWhitespace = leave_whitespace - - -class TokenConverter(ParseElementEnhance): - """ - Abstract subclass of :class:`ParseExpression`, for converting parsed results. - """ - - def __init__(self, expr: Union[ParserElement, str], savelist=False): - super().__init__(expr) # , savelist) - self.saveAsList = False - - -class Combine(TokenConverter): - """Converter to concatenate all matching tokens to a single string. - By default, the matching patterns must also be contiguous in the - input string; this can be disabled by specifying - ``'adjacent=False'`` in the constructor. - - Example:: - - real = Word(nums) + '.' + Word(nums) - print(real.parse_string('3.1416')) # -> ['3', '.', '1416'] - # will also erroneously match the following - print(real.parse_string('3. 1416')) # -> ['3', '.', '1416'] - - real = Combine(Word(nums) + '.' + Word(nums)) - print(real.parse_string('3.1416')) # -> ['3.1416'] - # no match when there are internal spaces - print(real.parse_string('3. 1416')) # -> Exception: Expected W:(0123...) - """ - - def __init__( - self, - expr: ParserElement, - join_string: str = "", - adjacent: bool = True, - *, - joinString: typing.Optional[str] = None, - ): - super().__init__(expr) - joinString = joinString if joinString is not None else join_string - # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself - if adjacent: - self.leave_whitespace() - self.adjacent = adjacent - self.skipWhitespace = True - self.joinString = joinString - self.callPreparse = True - - def ignore(self, other) -> ParserElement: - if self.adjacent: - ParserElement.ignore(self, other) - else: - super().ignore(other) - return self - - def postParse(self, instring, loc, tokenlist): - retToks = tokenlist.copy() - del retToks[:] - retToks += ParseResults( - ["".join(tokenlist._asStringList(self.joinString))], modal=self.modalResults - ) - - if self.resultsName and retToks.haskeys(): - return [retToks] - else: - return retToks - - -class Group(TokenConverter): - """Converter to return the matched tokens as a list - useful for - returning tokens of :class:`ZeroOrMore` and :class:`OneOrMore` expressions. - - The optional ``aslist`` argument when set to True will return the - parsed tokens as a Python list instead of a pyparsing ParseResults. - - Example:: - - ident = Word(alphas) - num = Word(nums) - term = ident | num - func = ident + Opt(delimited_list(term)) - print(func.parse_string("fn a, b, 100")) - # -> ['fn', 'a', 'b', '100'] - - func = ident + Group(Opt(delimited_list(term))) - print(func.parse_string("fn a, b, 100")) - # -> ['fn', ['a', 'b', '100']] - """ - - def __init__(self, expr: ParserElement, aslist: bool = False): - super().__init__(expr) - self.saveAsList = True - self._asPythonList = aslist - - def postParse(self, instring, loc, tokenlist): - if self._asPythonList: - return ParseResults.List( - tokenlist.asList() - if isinstance(tokenlist, ParseResults) - else list(tokenlist) - ) - else: - return [tokenlist] - - -class Dict(TokenConverter): - """Converter to return a repetitive expression as a list, but also - as a dictionary. Each element can also be referenced using the first - token in the expression as its key. Useful for tabular report - scraping when the first column can be used as a item key. - - The optional ``asdict`` argument when set to True will return the - parsed tokens as a Python dict instead of a pyparsing ParseResults. - - Example:: - - data_word = Word(alphas) - label = data_word + FollowedBy(':') - - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - - # print attributes as plain groups - print(attr_expr[1, ...].parse_string(text).dump()) - - # instead of OneOrMore(expr), parse using Dict(Group(expr)[1, ...]) - Dict will auto-assign names - result = Dict(Group(attr_expr)[1, ...]).parse_string(text) - print(result.dump()) - - # access named fields as dict entries, or output as dict - print(result['shape']) - print(result.as_dict()) - - prints:: - - ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: 'light blue' - - posn: 'upper left' - - shape: 'SQUARE' - - texture: 'burlap' - SQUARE - {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} - - See more examples at :class:`ParseResults` of accessing fields by results name. - """ - - def __init__(self, expr: ParserElement, asdict: bool = False): - super().__init__(expr) - self.saveAsList = True - self._asPythonDict = asdict - - def postParse(self, instring, loc, tokenlist): - for i, tok in enumerate(tokenlist): - if len(tok) == 0: - continue - - ikey = tok[0] - if isinstance(ikey, int): - ikey = str(ikey).strip() - - if len(tok) == 1: - tokenlist[ikey] = _ParseResultsWithOffset("", i) - - elif len(tok) == 2 and not isinstance(tok[1], ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1], i) - - else: - try: - dictvalue = tok.copy() # ParseResults(i) - except Exception: - exc = TypeError( - "could not extract dict values from parsed results" - " - Dict expression must contain Grouped expressions" - ) - raise exc from None - - del dictvalue[0] - - if len(dictvalue) != 1 or ( - isinstance(dictvalue, ParseResults) and dictvalue.haskeys() - ): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue, i) - else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i) - - if self._asPythonDict: - return [tokenlist.as_dict()] if self.resultsName else tokenlist.as_dict() - else: - return [tokenlist] if self.resultsName else tokenlist - - -class Suppress(TokenConverter): - """Converter for ignoring the results of a parsed expression. - - Example:: - - source = "a, b, c,d" - wd = Word(alphas) - wd_list1 = wd + (',' + wd)[...] - print(wd_list1.parse_string(source)) - - # often, delimiters that are useful during parsing are just in the - # way afterward - use Suppress to keep them out of the parsed output - wd_list2 = wd + (Suppress(',') + wd)[...] - print(wd_list2.parse_string(source)) - - # Skipped text (using '...') can be suppressed as well - source = "lead in START relevant text END trailing text" - start_marker = Keyword("START") - end_marker = Keyword("END") - find_body = Suppress(...) + start_marker + ... + end_marker - print(find_body.parse_string(source) - - prints:: - - ['a', ',', 'b', ',', 'c', ',', 'd'] - ['a', 'b', 'c', 'd'] - ['START', 'relevant text ', 'END'] - - (See also :class:`delimited_list`.) - """ - - def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): - if expr is ...: - expr = _PendingSkip(NoMatch()) - super().__init__(expr) - - def __add__(self, other) -> "ParserElement": - if isinstance(self.expr, _PendingSkip): - return Suppress(SkipTo(other)) + other - else: - return super().__add__(other) - - def __sub__(self, other) -> "ParserElement": - if isinstance(self.expr, _PendingSkip): - return Suppress(SkipTo(other)) - other - else: - return super().__sub__(other) - - def postParse(self, instring, loc, tokenlist): - return [] - - def suppress(self) -> ParserElement: - return self - - -def trace_parse_action(f: ParseAction) -> ParseAction: - """Decorator for debugging parse actions. - - When the parse action is called, this decorator will print - ``">> entering method-name(line:, , )"``. - When the parse action completes, the decorator will print - ``"<<"`` followed by the returned value, or any exception that the parse action raised. - - Example:: - - wd = Word(alphas) - - @trace_parse_action - def remove_duplicate_chars(tokens): - return ''.join(sorted(set(''.join(tokens)))) - - wds = wd[1, ...].set_parse_action(remove_duplicate_chars) - print(wds.parse_string("slkdjs sld sldd sdlf sdljf")) - - prints:: - - >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) - < 3: - thisFunc = paArgs[0].__class__.__name__ + "." + thisFunc - sys.stderr.write( - ">>entering {}(line: {!r}, {}, {!r})\n".format(thisFunc, line(l, s), l, t) - ) - try: - ret = f(*paArgs) - except Exception as exc: - sys.stderr.write("< str: - r"""Helper to easily define string ranges for use in :class:`Word` - construction. Borrows syntax from regexp ``'[]'`` string range - definitions:: - - srange("[0-9]") -> "0123456789" - srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" - srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" - - The input string must be enclosed in []'s, and the returned string - is the expanded character set joined into a single string. The - values enclosed in the []'s may be: - - - a single character - - an escaped character with a leading backslash (such as ``\-`` - or ``\]``) - - an escaped hex character with a leading ``'\x'`` - (``\x21``, which is a ``'!'`` character) (``\0x##`` - is also supported for backwards compatibility) - - an escaped octal character with a leading ``'\0'`` - (``\041``, which is a ``'!'`` character) - - a range of any of the above, separated by a dash (``'a-z'``, - etc.) - - any combination of the above (``'aeiouy'``, - ``'a-zA-Z0-9_$'``, etc.) - """ - _expanded = ( - lambda p: p - if not isinstance(p, ParseResults) - else "".join(chr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) - ) - try: - return "".join(_expanded(part) for part in _reBracketExpr.parse_string(s).body) - except Exception: - return "" - - -def token_map(func, *args) -> ParseAction: - """Helper to define a parse action by mapping a function to all - elements of a :class:`ParseResults` list. If any additional args are passed, - they are forwarded to the given function as additional arguments - after the token, as in - ``hex_integer = Word(hexnums).set_parse_action(token_map(int, 16))``, - which will convert the parsed data to an integer using base 16. - - Example (compare the last to example in :class:`ParserElement.transform_string`:: - - hex_ints = Word(hexnums)[1, ...].set_parse_action(token_map(int, 16)) - hex_ints.run_tests(''' - 00 11 22 aa FF 0a 0d 1a - ''') - - upperword = Word(alphas).set_parse_action(token_map(str.upper)) - upperword[1, ...].run_tests(''' - my kingdom for a horse - ''') - - wd = Word(alphas).set_parse_action(token_map(str.title)) - wd[1, ...].set_parse_action(' '.join).run_tests(''' - now is the winter of our discontent made glorious summer by this sun of york - ''') - - prints:: - - 00 11 22 aa FF 0a 0d 1a - [0, 17, 34, 170, 255, 10, 13, 26] - - my kingdom for a horse - ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] - - now is the winter of our discontent made glorious summer by this sun of york - ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] - """ - - def pa(s, l, t): - return [func(tokn, *args) for tokn in t] - - func_name = getattr(func, "__name__", getattr(func, "__class__").__name__) - pa.__name__ = func_name - - return pa - - -def autoname_elements() -> None: - """ - Utility to simplify mass-naming of parser elements, for - generating railroad diagram with named subdiagrams. - """ - for name, var in sys._getframe().f_back.f_locals.items(): - if isinstance(var, ParserElement) and not var.customName: - var.set_name(name) - - -dbl_quoted_string = Combine( - Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' -).set_name("string enclosed in double quotes") - -sgl_quoted_string = Combine( - Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" -).set_name("string enclosed in single quotes") - -quoted_string = Combine( - Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' - | Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" -).set_name("quotedString using single or double quotes") - -unicode_string = Combine("u" + quoted_string.copy()).set_name("unicode string literal") - - -alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") -punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") - -# build list of built-in expressions, for future reference if a global default value -# gets updated -_builtin_exprs: List[ParserElement] = [ - v for v in vars().values() if isinstance(v, ParserElement) -] - -# backward compatibility names -tokenMap = token_map -conditionAsParseAction = condition_as_parse_action -nullDebugAction = null_debug_action -sglQuotedString = sgl_quoted_string -dblQuotedString = dbl_quoted_string -quotedString = quoted_string -unicodeString = unicode_string -lineStart = line_start -lineEnd = line_end -stringStart = string_start -stringEnd = string_end -traceParseAction = trace_parse_action diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py deleted file mode 100755 index 8986447..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py +++ /dev/null @@ -1,642 +0,0 @@ -import railroad -import pyparsing -import typing -from typing import ( - List, - NamedTuple, - Generic, - TypeVar, - Dict, - Callable, - Set, - Iterable, -) -from jinja2 import Template -from io import StringIO -import inspect - - -jinja2_template_source = """\ - - - - {% if not head %} - - {% else %} - {{ head | safe }} - {% endif %} - - -{{ body | safe }} -{% for diagram in diagrams %} -
-

{{ diagram.title }}

-
{{ diagram.text }}
-
- {{ diagram.svg }} -
-
-{% endfor %} - - -""" - -template = Template(jinja2_template_source) - -# Note: ideally this would be a dataclass, but we're supporting Python 3.5+ so we can't do this yet -NamedDiagram = NamedTuple( - "NamedDiagram", - [("name", str), ("diagram", typing.Optional[railroad.DiagramItem]), ("index", int)], -) -""" -A simple structure for associating a name with a railroad diagram -""" - -T = TypeVar("T") - - -class EachItem(railroad.Group): - """ - Custom railroad item to compose a: - - Group containing a - - OneOrMore containing a - - Choice of the elements in the Each - with the group label indicating that all must be matched - """ - - all_label = "[ALL]" - - def __init__(self, *items): - choice_item = railroad.Choice(len(items) - 1, *items) - one_or_more_item = railroad.OneOrMore(item=choice_item) - super().__init__(one_or_more_item, label=self.all_label) - - -class AnnotatedItem(railroad.Group): - """ - Simple subclass of Group that creates an annotation label - """ - - def __init__(self, label: str, item): - super().__init__(item=item, label="[{}]".format(label) if label else label) - - -class EditablePartial(Generic[T]): - """ - Acts like a functools.partial, but can be edited. In other words, it represents a type that hasn't yet been - constructed. - """ - - # We need this here because the railroad constructors actually transform the data, so can't be called until the - # entire tree is assembled - - def __init__(self, func: Callable[..., T], args: list, kwargs: dict): - self.func = func - self.args = args - self.kwargs = kwargs - - @classmethod - def from_call(cls, func: Callable[..., T], *args, **kwargs) -> "EditablePartial[T]": - """ - If you call this function in the same way that you would call the constructor, it will store the arguments - as you expect. For example EditablePartial.from_call(Fraction, 1, 3)() == Fraction(1, 3) - """ - return EditablePartial(func=func, args=list(args), kwargs=kwargs) - - @property - def name(self): - return self.kwargs["name"] - - def __call__(self) -> T: - """ - Evaluate the partial and return the result - """ - args = self.args.copy() - kwargs = self.kwargs.copy() - - # This is a helpful hack to allow you to specify varargs parameters (e.g. *args) as keyword args (e.g. - # args=['list', 'of', 'things']) - arg_spec = inspect.getfullargspec(self.func) - if arg_spec.varargs in self.kwargs: - args += kwargs.pop(arg_spec.varargs) - - return self.func(*args, **kwargs) - - -def railroad_to_html(diagrams: List[NamedDiagram], **kwargs) -> str: - """ - Given a list of NamedDiagram, produce a single HTML string that visualises those diagrams - :params kwargs: kwargs to be passed in to the template - """ - data = [] - for diagram in diagrams: - if diagram.diagram is None: - continue - io = StringIO() - diagram.diagram.writeSvg(io.write) - title = diagram.name - if diagram.index == 0: - title += " (root)" - data.append({"title": title, "text": "", "svg": io.getvalue()}) - - return template.render(diagrams=data, **kwargs) - - -def resolve_partial(partial: "EditablePartial[T]") -> T: - """ - Recursively resolves a collection of Partials into whatever type they are - """ - if isinstance(partial, EditablePartial): - partial.args = resolve_partial(partial.args) - partial.kwargs = resolve_partial(partial.kwargs) - return partial() - elif isinstance(partial, list): - return [resolve_partial(x) for x in partial] - elif isinstance(partial, dict): - return {key: resolve_partial(x) for key, x in partial.items()} - else: - return partial - - -def to_railroad( - element: pyparsing.ParserElement, - diagram_kwargs: typing.Optional[dict] = None, - vertical: int = 3, - show_results_names: bool = False, - show_groups: bool = False, -) -> List[NamedDiagram]: - """ - Convert a pyparsing element tree into a list of diagrams. This is the recommended entrypoint to diagram - creation if you want to access the Railroad tree before it is converted to HTML - :param element: base element of the parser being diagrammed - :param diagram_kwargs: kwargs to pass to the Diagram() constructor - :param vertical: (optional) - int - limit at which number of alternatives should be - shown vertically instead of horizontally - :param show_results_names - bool to indicate whether results name annotations should be - included in the diagram - :param show_groups - bool to indicate whether groups should be highlighted with an unlabeled - surrounding box - """ - # Convert the whole tree underneath the root - lookup = ConverterState(diagram_kwargs=diagram_kwargs or {}) - _to_diagram_element( - element, - lookup=lookup, - parent=None, - vertical=vertical, - show_results_names=show_results_names, - show_groups=show_groups, - ) - - root_id = id(element) - # Convert the root if it hasn't been already - if root_id in lookup: - if not element.customName: - lookup[root_id].name = "" - lookup[root_id].mark_for_extraction(root_id, lookup, force=True) - - # Now that we're finished, we can convert from intermediate structures into Railroad elements - diags = list(lookup.diagrams.values()) - if len(diags) > 1: - # collapse out duplicate diags with the same name - seen = set() - deduped_diags = [] - for d in diags: - # don't extract SkipTo elements, they are uninformative as subdiagrams - if d.name == "...": - continue - if d.name is not None and d.name not in seen: - seen.add(d.name) - deduped_diags.append(d) - resolved = [resolve_partial(partial) for partial in deduped_diags] - else: - # special case - if just one diagram, always display it, even if - # it has no name - resolved = [resolve_partial(partial) for partial in diags] - return sorted(resolved, key=lambda diag: diag.index) - - -def _should_vertical( - specification: int, exprs: Iterable[pyparsing.ParserElement] -) -> bool: - """ - Returns true if we should return a vertical list of elements - """ - if specification is None: - return False - else: - return len(_visible_exprs(exprs)) >= specification - - -class ElementState: - """ - State recorded for an individual pyparsing Element - """ - - # Note: this should be a dataclass, but we have to support Python 3.5 - def __init__( - self, - element: pyparsing.ParserElement, - converted: EditablePartial, - parent: EditablePartial, - number: int, - name: str = None, - parent_index: typing.Optional[int] = None, - ): - #: The pyparsing element that this represents - self.element: pyparsing.ParserElement = element - #: The name of the element - self.name: typing.Optional[str] = name - #: The output Railroad element in an unconverted state - self.converted: EditablePartial = converted - #: The parent Railroad element, which we store so that we can extract this if it's duplicated - self.parent: EditablePartial = parent - #: The order in which we found this element, used for sorting diagrams if this is extracted into a diagram - self.number: int = number - #: The index of this inside its parent - self.parent_index: typing.Optional[int] = parent_index - #: If true, we should extract this out into a subdiagram - self.extract: bool = False - #: If true, all of this element's children have been filled out - self.complete: bool = False - - def mark_for_extraction( - self, el_id: int, state: "ConverterState", name: str = None, force: bool = False - ): - """ - Called when this instance has been seen twice, and thus should eventually be extracted into a sub-diagram - :param el_id: id of the element - :param state: element/diagram state tracker - :param name: name to use for this element's text - :param force: If true, force extraction now, regardless of the state of this. Only useful for extracting the - root element when we know we're finished - """ - self.extract = True - - # Set the name - if not self.name: - if name: - # Allow forcing a custom name - self.name = name - elif self.element.customName: - self.name = self.element.customName - else: - self.name = "" - - # Just because this is marked for extraction doesn't mean we can do it yet. We may have to wait for children - # to be added - # Also, if this is just a string literal etc, don't bother extracting it - if force or (self.complete and _worth_extracting(self.element)): - state.extract_into_diagram(el_id) - - -class ConverterState: - """ - Stores some state that persists between recursions into the element tree - """ - - def __init__(self, diagram_kwargs: typing.Optional[dict] = None): - #: A dictionary mapping ParserElements to state relating to them - self._element_diagram_states: Dict[int, ElementState] = {} - #: A dictionary mapping ParserElement IDs to subdiagrams generated from them - self.diagrams: Dict[int, EditablePartial[NamedDiagram]] = {} - #: The index of the next unnamed element - self.unnamed_index: int = 1 - #: The index of the next element. This is used for sorting - self.index: int = 0 - #: Shared kwargs that are used to customize the construction of diagrams - self.diagram_kwargs: dict = diagram_kwargs or {} - self.extracted_diagram_names: Set[str] = set() - - def __setitem__(self, key: int, value: ElementState): - self._element_diagram_states[key] = value - - def __getitem__(self, key: int) -> ElementState: - return self._element_diagram_states[key] - - def __delitem__(self, key: int): - del self._element_diagram_states[key] - - def __contains__(self, key: int): - return key in self._element_diagram_states - - def generate_unnamed(self) -> int: - """ - Generate a number used in the name of an otherwise unnamed diagram - """ - self.unnamed_index += 1 - return self.unnamed_index - - def generate_index(self) -> int: - """ - Generate a number used to index a diagram - """ - self.index += 1 - return self.index - - def extract_into_diagram(self, el_id: int): - """ - Used when we encounter the same token twice in the same tree. When this - happens, we replace all instances of that token with a terminal, and - create a new subdiagram for the token - """ - position = self[el_id] - - # Replace the original definition of this element with a regular block - if position.parent: - ret = EditablePartial.from_call(railroad.NonTerminal, text=position.name) - if "item" in position.parent.kwargs: - position.parent.kwargs["item"] = ret - elif "items" in position.parent.kwargs: - position.parent.kwargs["items"][position.parent_index] = ret - - # If the element we're extracting is a group, skip to its content but keep the title - if position.converted.func == railroad.Group: - content = position.converted.kwargs["item"] - else: - content = position.converted - - self.diagrams[el_id] = EditablePartial.from_call( - NamedDiagram, - name=position.name, - diagram=EditablePartial.from_call( - railroad.Diagram, content, **self.diagram_kwargs - ), - index=position.number, - ) - - del self[el_id] - - -def _worth_extracting(element: pyparsing.ParserElement) -> bool: - """ - Returns true if this element is worth having its own sub-diagram. Simply, if any of its children - themselves have children, then its complex enough to extract - """ - children = element.recurse() - return any(child.recurse() for child in children) - - -def _apply_diagram_item_enhancements(fn): - """ - decorator to ensure enhancements to a diagram item (such as results name annotations) - get applied on return from _to_diagram_element (we do this since there are several - returns in _to_diagram_element) - """ - - def _inner( - element: pyparsing.ParserElement, - parent: typing.Optional[EditablePartial], - lookup: ConverterState = None, - vertical: int = None, - index: int = 0, - name_hint: str = None, - show_results_names: bool = False, - show_groups: bool = False, - ) -> typing.Optional[EditablePartial]: - - ret = fn( - element, - parent, - lookup, - vertical, - index, - name_hint, - show_results_names, - show_groups, - ) - - # apply annotation for results name, if present - if show_results_names and ret is not None: - element_results_name = element.resultsName - if element_results_name: - # add "*" to indicate if this is a "list all results" name - element_results_name += "" if element.modalResults else "*" - ret = EditablePartial.from_call( - railroad.Group, item=ret, label=element_results_name - ) - - return ret - - return _inner - - -def _visible_exprs(exprs: Iterable[pyparsing.ParserElement]): - non_diagramming_exprs = ( - pyparsing.ParseElementEnhance, - pyparsing.PositionToken, - pyparsing.And._ErrorStop, - ) - return [ - e - for e in exprs - if not (e.customName or e.resultsName or isinstance(e, non_diagramming_exprs)) - ] - - -@_apply_diagram_item_enhancements -def _to_diagram_element( - element: pyparsing.ParserElement, - parent: typing.Optional[EditablePartial], - lookup: ConverterState = None, - vertical: int = None, - index: int = 0, - name_hint: str = None, - show_results_names: bool = False, - show_groups: bool = False, -) -> typing.Optional[EditablePartial]: - """ - Recursively converts a PyParsing Element to a railroad Element - :param lookup: The shared converter state that keeps track of useful things - :param index: The index of this element within the parent - :param parent: The parent of this element in the output tree - :param vertical: Controls at what point we make a list of elements vertical. If this is an integer (the default), - it sets the threshold of the number of items before we go vertical. If True, always go vertical, if False, never - do so - :param name_hint: If provided, this will override the generated name - :param show_results_names: bool flag indicating whether to add annotations for results names - :returns: The converted version of the input element, but as a Partial that hasn't yet been constructed - :param show_groups: bool flag indicating whether to show groups using bounding box - """ - exprs = element.recurse() - name = name_hint or element.customName or element.__class__.__name__ - - # Python's id() is used to provide a unique identifier for elements - el_id = id(element) - - element_results_name = element.resultsName - - # Here we basically bypass processing certain wrapper elements if they contribute nothing to the diagram - if not element.customName: - if isinstance( - element, - ( - # pyparsing.TokenConverter, - # pyparsing.Forward, - pyparsing.Located, - ), - ): - # However, if this element has a useful custom name, and its child does not, we can pass it on to the child - if exprs: - if not exprs[0].customName: - propagated_name = name - else: - propagated_name = None - - return _to_diagram_element( - element.expr, - parent=parent, - lookup=lookup, - vertical=vertical, - index=index, - name_hint=propagated_name, - show_results_names=show_results_names, - show_groups=show_groups, - ) - - # If the element isn't worth extracting, we always treat it as the first time we say it - if _worth_extracting(element): - if el_id in lookup: - # If we've seen this element exactly once before, we are only just now finding out that it's a duplicate, - # so we have to extract it into a new diagram. - looked_up = lookup[el_id] - looked_up.mark_for_extraction(el_id, lookup, name=name_hint) - ret = EditablePartial.from_call(railroad.NonTerminal, text=looked_up.name) - return ret - - elif el_id in lookup.diagrams: - # If we have seen the element at least twice before, and have already extracted it into a subdiagram, we - # just put in a marker element that refers to the sub-diagram - ret = EditablePartial.from_call( - railroad.NonTerminal, text=lookup.diagrams[el_id].kwargs["name"] - ) - return ret - - # Recursively convert child elements - # Here we find the most relevant Railroad element for matching pyparsing Element - # We use ``items=[]`` here to hold the place for where the child elements will go once created - if isinstance(element, pyparsing.And): - # detect And's created with ``expr*N`` notation - for these use a OneOrMore with a repeat - # (all will have the same name, and resultsName) - if not exprs: - return None - if len(set((e.name, e.resultsName) for e in exprs)) == 1: - ret = EditablePartial.from_call( - railroad.OneOrMore, item="", repeat=str(len(exprs)) - ) - elif _should_vertical(vertical, exprs): - ret = EditablePartial.from_call(railroad.Stack, items=[]) - else: - ret = EditablePartial.from_call(railroad.Sequence, items=[]) - elif isinstance(element, (pyparsing.Or, pyparsing.MatchFirst)): - if not exprs: - return None - if _should_vertical(vertical, exprs): - ret = EditablePartial.from_call(railroad.Choice, 0, items=[]) - else: - ret = EditablePartial.from_call(railroad.HorizontalChoice, items=[]) - elif isinstance(element, pyparsing.Each): - if not exprs: - return None - ret = EditablePartial.from_call(EachItem, items=[]) - elif isinstance(element, pyparsing.NotAny): - ret = EditablePartial.from_call(AnnotatedItem, label="NOT", item="") - elif isinstance(element, pyparsing.FollowedBy): - ret = EditablePartial.from_call(AnnotatedItem, label="LOOKAHEAD", item="") - elif isinstance(element, pyparsing.PrecededBy): - ret = EditablePartial.from_call(AnnotatedItem, label="LOOKBEHIND", item="") - elif isinstance(element, pyparsing.Group): - if show_groups: - ret = EditablePartial.from_call(AnnotatedItem, label="", item="") - else: - ret = EditablePartial.from_call(railroad.Group, label="", item="") - elif isinstance(element, pyparsing.TokenConverter): - ret = EditablePartial.from_call( - AnnotatedItem, label=type(element).__name__.lower(), item="" - ) - elif isinstance(element, pyparsing.Opt): - ret = EditablePartial.from_call(railroad.Optional, item="") - elif isinstance(element, pyparsing.OneOrMore): - ret = EditablePartial.from_call(railroad.OneOrMore, item="") - elif isinstance(element, pyparsing.ZeroOrMore): - ret = EditablePartial.from_call(railroad.ZeroOrMore, item="") - elif isinstance(element, pyparsing.Group): - ret = EditablePartial.from_call( - railroad.Group, item=None, label=element_results_name - ) - elif isinstance(element, pyparsing.Empty) and not element.customName: - # Skip unnamed "Empty" elements - ret = None - elif len(exprs) > 1: - ret = EditablePartial.from_call(railroad.Sequence, items=[]) - elif len(exprs) > 0 and not element_results_name: - ret = EditablePartial.from_call(railroad.Group, item="", label=name) - else: - terminal = EditablePartial.from_call(railroad.Terminal, element.defaultName) - ret = terminal - - if ret is None: - return - - # Indicate this element's position in the tree so we can extract it if necessary - lookup[el_id] = ElementState( - element=element, - converted=ret, - parent=parent, - parent_index=index, - number=lookup.generate_index(), - ) - if element.customName: - lookup[el_id].mark_for_extraction(el_id, lookup, element.customName) - - i = 0 - for expr in exprs: - # Add a placeholder index in case we have to extract the child before we even add it to the parent - if "items" in ret.kwargs: - ret.kwargs["items"].insert(i, None) - - item = _to_diagram_element( - expr, - parent=ret, - lookup=lookup, - vertical=vertical, - index=i, - show_results_names=show_results_names, - show_groups=show_groups, - ) - - # Some elements don't need to be shown in the diagram - if item is not None: - if "item" in ret.kwargs: - ret.kwargs["item"] = item - elif "items" in ret.kwargs: - # If we've already extracted the child, don't touch this index, since it's occupied by a nonterminal - ret.kwargs["items"][i] = item - i += 1 - elif "items" in ret.kwargs: - # If we're supposed to skip this element, remove it from the parent - del ret.kwargs["items"][i] - - # If all this items children are none, skip this item - if ret and ( - ("items" in ret.kwargs and len(ret.kwargs["items"]) == 0) - or ("item" in ret.kwargs and ret.kwargs["item"] is None) - ): - ret = EditablePartial.from_call(railroad.Terminal, name) - - # Mark this element as "complete", ie it has all of its children - if el_id in lookup: - lookup[el_id].complete = True - - if el_id in lookup and lookup[el_id].extract and lookup[el_id].complete: - lookup.extract_into_diagram(el_id) - if ret is not None: - ret = EditablePartial.from_call( - railroad.NonTerminal, text=lookup.diagrams[el_id].kwargs["name"] - ) - - return ret diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index bdf3015a4a5cbc8954d850d5f0380c44bc64ac52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28003 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/exceptions.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/exceptions.py deleted file mode 100755 index a38447b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/exceptions.py +++ /dev/null @@ -1,267 +0,0 @@ -# exceptions.py - -import re -import sys -import typing - -from .util import col, line, lineno, _collapse_string_to_ranges -from .unicode import pyparsing_unicode as ppu - - -class ExceptionWordUnicode(ppu.Latin1, ppu.LatinA, ppu.LatinB, ppu.Greek, ppu.Cyrillic): - pass - - -_extract_alphanums = _collapse_string_to_ranges(ExceptionWordUnicode.alphanums) -_exception_word_extractor = re.compile("([" + _extract_alphanums + "]{1,16})|.") - - -class ParseBaseException(Exception): - """base exception class for all parsing runtime exceptions""" - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( - self, - pstr: str, - loc: int = 0, - msg: typing.Optional[str] = None, - elem=None, - ): - self.loc = loc - if msg is None: - self.msg = pstr - self.pstr = "" - else: - self.msg = msg - self.pstr = pstr - self.parser_element = self.parserElement = elem - self.args = (pstr, loc, msg) - - @staticmethod - def explain_exception(exc, depth=16): - """ - Method to take an exception and translate the Python internal traceback into a list - of the pyparsing expressions that caused the exception to be raised. - - Parameters: - - - exc - exception raised during parsing (need not be a ParseException, in support - of Python exceptions that might be raised in a parse action) - - depth (default=16) - number of levels back in the stack trace to list expression - and function names; if None, the full stack trace names will be listed; if 0, only - the failing input line, marker, and exception string will be shown - - Returns a multi-line string listing the ParserElements and/or function names in the - exception's stack trace. - """ - import inspect - from .core import ParserElement - - if depth is None: - depth = sys.getrecursionlimit() - ret = [] - if isinstance(exc, ParseBaseException): - ret.append(exc.line) - ret.append(" " * (exc.column - 1) + "^") - ret.append("{}: {}".format(type(exc).__name__, exc)) - - if depth > 0: - callers = inspect.getinnerframes(exc.__traceback__, context=depth) - seen = set() - for i, ff in enumerate(callers[-depth:]): - frm = ff[0] - - f_self = frm.f_locals.get("self", None) - if isinstance(f_self, ParserElement): - if frm.f_code.co_name not in ("parseImpl", "_parseNoCache"): - continue - if id(f_self) in seen: - continue - seen.add(id(f_self)) - - self_type = type(f_self) - ret.append( - "{}.{} - {}".format( - self_type.__module__, self_type.__name__, f_self - ) - ) - - elif f_self is not None: - self_type = type(f_self) - ret.append("{}.{}".format(self_type.__module__, self_type.__name__)) - - else: - code = frm.f_code - if code.co_name in ("wrapper", ""): - continue - - ret.append("{}".format(code.co_name)) - - depth -= 1 - if not depth: - break - - return "\n".join(ret) - - @classmethod - def _from_exception(cls, pe): - """ - internal factory method to simplify creating one type of ParseException - from another - avoids having __init__ signature conflicts among subclasses - """ - return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) - - @property - def line(self) -> str: - """ - Return the line of text where the exception occurred. - """ - return line(self.loc, self.pstr) - - @property - def lineno(self) -> int: - """ - Return the 1-based line number of text where the exception occurred. - """ - return lineno(self.loc, self.pstr) - - @property - def col(self) -> int: - """ - Return the 1-based column on the line of text where the exception occurred. - """ - return col(self.loc, self.pstr) - - @property - def column(self) -> int: - """ - Return the 1-based column on the line of text where the exception occurred. - """ - return col(self.loc, self.pstr) - - def __str__(self) -> str: - if self.pstr: - if self.loc >= len(self.pstr): - foundstr = ", found end of text" - else: - # pull out next word at error location - found_match = _exception_word_extractor.match(self.pstr, self.loc) - if found_match is not None: - found = found_match.group(0) - else: - found = self.pstr[self.loc : self.loc + 1] - foundstr = (", found %r" % found).replace(r"\\", "\\") - else: - foundstr = "" - return "{}{} (at char {}), (line:{}, col:{})".format( - self.msg, foundstr, self.loc, self.lineno, self.column - ) - - def __repr__(self): - return str(self) - - def mark_input_line(self, marker_string: str = None, *, markerString=">!<") -> str: - """ - Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. - """ - markerString = marker_string if marker_string is not None else markerString - line_str = self.line - line_column = self.column - 1 - if markerString: - line_str = "".join( - (line_str[:line_column], markerString, line_str[line_column:]) - ) - return line_str.strip() - - def explain(self, depth=16) -> str: - """ - Method to translate the Python internal traceback into a list - of the pyparsing expressions that caused the exception to be raised. - - Parameters: - - - depth (default=16) - number of levels back in the stack trace to list expression - and function names; if None, the full stack trace names will be listed; if 0, only - the failing input line, marker, and exception string will be shown - - Returns a multi-line string listing the ParserElements and/or function names in the - exception's stack trace. - - Example:: - - expr = pp.Word(pp.nums) * 3 - try: - expr.parse_string("123 456 A789") - except pp.ParseException as pe: - print(pe.explain(depth=0)) - - prints:: - - 123 456 A789 - ^ - ParseException: Expected W:(0-9), found 'A' (at char 8), (line:1, col:9) - - Note: the diagnostic output will include string representations of the expressions - that failed to parse. These representations will be more helpful if you use `set_name` to - give identifiable names to your expressions. Otherwise they will use the default string - forms, which may be cryptic to read. - - Note: pyparsing's default truncation of exception tracebacks may also truncate the - stack of expressions that are displayed in the ``explain`` output. To get the full listing - of parser expressions, you may have to set ``ParserElement.verbose_stacktrace = True`` - """ - return self.explain_exception(self, depth) - - markInputline = mark_input_line - - -class ParseException(ParseBaseException): - """ - Exception thrown when a parse expression doesn't match the input string - - Example:: - - try: - Word(nums).set_name("integer").parse_string("ABC") - except ParseException as pe: - print(pe) - print("column: {}".format(pe.column)) - - prints:: - - Expected integer (at char 0), (line:1, col:1) - column: 1 - - """ - - -class ParseFatalException(ParseBaseException): - """ - User-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately - """ - - -class ParseSyntaxException(ParseFatalException): - """ - Just like :class:`ParseFatalException`, but thrown internally - when an :class:`ErrorStop` ('-' operator) indicates - that parsing is to stop immediately because an unbacktrackable - syntax error has been found. - """ - - -class RecursiveGrammarException(Exception): - """ - Exception thrown by :class:`ParserElement.validate` if the - grammar could be left-recursive; parser may need to enable - left recursion using :class:`ParserElement.enable_left_recursion` - """ - - def __init__(self, parseElementList): - self.parseElementTrace = parseElementList - - def __str__(self) -> str: - return "RecursiveGrammarException: {}".format(self.parseElementTrace) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/helpers.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/helpers.py deleted file mode 100755 index 9588b3b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/helpers.py +++ /dev/null @@ -1,1088 +0,0 @@ -# helpers.py -import html.entities -import re -import typing - -from . import __diag__ -from .core import * -from .util import _bslash, _flatten, _escape_regex_range_chars - - -# -# global helpers -# -def delimited_list( - expr: Union[str, ParserElement], - delim: Union[str, ParserElement] = ",", - combine: bool = False, - min: typing.Optional[int] = None, - max: typing.Optional[int] = None, - *, - allow_trailing_delim: bool = False, -) -> ParserElement: - """Helper to define a delimited list of expressions - the delimiter - defaults to ','. By default, the list elements and delimiters can - have intervening whitespace, and comments, but this can be - overridden by passing ``combine=True`` in the constructor. If - ``combine`` is set to ``True``, the matching tokens are - returned as a single token string, with the delimiters included; - otherwise, the matching tokens are returned as a list of tokens, - with the delimiters suppressed. - - If ``allow_trailing_delim`` is set to True, then the list may end with - a delimiter. - - Example:: - - delimited_list(Word(alphas)).parse_string("aa,bb,cc") # -> ['aa', 'bb', 'cc'] - delimited_list(Word(hexnums), delim=':', combine=True).parse_string("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] - """ - if isinstance(expr, str_type): - expr = ParserElement._literalStringClass(expr) - - dlName = "{expr} [{delim} {expr}]...{end}".format( - expr=str(expr.copy().streamline()), - delim=str(delim), - end=" [{}]".format(str(delim)) if allow_trailing_delim else "", - ) - - if not combine: - delim = Suppress(delim) - - if min is not None: - if min < 1: - raise ValueError("min must be greater than 0") - min -= 1 - if max is not None: - if min is not None and max <= min: - raise ValueError("max must be greater than, or equal to min") - max -= 1 - delimited_list_expr = expr + (delim + expr)[min, max] - - if allow_trailing_delim: - delimited_list_expr += Opt(delim) - - if combine: - return Combine(delimited_list_expr).set_name(dlName) - else: - return delimited_list_expr.set_name(dlName) - - -def counted_array( - expr: ParserElement, - int_expr: typing.Optional[ParserElement] = None, - *, - intExpr: typing.Optional[ParserElement] = None, -) -> ParserElement: - """Helper to define a counted list of expressions. - - This helper defines a pattern of the form:: - - integer expr expr expr... - - where the leading integer tells how many expr expressions follow. - The matched tokens returns the array of expr tokens as a list - the - leading count token is suppressed. - - If ``int_expr`` is specified, it should be a pyparsing expression - that produces an integer value. - - Example:: - - counted_array(Word(alphas)).parse_string('2 ab cd ef') # -> ['ab', 'cd'] - - # in this parser, the leading integer value is given in binary, - # '10' indicating that 2 values are in the array - binary_constant = Word('01').set_parse_action(lambda t: int(t[0], 2)) - counted_array(Word(alphas), int_expr=binary_constant).parse_string('10 ab cd ef') # -> ['ab', 'cd'] - - # if other fields must be parsed after the count but before the - # list items, give the fields results names and they will - # be preserved in the returned ParseResults: - count_with_metadata = integer + Word(alphas)("type") - typed_array = counted_array(Word(alphanums), int_expr=count_with_metadata)("items") - result = typed_array.parse_string("3 bool True True False") - print(result.dump()) - - # prints - # ['True', 'True', 'False'] - # - items: ['True', 'True', 'False'] - # - type: 'bool' - """ - intExpr = intExpr or int_expr - array_expr = Forward() - - def count_field_parse_action(s, l, t): - nonlocal array_expr - n = t[0] - array_expr <<= (expr * n) if n else Empty() - # clear list contents, but keep any named results - del t[:] - - if intExpr is None: - intExpr = Word(nums).set_parse_action(lambda t: int(t[0])) - else: - intExpr = intExpr.copy() - intExpr.set_name("arrayLen") - intExpr.add_parse_action(count_field_parse_action, call_during_try=True) - return (intExpr + array_expr).set_name("(len) " + str(expr) + "...") - - -def match_previous_literal(expr: ParserElement) -> ParserElement: - """Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks for - a 'repeat' of a previous expression. For example:: - - first = Word(nums) - second = match_previous_literal(first) - match_expr = first + ":" + second - - will match ``"1:1"``, but not ``"1:2"``. Because this - matches a previous literal, will also match the leading - ``"1:1"`` in ``"1:10"``. If this is not desired, use - :class:`match_previous_expr`. Do *not* use with packrat parsing - enabled. - """ - rep = Forward() - - def copy_token_to_repeater(s, l, t): - if t: - if len(t) == 1: - rep << t[0] - else: - # flatten t tokens - tflat = _flatten(t.as_list()) - rep << And(Literal(tt) for tt in tflat) - else: - rep << Empty() - - expr.add_parse_action(copy_token_to_repeater, callDuringTry=True) - rep.set_name("(prev) " + str(expr)) - return rep - - -def match_previous_expr(expr: ParserElement) -> ParserElement: - """Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks for - a 'repeat' of a previous expression. For example:: - - first = Word(nums) - second = match_previous_expr(first) - match_expr = first + ":" + second - - will match ``"1:1"``, but not ``"1:2"``. Because this - matches by expressions, will *not* match the leading ``"1:1"`` - in ``"1:10"``; the expressions are evaluated first, and then - compared, so ``"1"`` is compared with ``"10"``. Do *not* use - with packrat parsing enabled. - """ - rep = Forward() - e2 = expr.copy() - rep <<= e2 - - def copy_token_to_repeater(s, l, t): - matchTokens = _flatten(t.as_list()) - - def must_match_these_tokens(s, l, t): - theseTokens = _flatten(t.as_list()) - if theseTokens != matchTokens: - raise ParseException( - s, l, "Expected {}, found{}".format(matchTokens, theseTokens) - ) - - rep.set_parse_action(must_match_these_tokens, callDuringTry=True) - - expr.add_parse_action(copy_token_to_repeater, callDuringTry=True) - rep.set_name("(prev) " + str(expr)) - return rep - - -def one_of( - strs: Union[typing.Iterable[str], str], - caseless: bool = False, - use_regex: bool = True, - as_keyword: bool = False, - *, - useRegex: bool = True, - asKeyword: bool = False, -) -> ParserElement: - """Helper to quickly define a set of alternative :class:`Literal` s, - and makes sure to do longest-first testing when there is a conflict, - regardless of the input order, but returns - a :class:`MatchFirst` for best performance. - - Parameters: - - - ``strs`` - a string of space-delimited literals, or a collection of - string literals - - ``caseless`` - treat all literals as caseless - (default= ``False``) - - ``use_regex`` - as an optimization, will - generate a :class:`Regex` object; otherwise, will generate - a :class:`MatchFirst` object (if ``caseless=True`` or ``asKeyword=True``, or if - creating a :class:`Regex` raises an exception) - (default= ``True``) - - ``as_keyword`` - enforce :class:`Keyword`-style matching on the - generated expressions - (default= ``False``) - - ``asKeyword`` and ``useRegex`` are retained for pre-PEP8 compatibility, - but will be removed in a future release - - Example:: - - comp_oper = one_of("< = > <= >= !=") - var = Word(alphas) - number = Word(nums) - term = var | number - comparison_expr = term + comp_oper + term - print(comparison_expr.search_string("B = 12 AA=23 B<=AA AA>12")) - - prints:: - - [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] - """ - asKeyword = asKeyword or as_keyword - useRegex = useRegex and use_regex - - if ( - isinstance(caseless, str_type) - and __diag__.warn_on_multiple_string_args_to_oneof - ): - warnings.warn( - "More than one string argument passed to one_of, pass" - " choices as a list or space-delimited string", - stacklevel=2, - ) - - if caseless: - isequal = lambda a, b: a.upper() == b.upper() - masks = lambda a, b: b.upper().startswith(a.upper()) - parseElementClass = CaselessKeyword if asKeyword else CaselessLiteral - else: - isequal = lambda a, b: a == b - masks = lambda a, b: b.startswith(a) - parseElementClass = Keyword if asKeyword else Literal - - symbols: List[str] = [] - if isinstance(strs, str_type): - symbols = strs.split() - elif isinstance(strs, Iterable): - symbols = list(strs) - else: - raise TypeError("Invalid argument to one_of, expected string or iterable") - if not symbols: - return NoMatch() - - # reorder given symbols to take care to avoid masking longer choices with shorter ones - # (but only if the given symbols are not just single characters) - if any(len(sym) > 1 for sym in symbols): - i = 0 - while i < len(symbols) - 1: - cur = symbols[i] - for j, other in enumerate(symbols[i + 1 :]): - if isequal(other, cur): - del symbols[i + j + 1] - break - elif masks(cur, other): - del symbols[i + j + 1] - symbols.insert(i, other) - break - else: - i += 1 - - if useRegex: - re_flags: int = re.IGNORECASE if caseless else 0 - - try: - if all(len(sym) == 1 for sym in symbols): - # symbols are just single characters, create range regex pattern - patt = "[{}]".format( - "".join(_escape_regex_range_chars(sym) for sym in symbols) - ) - else: - patt = "|".join(re.escape(sym) for sym in symbols) - - # wrap with \b word break markers if defining as keywords - if asKeyword: - patt = r"\b(?:{})\b".format(patt) - - ret = Regex(patt, flags=re_flags).set_name(" | ".join(symbols)) - - if caseless: - # add parse action to return symbols as specified, not in random - # casing as found in input string - symbol_map = {sym.lower(): sym for sym in symbols} - ret.add_parse_action(lambda s, l, t: symbol_map[t[0].lower()]) - - return ret - - except re.error: - warnings.warn( - "Exception creating Regex for one_of, building MatchFirst", stacklevel=2 - ) - - # last resort, just use MatchFirst - return MatchFirst(parseElementClass(sym) for sym in symbols).set_name( - " | ".join(symbols) - ) - - -def dict_of(key: ParserElement, value: ParserElement) -> ParserElement: - """Helper to easily and clearly define a dictionary by specifying - the respective patterns for the key and value. Takes care of - defining the :class:`Dict`, :class:`ZeroOrMore`, and - :class:`Group` tokens in the proper order. The key pattern - can include delimiting markers or punctuation, as long as they are - suppressed, thereby leaving the significant key text. The value - pattern can include named results, so that the :class:`Dict` results - can include named token fields. - - Example:: - - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - print(attr_expr[1, ...].parse_string(text).dump()) - - attr_label = label - attr_value = Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join) - - # similar to Dict, but simpler call format - result = dict_of(attr_label, attr_value).parse_string(text) - print(result.dump()) - print(result['shape']) - print(result.shape) # object attribute access works too - print(result.as_dict()) - - prints:: - - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: 'light blue' - - posn: 'upper left' - - shape: 'SQUARE' - - texture: 'burlap' - SQUARE - SQUARE - {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} - """ - return Dict(OneOrMore(Group(key + value))) - - -def original_text_for( - expr: ParserElement, as_string: bool = True, *, asString: bool = True -) -> ParserElement: - """Helper to return the original, untokenized text for a given - expression. Useful to restore the parsed fields of an HTML start - tag into the raw tag text itself, or to revert separate tokens with - intervening whitespace back to the original matching input text. By - default, returns astring containing the original parsed text. - - If the optional ``as_string`` argument is passed as - ``False``, then the return value is - a :class:`ParseResults` containing any results names that - were originally matched, and a single token containing the original - matched text from the input string. So if the expression passed to - :class:`original_text_for` contains expressions with defined - results names, you must set ``as_string`` to ``False`` if you - want to preserve those results name values. - - The ``asString`` pre-PEP8 argument is retained for compatibility, - but will be removed in a future release. - - Example:: - - src = "this is test bold text normal text " - for tag in ("b", "i"): - opener, closer = make_html_tags(tag) - patt = original_text_for(opener + SkipTo(closer) + closer) - print(patt.search_string(src)[0]) - - prints:: - - [' bold text '] - ['text'] - """ - asString = asString and as_string - - locMarker = Empty().set_parse_action(lambda s, loc, t: loc) - endlocMarker = locMarker.copy() - endlocMarker.callPreparse = False - matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") - if asString: - extractText = lambda s, l, t: s[t._original_start : t._original_end] - else: - - def extractText(s, l, t): - t[:] = [s[t.pop("_original_start") : t.pop("_original_end")]] - - matchExpr.set_parse_action(extractText) - matchExpr.ignoreExprs = expr.ignoreExprs - matchExpr.suppress_warning(Diagnostics.warn_ungrouped_named_tokens_in_collection) - return matchExpr - - -def ungroup(expr: ParserElement) -> ParserElement: - """Helper to undo pyparsing's default grouping of And expressions, - even if all but one are non-empty. - """ - return TokenConverter(expr).add_parse_action(lambda t: t[0]) - - -def locatedExpr(expr: ParserElement) -> ParserElement: - """ - (DEPRECATED - future code should use the Located class) - Helper to decorate a returned token with its starting and ending - locations in the input string. - - This helper adds the following results names: - - - ``locn_start`` - location where matched expression begins - - ``locn_end`` - location where matched expression ends - - ``value`` - the actual parsed results - - Be careful if the input text contains ```` characters, you - may want to call :class:`ParserElement.parseWithTabs` - - Example:: - - wd = Word(alphas) - for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"): - print(match) - - prints:: - - [[0, 'ljsdf', 5]] - [[8, 'lksdjjf', 15]] - [[18, 'lkkjj', 23]] - """ - locator = Empty().set_parse_action(lambda ss, ll, tt: ll) - return Group( - locator("locn_start") - + expr("value") - + locator.copy().leaveWhitespace()("locn_end") - ) - - -def nested_expr( - opener: Union[str, ParserElement] = "(", - closer: Union[str, ParserElement] = ")", - content: typing.Optional[ParserElement] = None, - ignore_expr: ParserElement = quoted_string(), - *, - ignoreExpr: ParserElement = quoted_string(), -) -> ParserElement: - """Helper method for defining nested lists enclosed in opening and - closing delimiters (``"("`` and ``")"`` are the default). - - Parameters: - - ``opener`` - opening character for a nested list - (default= ``"("``); can also be a pyparsing expression - - ``closer`` - closing character for a nested list - (default= ``")"``); can also be a pyparsing expression - - ``content`` - expression for items within the nested lists - (default= ``None``) - - ``ignore_expr`` - expression for ignoring opening and closing delimiters - (default= :class:`quoted_string`) - - ``ignoreExpr`` - this pre-PEP8 argument is retained for compatibility - but will be removed in a future release - - If an expression is not provided for the content argument, the - nested expression will capture all whitespace-delimited content - between delimiters as a list of separate values. - - Use the ``ignore_expr`` argument to define expressions that may - contain opening or closing characters that should not be treated as - opening or closing characters for nesting, such as quoted_string or - a comment expression. Specify multiple expressions using an - :class:`Or` or :class:`MatchFirst`. The default is - :class:`quoted_string`, but if no expressions are to be ignored, then - pass ``None`` for this argument. - - Example:: - - data_type = one_of("void int short long char float double") - decl_data_type = Combine(data_type + Opt(Word('*'))) - ident = Word(alphas+'_', alphanums+'_') - number = pyparsing_common.number - arg = Group(decl_data_type + ident) - LPAR, RPAR = map(Suppress, "()") - - code_body = nested_expr('{', '}', ignore_expr=(quoted_string | c_style_comment)) - - c_function = (decl_data_type("type") - + ident("name") - + LPAR + Opt(delimited_list(arg), [])("args") + RPAR - + code_body("body")) - c_function.ignore(c_style_comment) - - source_code = ''' - int is_odd(int x) { - return (x%2); - } - - int dec_to_hex(char hchar) { - if (hchar >= '0' && hchar <= '9') { - return (ord(hchar)-ord('0')); - } else { - return (10+ord(hchar)-ord('A')); - } - } - ''' - for func in c_function.search_string(source_code): - print("%(name)s (%(type)s) args: %(args)s" % func) - - - prints:: - - is_odd (int) args: [['int', 'x']] - dec_to_hex (int) args: [['char', 'hchar']] - """ - if ignoreExpr != ignore_expr: - ignoreExpr = ignore_expr if ignoreExpr == quoted_string() else ignoreExpr - if opener == closer: - raise ValueError("opening and closing strings cannot be the same") - if content is None: - if isinstance(opener, str_type) and isinstance(closer, str_type): - if len(opener) == 1 and len(closer) == 1: - if ignoreExpr is not None: - content = Combine( - OneOrMore( - ~ignoreExpr - + CharsNotIn( - opener + closer + ParserElement.DEFAULT_WHITE_CHARS, - exact=1, - ) - ) - ).set_parse_action(lambda t: t[0].strip()) - else: - content = empty.copy() + CharsNotIn( - opener + closer + ParserElement.DEFAULT_WHITE_CHARS - ).set_parse_action(lambda t: t[0].strip()) - else: - if ignoreExpr is not None: - content = Combine( - OneOrMore( - ~ignoreExpr - + ~Literal(opener) - + ~Literal(closer) - + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) - ) - ).set_parse_action(lambda t: t[0].strip()) - else: - content = Combine( - OneOrMore( - ~Literal(opener) - + ~Literal(closer) - + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) - ) - ).set_parse_action(lambda t: t[0].strip()) - else: - raise ValueError( - "opening and closing arguments must be strings if no content expression is given" - ) - ret = Forward() - if ignoreExpr is not None: - ret <<= Group( - Suppress(opener) + ZeroOrMore(ignoreExpr | ret | content) + Suppress(closer) - ) - else: - ret <<= Group(Suppress(opener) + ZeroOrMore(ret | content) + Suppress(closer)) - ret.set_name("nested %s%s expression" % (opener, closer)) - return ret - - -def _makeTags(tagStr, xml, suppress_LT=Suppress("<"), suppress_GT=Suppress(">")): - """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr, str_type): - resname = tagStr - tagStr = Keyword(tagStr, caseless=not xml) - else: - resname = tagStr.name - - tagAttrName = Word(alphas, alphanums + "_-:") - if xml: - tagAttrValue = dbl_quoted_string.copy().set_parse_action(remove_quotes) - openTag = ( - suppress_LT - + tagStr("tag") - + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue))) - + Opt("/", default=[False])("empty").set_parse_action( - lambda s, l, t: t[0] == "/" - ) - + suppress_GT - ) - else: - tagAttrValue = quoted_string.copy().set_parse_action(remove_quotes) | Word( - printables, exclude_chars=">" - ) - openTag = ( - suppress_LT - + tagStr("tag") - + Dict( - ZeroOrMore( - Group( - tagAttrName.set_parse_action(lambda t: t[0].lower()) - + Opt(Suppress("=") + tagAttrValue) - ) - ) - ) - + Opt("/", default=[False])("empty").set_parse_action( - lambda s, l, t: t[0] == "/" - ) - + suppress_GT - ) - closeTag = Combine(Literal("", adjacent=False) - - openTag.set_name("<%s>" % resname) - # add start results name in parse action now that ungrouped names are not reported at two levels - openTag.add_parse_action( - lambda t: t.__setitem__( - "start" + "".join(resname.replace(":", " ").title().split()), t.copy() - ) - ) - closeTag = closeTag( - "end" + "".join(resname.replace(":", " ").title().split()) - ).set_name("" % resname) - openTag.tag = resname - closeTag.tag = resname - openTag.tag_body = SkipTo(closeTag()) - return openTag, closeTag - - -def make_html_tags( - tag_str: Union[str, ParserElement] -) -> Tuple[ParserElement, ParserElement]: - """Helper to construct opening and closing tag expressions for HTML, - given a tag name. Matches tags in either upper or lower case, - attributes with namespaces and with quoted or unquoted values. - - Example:: - - text = 'More info at the pyparsing wiki page' - # make_html_tags returns pyparsing expressions for the opening and - # closing tags as a 2-tuple - a, a_end = make_html_tags("A") - link_expr = a + SkipTo(a_end)("link_text") + a_end - - for link in link_expr.search_string(text): - # attributes in the tag (like "href" shown here) are - # also accessible as named results - print(link.link_text, '->', link.href) - - prints:: - - pyparsing -> https://github.com/pyparsing/pyparsing/wiki - """ - return _makeTags(tag_str, False) - - -def make_xml_tags( - tag_str: Union[str, ParserElement] -) -> Tuple[ParserElement, ParserElement]: - """Helper to construct opening and closing tag expressions for XML, - given a tag name. Matches tags only in the given upper/lower case. - - Example: similar to :class:`make_html_tags` - """ - return _makeTags(tag_str, True) - - -any_open_tag: ParserElement -any_close_tag: ParserElement -any_open_tag, any_close_tag = make_html_tags( - Word(alphas, alphanums + "_:").set_name("any tag") -) - -_htmlEntityMap = {k.rstrip(";"): v for k, v in html.entities.html5.items()} -common_html_entity = Regex("&(?P" + "|".join(_htmlEntityMap) + ");").set_name( - "common HTML entity" -) - - -def replace_html_entity(t): - """Helper parser action to replace common HTML entities with their special characters""" - return _htmlEntityMap.get(t.entity) - - -class OpAssoc(Enum): - LEFT = 1 - RIGHT = 2 - - -InfixNotationOperatorArgType = Union[ - ParserElement, str, Tuple[Union[ParserElement, str], Union[ParserElement, str]] -] -InfixNotationOperatorSpec = Union[ - Tuple[ - InfixNotationOperatorArgType, - int, - OpAssoc, - typing.Optional[ParseAction], - ], - Tuple[ - InfixNotationOperatorArgType, - int, - OpAssoc, - ], -] - - -def infix_notation( - base_expr: ParserElement, - op_list: List[InfixNotationOperatorSpec], - lpar: Union[str, ParserElement] = Suppress("("), - rpar: Union[str, ParserElement] = Suppress(")"), -) -> ParserElement: - """Helper method for constructing grammars of expressions made up of - operators working in a precedence hierarchy. Operators may be unary - or binary, left- or right-associative. Parse actions can also be - attached to operator expressions. The generated parser will also - recognize the use of parentheses to override operator precedences - (see example below). - - Note: if you define a deep operator list, you may see performance - issues when using infix_notation. See - :class:`ParserElement.enable_packrat` for a mechanism to potentially - improve your parser performance. - - Parameters: - - ``base_expr`` - expression representing the most basic operand to - be used in the expression - - ``op_list`` - list of tuples, one for each operator precedence level - in the expression grammar; each tuple is of the form ``(op_expr, - num_operands, right_left_assoc, (optional)parse_action)``, where: - - - ``op_expr`` is the pyparsing expression for the operator; may also - be a string, which will be converted to a Literal; if ``num_operands`` - is 3, ``op_expr`` is a tuple of two expressions, for the two - operators separating the 3 terms - - ``num_operands`` is the number of terms for this operator (must be 1, - 2, or 3) - - ``right_left_assoc`` is the indicator whether the operator is right - or left associative, using the pyparsing-defined constants - ``OpAssoc.RIGHT`` and ``OpAssoc.LEFT``. - - ``parse_action`` is the parse action to be associated with - expressions matching this operator expression (the parse action - tuple member may be omitted); if the parse action is passed - a tuple or list of functions, this is equivalent to calling - ``set_parse_action(*fn)`` - (:class:`ParserElement.set_parse_action`) - - ``lpar`` - expression for matching left-parentheses; if passed as a - str, then will be parsed as Suppress(lpar). If lpar is passed as - an expression (such as ``Literal('(')``), then it will be kept in - the parsed results, and grouped with them. (default= ``Suppress('(')``) - - ``rpar`` - expression for matching right-parentheses; if passed as a - str, then will be parsed as Suppress(rpar). If rpar is passed as - an expression (such as ``Literal(')')``), then it will be kept in - the parsed results, and grouped with them. (default= ``Suppress(')')``) - - Example:: - - # simple example of four-function arithmetic with ints and - # variable names - integer = pyparsing_common.signed_integer - varname = pyparsing_common.identifier - - arith_expr = infix_notation(integer | varname, - [ - ('-', 1, OpAssoc.RIGHT), - (one_of('* /'), 2, OpAssoc.LEFT), - (one_of('+ -'), 2, OpAssoc.LEFT), - ]) - - arith_expr.run_tests(''' - 5+3*6 - (5+3)*6 - -2--11 - ''', full_dump=False) - - prints:: - - 5+3*6 - [[5, '+', [3, '*', 6]]] - - (5+3)*6 - [[[5, '+', 3], '*', 6]] - - -2--11 - [[['-', 2], '-', ['-', 11]]] - """ - # captive version of FollowedBy that does not do parse actions or capture results names - class _FB(FollowedBy): - def parseImpl(self, instring, loc, doActions=True): - self.expr.try_parse(instring, loc) - return loc, [] - - _FB.__name__ = "FollowedBy>" - - ret = Forward() - if isinstance(lpar, str): - lpar = Suppress(lpar) - if isinstance(rpar, str): - rpar = Suppress(rpar) - - # if lpar and rpar are not suppressed, wrap in group - if not (isinstance(rpar, Suppress) and isinstance(rpar, Suppress)): - lastExpr = base_expr | Group(lpar + ret + rpar) - else: - lastExpr = base_expr | (lpar + ret + rpar) - - for i, operDef in enumerate(op_list): - opExpr, arity, rightLeftAssoc, pa = (operDef + (None,))[:4] - if isinstance(opExpr, str_type): - opExpr = ParserElement._literalStringClass(opExpr) - if arity == 3: - if not isinstance(opExpr, (tuple, list)) or len(opExpr) != 2: - raise ValueError( - "if numterms=3, opExpr must be a tuple or list of two expressions" - ) - opExpr1, opExpr2 = opExpr - term_name = "{}{} term".format(opExpr1, opExpr2) - else: - term_name = "{} term".format(opExpr) - - if not 1 <= arity <= 3: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - - if rightLeftAssoc not in (OpAssoc.LEFT, OpAssoc.RIGHT): - raise ValueError("operator must indicate right or left associativity") - - thisExpr: Forward = Forward().set_name(term_name) - if rightLeftAssoc is OpAssoc.LEFT: - if arity == 1: - matchExpr = _FB(lastExpr + opExpr) + Group(lastExpr + opExpr[1, ...]) - elif arity == 2: - if opExpr is not None: - matchExpr = _FB(lastExpr + opExpr + lastExpr) + Group( - lastExpr + (opExpr + lastExpr)[1, ...] - ) - else: - matchExpr = _FB(lastExpr + lastExpr) + Group(lastExpr[2, ...]) - elif arity == 3: - matchExpr = _FB( - lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr - ) + Group(lastExpr + OneOrMore(opExpr1 + lastExpr + opExpr2 + lastExpr)) - elif rightLeftAssoc is OpAssoc.RIGHT: - if arity == 1: - # try to avoid LR with this extra test - if not isinstance(opExpr, Opt): - opExpr = Opt(opExpr) - matchExpr = _FB(opExpr.expr + thisExpr) + Group(opExpr + thisExpr) - elif arity == 2: - if opExpr is not None: - matchExpr = _FB(lastExpr + opExpr + thisExpr) + Group( - lastExpr + (opExpr + thisExpr)[1, ...] - ) - else: - matchExpr = _FB(lastExpr + thisExpr) + Group( - lastExpr + thisExpr[1, ...] - ) - elif arity == 3: - matchExpr = _FB( - lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr - ) + Group(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) - if pa: - if isinstance(pa, (tuple, list)): - matchExpr.set_parse_action(*pa) - else: - matchExpr.set_parse_action(pa) - thisExpr <<= (matchExpr | lastExpr).setName(term_name) - lastExpr = thisExpr - ret <<= lastExpr - return ret - - -def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]): - """ - (DEPRECATED - use IndentedBlock class instead) - Helper method for defining space-delimited indentation blocks, - such as those used to define block statements in Python source code. - - Parameters: - - - ``blockStatementExpr`` - expression defining syntax of statement that - is repeated within the indented block - - ``indentStack`` - list created by caller to manage indentation stack - (multiple ``statementWithIndentedBlock`` expressions within a single - grammar should share a common ``indentStack``) - - ``indent`` - boolean indicating whether block must be indented beyond - the current level; set to ``False`` for block of left-most statements - (default= ``True``) - - A valid block must contain at least one ``blockStatement``. - - (Note that indentedBlock uses internal parse actions which make it - incompatible with packrat parsing.) - - Example:: - - data = ''' - def A(z): - A1 - B = 100 - G = A2 - A2 - A3 - B - def BB(a,b,c): - BB1 - def BBA(): - bba1 - bba2 - bba3 - C - D - def spam(x,y): - def eggs(z): - pass - ''' - - - indentStack = [1] - stmt = Forward() - - identifier = Word(alphas, alphanums) - funcDecl = ("def" + identifier + Group("(" + Opt(delimitedList(identifier)) + ")") + ":") - func_body = indentedBlock(stmt, indentStack) - funcDef = Group(funcDecl + func_body) - - rvalue = Forward() - funcCall = Group(identifier + "(" + Opt(delimitedList(rvalue)) + ")") - rvalue << (funcCall | identifier | Word(nums)) - assignment = Group(identifier + "=" + rvalue) - stmt << (funcDef | assignment | identifier) - - module_body = stmt[1, ...] - - parseTree = module_body.parseString(data) - parseTree.pprint() - - prints:: - - [['def', - 'A', - ['(', 'z', ')'], - ':', - [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], - 'B', - ['def', - 'BB', - ['(', 'a', 'b', 'c', ')'], - ':', - [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], - 'C', - 'D', - ['def', - 'spam', - ['(', 'x', 'y', ')'], - ':', - [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] - """ - backup_stacks.append(indentStack[:]) - - def reset_stack(): - indentStack[:] = backup_stacks[-1] - - def checkPeerIndent(s, l, t): - if l >= len(s): - return - curCol = col(l, s) - if curCol != indentStack[-1]: - if curCol > indentStack[-1]: - raise ParseException(s, l, "illegal nesting") - raise ParseException(s, l, "not a peer entry") - - def checkSubIndent(s, l, t): - curCol = col(l, s) - if curCol > indentStack[-1]: - indentStack.append(curCol) - else: - raise ParseException(s, l, "not a subentry") - - def checkUnindent(s, l, t): - if l >= len(s): - return - curCol = col(l, s) - if not (indentStack and curCol in indentStack): - raise ParseException(s, l, "not an unindent") - if curCol < indentStack[-1]: - indentStack.pop() - - NL = OneOrMore(LineEnd().set_whitespace_chars("\t ").suppress()) - INDENT = (Empty() + Empty().set_parse_action(checkSubIndent)).set_name("INDENT") - PEER = Empty().set_parse_action(checkPeerIndent).set_name("") - UNDENT = Empty().set_parse_action(checkUnindent).set_name("UNINDENT") - if indent: - smExpr = Group( - Opt(NL) - + INDENT - + OneOrMore(PEER + Group(blockStatementExpr) + Opt(NL)) - + UNDENT - ) - else: - smExpr = Group( - Opt(NL) - + OneOrMore(PEER + Group(blockStatementExpr) + Opt(NL)) - + Opt(UNDENT) - ) - - # add a parse action to remove backup_stack from list of backups - smExpr.add_parse_action( - lambda: backup_stacks.pop(-1) and None if backup_stacks else None - ) - smExpr.set_fail_action(lambda a, b, c, d: reset_stack()) - blockStatementExpr.ignore(_bslash + LineEnd()) - return smExpr.set_name("indented block") - - -# it's easy to get these comment structures wrong - they're very common, so may as well make them available -c_style_comment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + "*/").set_name( - "C style comment" -) -"Comment of the form ``/* ... */``" - -html_comment = Regex(r"").set_name("HTML comment") -"Comment of the form ````" - -rest_of_line = Regex(r".*").leave_whitespace().set_name("rest of line") -dbl_slash_comment = Regex(r"//(?:\\\n|[^\n])*").set_name("// comment") -"Comment of the form ``// ... (to end of line)``" - -cpp_style_comment = Combine( - Regex(r"/\*(?:[^*]|\*(?!/))*") + "*/" | dbl_slash_comment -).set_name("C++ style comment") -"Comment of either form :class:`c_style_comment` or :class:`dbl_slash_comment`" - -java_style_comment = cpp_style_comment -"Same as :class:`cpp_style_comment`" - -python_style_comment = Regex(r"#.*").set_name("Python style comment") -"Comment of the form ``# ... (to end of line)``" - - -# build list of built-in expressions, for future reference if a global default value -# gets updated -_builtin_exprs: List[ParserElement] = [ - v for v in vars().values() if isinstance(v, ParserElement) -] - - -# pre-PEP8 compatible names -delimitedList = delimited_list -countedArray = counted_array -matchPreviousLiteral = match_previous_literal -matchPreviousExpr = match_previous_expr -oneOf = one_of -dictOf = dict_of -originalTextFor = original_text_for -nestedExpr = nested_expr -makeHTMLTags = make_html_tags -makeXMLTags = make_xml_tags -anyOpenTag, anyCloseTag = any_open_tag, any_close_tag -commonHTMLEntity = common_html_entity -replaceHTMLEntity = replace_html_entity -opAssoc = OpAssoc -infixNotation = infix_notation -cStyleComment = c_style_comment -htmlComment = html_comment -restOfLine = rest_of_line -dblSlashComment = dbl_slash_comment -cppStyleComment = cpp_style_comment -javaStyleComment = java_style_comment -pythonStyleComment = python_style_comment diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/results.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/results.py deleted file mode 100755 index 00c9421..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/results.py +++ /dev/null @@ -1,760 +0,0 @@ -# results.py -from collections.abc import MutableMapping, Mapping, MutableSequence, Iterator -import pprint -from weakref import ref as wkref -from typing import Tuple, Any - -str_type: Tuple[type, ...] = (str, bytes) -_generator_type = type((_ for _ in ())) - - -class _ParseResultsWithOffset: - __slots__ = ["tup"] - - def __init__(self, p1, p2): - self.tup = (p1, p2) - - def __getitem__(self, i): - return self.tup[i] - - def __getstate__(self): - return self.tup - - def __setstate__(self, *args): - self.tup = args[0] - - -class ParseResults: - """Structured parse results, to provide multiple means of access to - the parsed data: - - - as a list (``len(results)``) - - by list index (``results[0], results[1]``, etc.) - - by attribute (``results.`` - see :class:`ParserElement.set_results_name`) - - Example:: - - integer = Word(nums) - date_str = (integer.set_results_name("year") + '/' - + integer.set_results_name("month") + '/' - + integer.set_results_name("day")) - # equivalent form: - # date_str = (integer("year") + '/' - # + integer("month") + '/' - # + integer("day")) - - # parse_string returns a ParseResults object - result = date_str.parse_string("1999/12/31") - - def test(s, fn=repr): - print("{} -> {}".format(s, fn(eval(s)))) - test("list(result)") - test("result[0]") - test("result['month']") - test("result.day") - test("'month' in result") - test("'minutes' in result") - test("result.dump()", str) - - prints:: - - list(result) -> ['1999', '/', '12', '/', '31'] - result[0] -> '1999' - result['month'] -> '12' - result.day -> '31' - 'month' in result -> True - 'minutes' in result -> False - result.dump() -> ['1999', '/', '12', '/', '31'] - - day: '31' - - month: '12' - - year: '1999' - """ - - _null_values: Tuple[Any, ...] = (None, [], "", ()) - - __slots__ = [ - "_name", - "_parent", - "_all_names", - "_modal", - "_toklist", - "_tokdict", - "__weakref__", - ] - - class List(list): - """ - Simple wrapper class to distinguish parsed list results that should be preserved - as actual Python lists, instead of being converted to :class:`ParseResults`: - - LBRACK, RBRACK = map(pp.Suppress, "[]") - element = pp.Forward() - item = ppc.integer - element_list = LBRACK + pp.delimited_list(element) + RBRACK - - # add parse actions to convert from ParseResults to actual Python collection types - def as_python_list(t): - return pp.ParseResults.List(t.as_list()) - element_list.add_parse_action(as_python_list) - - element <<= item | element_list - - element.run_tests(''' - 100 - [2,3,4] - [[2, 1],3,4] - [(2, 1),3,4] - (2,3,4) - ''', post_parse=lambda s, r: (r[0], type(r[0]))) - - prints: - - 100 - (100, ) - - [2,3,4] - ([2, 3, 4], ) - - [[2, 1],3,4] - ([[2, 1], 3, 4], ) - - (Used internally by :class:`Group` when `aslist=True`.) - """ - - def __new__(cls, contained=None): - if contained is None: - contained = [] - - if not isinstance(contained, list): - raise TypeError( - "{} may only be constructed with a list," - " not {}".format(cls.__name__, type(contained).__name__) - ) - - return list.__new__(cls) - - def __new__(cls, toklist=None, name=None, **kwargs): - if isinstance(toklist, ParseResults): - return toklist - self = object.__new__(cls) - self._name = None - self._parent = None - self._all_names = set() - - if toklist is None: - self._toklist = [] - elif isinstance(toklist, (list, _generator_type)): - self._toklist = ( - [toklist[:]] - if isinstance(toklist, ParseResults.List) - else list(toklist) - ) - else: - self._toklist = [toklist] - self._tokdict = dict() - return self - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( - self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance - ): - self._modal = modal - if name is not None and name != "": - if isinstance(name, int): - name = str(name) - if not modal: - self._all_names = {name} - self._name = name - if toklist not in self._null_values: - if isinstance(toklist, (str_type, type)): - toklist = [toklist] - if asList: - if isinstance(toklist, ParseResults): - self[name] = _ParseResultsWithOffset( - ParseResults(toklist._toklist), 0 - ) - else: - self[name] = _ParseResultsWithOffset( - ParseResults(toklist[0]), 0 - ) - self[name]._name = name - else: - try: - self[name] = toklist[0] - except (KeyError, TypeError, IndexError): - if toklist is not self: - self[name] = toklist - else: - self._name = name - - def __getitem__(self, i): - if isinstance(i, (int, slice)): - return self._toklist[i] - else: - if i not in self._all_names: - return self._tokdict[i][-1][0] - else: - return ParseResults([v[0] for v in self._tokdict[i]]) - - def __setitem__(self, k, v, isinstance=isinstance): - if isinstance(v, _ParseResultsWithOffset): - self._tokdict[k] = self._tokdict.get(k, list()) + [v] - sub = v[0] - elif isinstance(k, (int, slice)): - self._toklist[k] = v - sub = v - else: - self._tokdict[k] = self._tokdict.get(k, list()) + [ - _ParseResultsWithOffset(v, 0) - ] - sub = v - if isinstance(sub, ParseResults): - sub._parent = wkref(self) - - def __delitem__(self, i): - if isinstance(i, (int, slice)): - mylen = len(self._toklist) - del self._toklist[i] - - # convert int to slice - if isinstance(i, int): - if i < 0: - i += mylen - i = slice(i, i + 1) - # get removed indices - removed = list(range(*i.indices(mylen))) - removed.reverse() - # fixup indices in token dictionary - for name, occurrences in self._tokdict.items(): - for j in removed: - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset( - value, position - (position > j) - ) - else: - del self._tokdict[i] - - def __contains__(self, k) -> bool: - return k in self._tokdict - - def __len__(self) -> int: - return len(self._toklist) - - def __bool__(self) -> bool: - return not not (self._toklist or self._tokdict) - - def __iter__(self) -> Iterator: - return iter(self._toklist) - - def __reversed__(self) -> Iterator: - return iter(self._toklist[::-1]) - - def keys(self): - return iter(self._tokdict) - - def values(self): - return (self[k] for k in self.keys()) - - def items(self): - return ((k, self[k]) for k in self.keys()) - - def haskeys(self) -> bool: - """ - Since ``keys()`` returns an iterator, this method is helpful in bypassing - code that looks for the existence of any defined results names.""" - return bool(self._tokdict) - - def pop(self, *args, **kwargs): - """ - Removes and returns item at specified index (default= ``last``). - Supports both ``list`` and ``dict`` semantics for ``pop()``. If - passed no argument or an integer argument, it will use ``list`` - semantics and pop tokens from the list of parsed tokens. If passed - a non-integer argument (most likely a string), it will use ``dict`` - semantics and pop the corresponding value from any defined results - names. A second default return value argument is supported, just as in - ``dict.pop()``. - - Example:: - - numlist = Word(nums)[...] - print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] - - def remove_first(tokens): - tokens.pop(0) - numlist.add_parse_action(remove_first) - print(numlist.parse_string("0 123 321")) # -> ['123', '321'] - - label = Word(alphas) - patt = label("LABEL") + Word(nums)[1, ...] - print(patt.parse_string("AAB 123 321").dump()) - - # Use pop() in a parse action to remove named result (note that corresponding value is not - # removed from list form of results) - def remove_LABEL(tokens): - tokens.pop("LABEL") - return tokens - patt.add_parse_action(remove_LABEL) - print(patt.parse_string("AAB 123 321").dump()) - - prints:: - - ['AAB', '123', '321'] - - LABEL: 'AAB' - - ['AAB', '123', '321'] - """ - if not args: - args = [-1] - for k, v in kwargs.items(): - if k == "default": - args = (args[0], v) - else: - raise TypeError( - "pop() got an unexpected keyword argument {!r}".format(k) - ) - if isinstance(args[0], int) or len(args) == 1 or args[0] in self: - index = args[0] - ret = self[index] - del self[index] - return ret - else: - defaultvalue = args[1] - return defaultvalue - - def get(self, key, default_value=None): - """ - Returns named result matching the given key, or if there is no - such name, then returns the given ``default_value`` or ``None`` if no - ``default_value`` is specified. - - Similar to ``dict.get()``. - - Example:: - - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parse_string("1999/12/31") - print(result.get("year")) # -> '1999' - print(result.get("hour", "not specified")) # -> 'not specified' - print(result.get("hour")) # -> None - """ - if key in self: - return self[key] - else: - return default_value - - def insert(self, index, ins_string): - """ - Inserts new element at location index in the list of parsed tokens. - - Similar to ``list.insert()``. - - Example:: - - numlist = Word(nums)[...] - print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to insert the parse location in the front of the parsed results - def insert_locn(locn, tokens): - tokens.insert(0, locn) - numlist.add_parse_action(insert_locn) - print(numlist.parse_string("0 123 321")) # -> [0, '0', '123', '321'] - """ - self._toklist.insert(index, ins_string) - # fixup indices in token dictionary - for name, occurrences in self._tokdict.items(): - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset( - value, position + (position > index) - ) - - def append(self, item): - """ - Add single element to end of ``ParseResults`` list of elements. - - Example:: - - numlist = Word(nums)[...] - print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to compute the sum of the parsed integers, and add it to the end - def append_sum(tokens): - tokens.append(sum(map(int, tokens))) - numlist.add_parse_action(append_sum) - print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321', 444] - """ - self._toklist.append(item) - - def extend(self, itemseq): - """ - Add sequence of elements to end of ``ParseResults`` list of elements. - - Example:: - - patt = Word(alphas)[1, ...] - - # use a parse action to append the reverse of the matched strings, to make a palindrome - def make_palindrome(tokens): - tokens.extend(reversed([t[::-1] for t in tokens])) - return ''.join(tokens) - patt.add_parse_action(make_palindrome) - print(patt.parse_string("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' - """ - if isinstance(itemseq, ParseResults): - self.__iadd__(itemseq) - else: - self._toklist.extend(itemseq) - - def clear(self): - """ - Clear all elements and results names. - """ - del self._toklist[:] - self._tokdict.clear() - - def __getattr__(self, name): - try: - return self[name] - except KeyError: - if name.startswith("__"): - raise AttributeError(name) - return "" - - def __add__(self, other) -> "ParseResults": - ret = self.copy() - ret += other - return ret - - def __iadd__(self, other) -> "ParseResults": - if other._tokdict: - offset = len(self._toklist) - addoffset = lambda a: offset if a < 0 else a + offset - otheritems = other._tokdict.items() - otherdictitems = [ - (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) - for k, vlist in otheritems - for v in vlist - ] - for k, v in otherdictitems: - self[k] = v - if isinstance(v[0], ParseResults): - v[0]._parent = wkref(self) - - self._toklist += other._toklist - self._all_names |= other._all_names - return self - - def __radd__(self, other) -> "ParseResults": - if isinstance(other, int) and other == 0: - # useful for merging many ParseResults using sum() builtin - return self.copy() - else: - # this may raise a TypeError - so be it - return other + self - - def __repr__(self) -> str: - return "{}({!r}, {})".format(type(self).__name__, self._toklist, self.as_dict()) - - def __str__(self) -> str: - return ( - "[" - + ", ".join( - [ - str(i) if isinstance(i, ParseResults) else repr(i) - for i in self._toklist - ] - ) - + "]" - ) - - def _asStringList(self, sep=""): - out = [] - for item in self._toklist: - if out and sep: - out.append(sep) - if isinstance(item, ParseResults): - out += item._asStringList() - else: - out.append(str(item)) - return out - - def as_list(self) -> list: - """ - Returns the parse results as a nested list of matching tokens, all converted to strings. - - Example:: - - patt = Word(alphas)[1, ...] - result = patt.parse_string("sldkj lsdkj sldkj") - # even though the result prints in string-like form, it is actually a pyparsing ParseResults - print(type(result), result) # -> ['sldkj', 'lsdkj', 'sldkj'] - - # Use as_list() to create an actual list - result_list = result.as_list() - print(type(result_list), result_list) # -> ['sldkj', 'lsdkj', 'sldkj'] - """ - return [ - res.as_list() if isinstance(res, ParseResults) else res - for res in self._toklist - ] - - def as_dict(self) -> dict: - """ - Returns the named parse results as a nested dictionary. - - Example:: - - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parse_string('12/31/1999') - print(type(result), repr(result)) # -> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) - - result_dict = result.as_dict() - print(type(result_dict), repr(result_dict)) # -> {'day': '1999', 'year': '12', 'month': '31'} - - # even though a ParseResults supports dict-like access, sometime you just need to have a dict - import json - print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable - print(json.dumps(result.as_dict())) # -> {"month": "31", "day": "1999", "year": "12"} - """ - - def to_item(obj): - if isinstance(obj, ParseResults): - return obj.as_dict() if obj.haskeys() else [to_item(v) for v in obj] - else: - return obj - - return dict((k, to_item(v)) for k, v in self.items()) - - def copy(self) -> "ParseResults": - """ - Returns a new copy of a :class:`ParseResults` object. - """ - ret = ParseResults(self._toklist) - ret._tokdict = self._tokdict.copy() - ret._parent = self._parent - ret._all_names |= self._all_names - ret._name = self._name - return ret - - def get_name(self): - r""" - Returns the results name for this token expression. Useful when several - different expressions might match at a particular location. - - Example:: - - integer = Word(nums) - ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") - house_number_expr = Suppress('#') + Word(nums, alphanums) - user_data = (Group(house_number_expr)("house_number") - | Group(ssn_expr)("ssn") - | Group(integer)("age")) - user_info = user_data[1, ...] - - result = user_info.parse_string("22 111-22-3333 #221B") - for item in result: - print(item.get_name(), ':', item[0]) - - prints:: - - age : 22 - ssn : 111-22-3333 - house_number : 221B - """ - if self._name: - return self._name - elif self._parent: - par = self._parent() - - def find_in_parent(sub): - return next( - ( - k - for k, vlist in par._tokdict.items() - for v, loc in vlist - if sub is v - ), - None, - ) - - return find_in_parent(self) if par else None - elif ( - len(self) == 1 - and len(self._tokdict) == 1 - and next(iter(self._tokdict.values()))[0][1] in (0, -1) - ): - return next(iter(self._tokdict.keys())) - else: - return None - - def dump(self, indent="", full=True, include_list=True, _depth=0) -> str: - """ - Diagnostic method for listing out the contents of - a :class:`ParseResults`. Accepts an optional ``indent`` argument so - that this string can be embedded in a nested display of other data. - - Example:: - - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parse_string('1999/12/31') - print(result.dump()) - - prints:: - - ['1999', '/', '12', '/', '31'] - - day: '31' - - month: '12' - - year: '1999' - """ - out = [] - NL = "\n" - out.append(indent + str(self.as_list()) if include_list else "") - - if full: - if self.haskeys(): - items = sorted((str(k), v) for k, v in self.items()) - for k, v in items: - if out: - out.append(NL) - out.append("{}{}- {}: ".format(indent, (" " * _depth), k)) - if isinstance(v, ParseResults): - if v: - out.append( - v.dump( - indent=indent, - full=full, - include_list=include_list, - _depth=_depth + 1, - ) - ) - else: - out.append(str(v)) - else: - out.append(repr(v)) - if any(isinstance(vv, ParseResults) for vv in self): - v = self - for i, vv in enumerate(v): - if isinstance(vv, ParseResults): - out.append( - "\n{}{}[{}]:\n{}{}{}".format( - indent, - (" " * (_depth)), - i, - indent, - (" " * (_depth + 1)), - vv.dump( - indent=indent, - full=full, - include_list=include_list, - _depth=_depth + 1, - ), - ) - ) - else: - out.append( - "\n%s%s[%d]:\n%s%s%s" - % ( - indent, - (" " * (_depth)), - i, - indent, - (" " * (_depth + 1)), - str(vv), - ) - ) - - return "".join(out) - - def pprint(self, *args, **kwargs): - """ - Pretty-printer for parsed results as a list, using the - `pprint `_ module. - Accepts additional positional or keyword args as defined for - `pprint.pprint `_ . - - Example:: - - ident = Word(alphas, alphanums) - num = Word(nums) - func = Forward() - term = ident | num | Group('(' + func + ')') - func <<= ident + Group(Optional(delimited_list(term))) - result = func.parse_string("fna a,b,(fnb c,d,200),100") - result.pprint(width=40) - - prints:: - - ['fna', - ['a', - 'b', - ['(', 'fnb', ['c', 'd', '200'], ')'], - '100']] - """ - pprint.pprint(self.as_list(), *args, **kwargs) - - # add support for pickle protocol - def __getstate__(self): - return ( - self._toklist, - ( - self._tokdict.copy(), - self._parent is not None and self._parent() or None, - self._all_names, - self._name, - ), - ) - - def __setstate__(self, state): - self._toklist, (self._tokdict, par, inAccumNames, self._name) = state - self._all_names = set(inAccumNames) - if par is not None: - self._parent = wkref(par) - else: - self._parent = None - - def __getnewargs__(self): - return self._toklist, self._name - - def __dir__(self): - return dir(type(self)) + list(self.keys()) - - @classmethod - def from_dict(cls, other, name=None) -> "ParseResults": - """ - Helper classmethod to construct a ``ParseResults`` from a ``dict``, preserving the - name-value relations as results names. If an optional ``name`` argument is - given, a nested ``ParseResults`` will be returned. - """ - - def is_iterable(obj): - try: - iter(obj) - except Exception: - return False - else: - return not isinstance(obj, str_type) - - ret = cls([]) - for k, v in other.items(): - if isinstance(v, Mapping): - ret += cls.from_dict(v, name=k) - else: - ret += cls([v], name=k, asList=is_iterable(v)) - if name is not None: - ret = cls([ret], name=name) - return ret - - asList = as_list - asDict = as_dict - getName = get_name - - -MutableMapping.register(ParseResults) -MutableSequence.register(ParseResults) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/testing.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/testing.py deleted file mode 100755 index 84a0ef1..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/testing.py +++ /dev/null @@ -1,331 +0,0 @@ -# testing.py - -from contextlib import contextmanager -import typing - -from .core import ( - ParserElement, - ParseException, - Keyword, - __diag__, - __compat__, -) - - -class pyparsing_test: - """ - namespace class for classes useful in writing unit tests - """ - - class reset_pyparsing_context: - """ - Context manager to be used when writing unit tests that modify pyparsing config values: - - packrat parsing - - bounded recursion parsing - - default whitespace characters. - - default keyword characters - - literal string auto-conversion class - - __diag__ settings - - Example:: - - with reset_pyparsing_context(): - # test that literals used to construct a grammar are automatically suppressed - ParserElement.inlineLiteralsUsing(Suppress) - - term = Word(alphas) | Word(nums) - group = Group('(' + term[...] + ')') - - # assert that the '()' characters are not included in the parsed tokens - self.assertParseAndCheckList(group, "(abc 123 def)", ['abc', '123', 'def']) - - # after exiting context manager, literals are converted to Literal expressions again - """ - - def __init__(self): - self._save_context = {} - - def save(self): - self._save_context["default_whitespace"] = ParserElement.DEFAULT_WHITE_CHARS - self._save_context["default_keyword_chars"] = Keyword.DEFAULT_KEYWORD_CHARS - - self._save_context[ - "literal_string_class" - ] = ParserElement._literalStringClass - - self._save_context["verbose_stacktrace"] = ParserElement.verbose_stacktrace - - self._save_context["packrat_enabled"] = ParserElement._packratEnabled - if ParserElement._packratEnabled: - self._save_context[ - "packrat_cache_size" - ] = ParserElement.packrat_cache.size - else: - self._save_context["packrat_cache_size"] = None - self._save_context["packrat_parse"] = ParserElement._parse - self._save_context[ - "recursion_enabled" - ] = ParserElement._left_recursion_enabled - - self._save_context["__diag__"] = { - name: getattr(__diag__, name) for name in __diag__._all_names - } - - self._save_context["__compat__"] = { - "collect_all_And_tokens": __compat__.collect_all_And_tokens - } - - return self - - def restore(self): - # reset pyparsing global state - if ( - ParserElement.DEFAULT_WHITE_CHARS - != self._save_context["default_whitespace"] - ): - ParserElement.set_default_whitespace_chars( - self._save_context["default_whitespace"] - ) - - ParserElement.verbose_stacktrace = self._save_context["verbose_stacktrace"] - - Keyword.DEFAULT_KEYWORD_CHARS = self._save_context["default_keyword_chars"] - ParserElement.inlineLiteralsUsing( - self._save_context["literal_string_class"] - ) - - for name, value in self._save_context["__diag__"].items(): - (__diag__.enable if value else __diag__.disable)(name) - - ParserElement._packratEnabled = False - if self._save_context["packrat_enabled"]: - ParserElement.enable_packrat(self._save_context["packrat_cache_size"]) - else: - ParserElement._parse = self._save_context["packrat_parse"] - ParserElement._left_recursion_enabled = self._save_context[ - "recursion_enabled" - ] - - __compat__.collect_all_And_tokens = self._save_context["__compat__"] - - return self - - def copy(self): - ret = type(self)() - ret._save_context.update(self._save_context) - return ret - - def __enter__(self): - return self.save() - - def __exit__(self, *args): - self.restore() - - class TestParseResultsAsserts: - """ - A mixin class to add parse results assertion methods to normal unittest.TestCase classes. - """ - - def assertParseResultsEquals( - self, result, expected_list=None, expected_dict=None, msg=None - ): - """ - Unit test assertion to compare a :class:`ParseResults` object with an optional ``expected_list``, - and compare any defined results names with an optional ``expected_dict``. - """ - if expected_list is not None: - self.assertEqual(expected_list, result.as_list(), msg=msg) - if expected_dict is not None: - self.assertEqual(expected_dict, result.as_dict(), msg=msg) - - def assertParseAndCheckList( - self, expr, test_string, expected_list, msg=None, verbose=True - ): - """ - Convenience wrapper assert to test a parser element and input string, and assert that - the resulting ``ParseResults.asList()`` is equal to the ``expected_list``. - """ - result = expr.parse_string(test_string, parse_all=True) - if verbose: - print(result.dump()) - else: - print(result.as_list()) - self.assertParseResultsEquals(result, expected_list=expected_list, msg=msg) - - def assertParseAndCheckDict( - self, expr, test_string, expected_dict, msg=None, verbose=True - ): - """ - Convenience wrapper assert to test a parser element and input string, and assert that - the resulting ``ParseResults.asDict()`` is equal to the ``expected_dict``. - """ - result = expr.parse_string(test_string, parseAll=True) - if verbose: - print(result.dump()) - else: - print(result.as_list()) - self.assertParseResultsEquals(result, expected_dict=expected_dict, msg=msg) - - def assertRunTestResults( - self, run_tests_report, expected_parse_results=None, msg=None - ): - """ - Unit test assertion to evaluate output of ``ParserElement.runTests()``. If a list of - list-dict tuples is given as the ``expected_parse_results`` argument, then these are zipped - with the report tuples returned by ``runTests`` and evaluated using ``assertParseResultsEquals``. - Finally, asserts that the overall ``runTests()`` success value is ``True``. - - :param run_tests_report: tuple(bool, [tuple(str, ParseResults or Exception)]) returned from runTests - :param expected_parse_results (optional): [tuple(str, list, dict, Exception)] - """ - run_test_success, run_test_results = run_tests_report - - if expected_parse_results is not None: - merged = [ - (*rpt, expected) - for rpt, expected in zip(run_test_results, expected_parse_results) - ] - for test_string, result, expected in merged: - # expected should be a tuple containing a list and/or a dict or an exception, - # and optional failure message string - # an empty tuple will skip any result validation - fail_msg = next( - (exp for exp in expected if isinstance(exp, str)), None - ) - expected_exception = next( - ( - exp - for exp in expected - if isinstance(exp, type) and issubclass(exp, Exception) - ), - None, - ) - if expected_exception is not None: - with self.assertRaises( - expected_exception=expected_exception, msg=fail_msg or msg - ): - if isinstance(result, Exception): - raise result - else: - expected_list = next( - (exp for exp in expected if isinstance(exp, list)), None - ) - expected_dict = next( - (exp for exp in expected if isinstance(exp, dict)), None - ) - if (expected_list, expected_dict) != (None, None): - self.assertParseResultsEquals( - result, - expected_list=expected_list, - expected_dict=expected_dict, - msg=fail_msg or msg, - ) - else: - # warning here maybe? - print("no validation for {!r}".format(test_string)) - - # do this last, in case some specific test results can be reported instead - self.assertTrue( - run_test_success, msg=msg if msg is not None else "failed runTests" - ) - - @contextmanager - def assertRaisesParseException(self, exc_type=ParseException, msg=None): - with self.assertRaises(exc_type, msg=msg): - yield - - @staticmethod - def with_line_numbers( - s: str, - start_line: typing.Optional[int] = None, - end_line: typing.Optional[int] = None, - expand_tabs: bool = True, - eol_mark: str = "|", - mark_spaces: typing.Optional[str] = None, - mark_control: typing.Optional[str] = None, - ) -> str: - """ - Helpful method for debugging a parser - prints a string with line and column numbers. - (Line and column numbers are 1-based.) - - :param s: tuple(bool, str - string to be printed with line and column numbers - :param start_line: int - (optional) starting line number in s to print (default=1) - :param end_line: int - (optional) ending line number in s to print (default=len(s)) - :param expand_tabs: bool - (optional) expand tabs to spaces, to match the pyparsing default - :param eol_mark: str - (optional) string to mark the end of lines, helps visualize trailing spaces (default="|") - :param mark_spaces: str - (optional) special character to display in place of spaces - :param mark_control: str - (optional) convert non-printing control characters to a placeholding - character; valid values: - - "unicode" - replaces control chars with Unicode symbols, such as "␍" and "␊" - - any single character string - replace control characters with given string - - None (default) - string is displayed as-is - - :return: str - input string with leading line numbers and column number headers - """ - if expand_tabs: - s = s.expandtabs() - if mark_control is not None: - if mark_control == "unicode": - tbl = str.maketrans( - {c: u for c, u in zip(range(0, 33), range(0x2400, 0x2433))} - | {127: 0x2421} - ) - eol_mark = "" - else: - tbl = str.maketrans( - {c: mark_control for c in list(range(0, 32)) + [127]} - ) - s = s.translate(tbl) - if mark_spaces is not None and mark_spaces != " ": - if mark_spaces == "unicode": - tbl = str.maketrans({9: 0x2409, 32: 0x2423}) - s = s.translate(tbl) - else: - s = s.replace(" ", mark_spaces) - if start_line is None: - start_line = 1 - if end_line is None: - end_line = len(s) - end_line = min(end_line, len(s)) - start_line = min(max(1, start_line), end_line) - - if mark_control != "unicode": - s_lines = s.splitlines()[start_line - 1 : end_line] - else: - s_lines = [line + "␊" for line in s.split("␊")[start_line - 1 : end_line]] - if not s_lines: - return "" - - lineno_width = len(str(end_line)) - max_line_len = max(len(line) for line in s_lines) - lead = " " * (lineno_width + 1) - if max_line_len >= 99: - header0 = ( - lead - + "".join( - "{}{}".format(" " * 99, (i + 1) % 100) - for i in range(max(max_line_len // 100, 1)) - ) - + "\n" - ) - else: - header0 = "" - header1 = ( - header0 - + lead - + "".join( - " {}".format((i + 1) % 10) - for i in range(-(-max_line_len // 10)) - ) - + "\n" - ) - header2 = lead + "1234567890" * (-(-max_line_len // 10)) + "\n" - return ( - header1 - + header2 - + "\n".join( - "{:{}d}:{}{}".format(i, lineno_width, line, eol_mark) - for i, line in enumerate(s_lines, start=start_line) - ) - + "\n" - ) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/unicode.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/unicode.py deleted file mode 100755 index 0652620..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/unicode.py +++ /dev/null @@ -1,352 +0,0 @@ -# unicode.py - -import sys -from itertools import filterfalse -from typing import List, Tuple, Union - - -class _lazyclassproperty: - def __init__(self, fn): - self.fn = fn - self.__doc__ = fn.__doc__ - self.__name__ = fn.__name__ - - def __get__(self, obj, cls): - if cls is None: - cls = type(obj) - if not hasattr(cls, "_intern") or any( - cls._intern is getattr(superclass, "_intern", []) - for superclass in cls.__mro__[1:] - ): - cls._intern = {} - attrname = self.fn.__name__ - if attrname not in cls._intern: - cls._intern[attrname] = self.fn(cls) - return cls._intern[attrname] - - -UnicodeRangeList = List[Union[Tuple[int, int], Tuple[int]]] - - -class unicode_set: - """ - A set of Unicode characters, for language-specific strings for - ``alphas``, ``nums``, ``alphanums``, and ``printables``. - A unicode_set is defined by a list of ranges in the Unicode character - set, in a class attribute ``_ranges``. Ranges can be specified using - 2-tuples or a 1-tuple, such as:: - - _ranges = [ - (0x0020, 0x007e), - (0x00a0, 0x00ff), - (0x0100,), - ] - - Ranges are left- and right-inclusive. A 1-tuple of (x,) is treated as (x, x). - - A unicode set can also be defined using multiple inheritance of other unicode sets:: - - class CJK(Chinese, Japanese, Korean): - pass - """ - - _ranges: UnicodeRangeList = [] - - @_lazyclassproperty - def _chars_for_ranges(cls): - ret = [] - for cc in cls.__mro__: - if cc is unicode_set: - break - for rr in getattr(cc, "_ranges", ()): - ret.extend(range(rr[0], rr[-1] + 1)) - return [chr(c) for c in sorted(set(ret))] - - @_lazyclassproperty - def printables(cls): - "all non-whitespace characters in this range" - return "".join(filterfalse(str.isspace, cls._chars_for_ranges)) - - @_lazyclassproperty - def alphas(cls): - "all alphabetic characters in this range" - return "".join(filter(str.isalpha, cls._chars_for_ranges)) - - @_lazyclassproperty - def nums(cls): - "all numeric digit characters in this range" - return "".join(filter(str.isdigit, cls._chars_for_ranges)) - - @_lazyclassproperty - def alphanums(cls): - "all alphanumeric characters in this range" - return cls.alphas + cls.nums - - @_lazyclassproperty - def identchars(cls): - "all characters in this range that are valid identifier characters, plus underscore '_'" - return "".join( - sorted( - set( - "".join(filter(str.isidentifier, cls._chars_for_ranges)) - + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµº" - + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ" - + "_" - ) - ) - ) - - @_lazyclassproperty - def identbodychars(cls): - """ - all characters in this range that are valid identifier body characters, - plus the digits 0-9 - """ - return "".join( - sorted( - set( - cls.identchars - + "0123456789" - + "".join( - [c for c in cls._chars_for_ranges if ("_" + c).isidentifier()] - ) - ) - ) - ) - - -class pyparsing_unicode(unicode_set): - """ - A namespace class for defining common language unicode_sets. - """ - - # fmt: off - - # define ranges in language character sets - _ranges: UnicodeRangeList = [ - (0x0020, sys.maxunicode), - ] - - class BasicMultilingualPlane(unicode_set): - "Unicode set for the Basic Multilingual Plane" - _ranges: UnicodeRangeList = [ - (0x0020, 0xFFFF), - ] - - class Latin1(unicode_set): - "Unicode set for Latin-1 Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0020, 0x007E), - (0x00A0, 0x00FF), - ] - - class LatinA(unicode_set): - "Unicode set for Latin-A Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0100, 0x017F), - ] - - class LatinB(unicode_set): - "Unicode set for Latin-B Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0180, 0x024F), - ] - - class Greek(unicode_set): - "Unicode set for Greek Unicode Character Ranges" - _ranges: UnicodeRangeList = [ - (0x0342, 0x0345), - (0x0370, 0x0377), - (0x037A, 0x037F), - (0x0384, 0x038A), - (0x038C,), - (0x038E, 0x03A1), - (0x03A3, 0x03E1), - (0x03F0, 0x03FF), - (0x1D26, 0x1D2A), - (0x1D5E,), - (0x1D60,), - (0x1D66, 0x1D6A), - (0x1F00, 0x1F15), - (0x1F18, 0x1F1D), - (0x1F20, 0x1F45), - (0x1F48, 0x1F4D), - (0x1F50, 0x1F57), - (0x1F59,), - (0x1F5B,), - (0x1F5D,), - (0x1F5F, 0x1F7D), - (0x1F80, 0x1FB4), - (0x1FB6, 0x1FC4), - (0x1FC6, 0x1FD3), - (0x1FD6, 0x1FDB), - (0x1FDD, 0x1FEF), - (0x1FF2, 0x1FF4), - (0x1FF6, 0x1FFE), - (0x2129,), - (0x2719, 0x271A), - (0xAB65,), - (0x10140, 0x1018D), - (0x101A0,), - (0x1D200, 0x1D245), - (0x1F7A1, 0x1F7A7), - ] - - class Cyrillic(unicode_set): - "Unicode set for Cyrillic Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0400, 0x052F), - (0x1C80, 0x1C88), - (0x1D2B,), - (0x1D78,), - (0x2DE0, 0x2DFF), - (0xA640, 0xA672), - (0xA674, 0xA69F), - (0xFE2E, 0xFE2F), - ] - - class Chinese(unicode_set): - "Unicode set for Chinese Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x2E80, 0x2E99), - (0x2E9B, 0x2EF3), - (0x31C0, 0x31E3), - (0x3400, 0x4DB5), - (0x4E00, 0x9FEF), - (0xA700, 0xA707), - (0xF900, 0xFA6D), - (0xFA70, 0xFAD9), - (0x16FE2, 0x16FE3), - (0x1F210, 0x1F212), - (0x1F214, 0x1F23B), - (0x1F240, 0x1F248), - (0x20000, 0x2A6D6), - (0x2A700, 0x2B734), - (0x2B740, 0x2B81D), - (0x2B820, 0x2CEA1), - (0x2CEB0, 0x2EBE0), - (0x2F800, 0x2FA1D), - ] - - class Japanese(unicode_set): - "Unicode set for Japanese Unicode Character Range, combining Kanji, Hiragana, and Katakana ranges" - _ranges: UnicodeRangeList = [] - - class Kanji(unicode_set): - "Unicode set for Kanji Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x4E00, 0x9FBF), - (0x3000, 0x303F), - ] - - class Hiragana(unicode_set): - "Unicode set for Hiragana Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x3041, 0x3096), - (0x3099, 0x30A0), - (0x30FC,), - (0xFF70,), - (0x1B001,), - (0x1B150, 0x1B152), - (0x1F200,), - ] - - class Katakana(unicode_set): - "Unicode set for Katakana Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x3099, 0x309C), - (0x30A0, 0x30FF), - (0x31F0, 0x31FF), - (0x32D0, 0x32FE), - (0xFF65, 0xFF9F), - (0x1B000,), - (0x1B164, 0x1B167), - (0x1F201, 0x1F202), - (0x1F213,), - ] - - class Hangul(unicode_set): - "Unicode set for Hangul (Korean) Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x1100, 0x11FF), - (0x302E, 0x302F), - (0x3131, 0x318E), - (0x3200, 0x321C), - (0x3260, 0x327B), - (0x327E,), - (0xA960, 0xA97C), - (0xAC00, 0xD7A3), - (0xD7B0, 0xD7C6), - (0xD7CB, 0xD7FB), - (0xFFA0, 0xFFBE), - (0xFFC2, 0xFFC7), - (0xFFCA, 0xFFCF), - (0xFFD2, 0xFFD7), - (0xFFDA, 0xFFDC), - ] - - Korean = Hangul - - class CJK(Chinese, Japanese, Hangul): - "Unicode set for combined Chinese, Japanese, and Korean (CJK) Unicode Character Range" - - class Thai(unicode_set): - "Unicode set for Thai Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0E01, 0x0E3A), - (0x0E3F, 0x0E5B) - ] - - class Arabic(unicode_set): - "Unicode set for Arabic Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0600, 0x061B), - (0x061E, 0x06FF), - (0x0700, 0x077F), - ] - - class Hebrew(unicode_set): - "Unicode set for Hebrew Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0591, 0x05C7), - (0x05D0, 0x05EA), - (0x05EF, 0x05F4), - (0xFB1D, 0xFB36), - (0xFB38, 0xFB3C), - (0xFB3E,), - (0xFB40, 0xFB41), - (0xFB43, 0xFB44), - (0xFB46, 0xFB4F), - ] - - class Devanagari(unicode_set): - "Unicode set for Devanagari Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0900, 0x097F), - (0xA8E0, 0xA8FF) - ] - - # fmt: on - - -pyparsing_unicode.Japanese._ranges = ( - pyparsing_unicode.Japanese.Kanji._ranges - + pyparsing_unicode.Japanese.Hiragana._ranges - + pyparsing_unicode.Japanese.Katakana._ranges -) - -pyparsing_unicode.BMP = pyparsing_unicode.BasicMultilingualPlane - -# add language identifiers using language Unicode -pyparsing_unicode.العربية = pyparsing_unicode.Arabic -pyparsing_unicode.中文 = pyparsing_unicode.Chinese -pyparsing_unicode.кириллица = pyparsing_unicode.Cyrillic -pyparsing_unicode.Ελληνικά = pyparsing_unicode.Greek -pyparsing_unicode.עִברִית = pyparsing_unicode.Hebrew -pyparsing_unicode.日本語 = pyparsing_unicode.Japanese -pyparsing_unicode.Japanese.漢字 = pyparsing_unicode.Japanese.Kanji -pyparsing_unicode.Japanese.カタカナ = pyparsing_unicode.Japanese.Katakana -pyparsing_unicode.Japanese.ひらがな = pyparsing_unicode.Japanese.Hiragana -pyparsing_unicode.한국어 = pyparsing_unicode.Korean -pyparsing_unicode.ไทย = pyparsing_unicode.Thai -pyparsing_unicode.देवनागरी = pyparsing_unicode.Devanagari diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/util.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/util.py deleted file mode 100755 index 34ce092..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/util.py +++ /dev/null @@ -1,235 +0,0 @@ -# util.py -import warnings -import types -import collections -import itertools -from functools import lru_cache -from typing import List, Union, Iterable - -_bslash = chr(92) - - -class __config_flags: - """Internal class for defining compatibility and debugging flags""" - - _all_names: List[str] = [] - _fixed_names: List[str] = [] - _type_desc = "configuration" - - @classmethod - def _set(cls, dname, value): - if dname in cls._fixed_names: - warnings.warn( - "{}.{} {} is {} and cannot be overridden".format( - cls.__name__, - dname, - cls._type_desc, - str(getattr(cls, dname)).upper(), - ) - ) - return - if dname in cls._all_names: - setattr(cls, dname, value) - else: - raise ValueError("no such {} {!r}".format(cls._type_desc, dname)) - - enable = classmethod(lambda cls, name: cls._set(name, True)) - disable = classmethod(lambda cls, name: cls._set(name, False)) - - -@lru_cache(maxsize=128) -def col(loc: int, strg: str) -> int: - """ - Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See - :class:`ParserElement.parseString` for more - information on parsing strings containing ```` s, and suggested - methods to maintain a consistent view of the parsed string, the parse - location, and line and column positions within the parsed string. - """ - s = strg - return 1 if 0 < loc < len(s) and s[loc - 1] == "\n" else loc - s.rfind("\n", 0, loc) - - -@lru_cache(maxsize=128) -def lineno(loc: int, strg: str) -> int: - """Returns current line number within a string, counting newlines as line separators. - The first line is number 1. - - Note - the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See :class:`ParserElement.parseString` - for more information on parsing strings containing ```` s, and - suggested methods to maintain a consistent view of the parsed string, the - parse location, and line and column positions within the parsed string. - """ - return strg.count("\n", 0, loc) + 1 - - -@lru_cache(maxsize=128) -def line(loc: int, strg: str) -> str: - """ - Returns the line of text containing loc within a string, counting newlines as line separators. - """ - last_cr = strg.rfind("\n", 0, loc) - next_cr = strg.find("\n", loc) - return strg[last_cr + 1 : next_cr] if next_cr >= 0 else strg[last_cr + 1 :] - - -class _UnboundedCache: - def __init__(self): - cache = {} - cache_get = cache.get - self.not_in_cache = not_in_cache = object() - - def get(_, key): - return cache_get(key, not_in_cache) - - def set_(_, key, value): - cache[key] = value - - def clear(_): - cache.clear() - - self.size = None - self.get = types.MethodType(get, self) - self.set = types.MethodType(set_, self) - self.clear = types.MethodType(clear, self) - - -class _FifoCache: - def __init__(self, size): - self.not_in_cache = not_in_cache = object() - cache = collections.OrderedDict() - cache_get = cache.get - - def get(_, key): - return cache_get(key, not_in_cache) - - def set_(_, key, value): - cache[key] = value - while len(cache) > size: - cache.popitem(last=False) - - def clear(_): - cache.clear() - - self.size = size - self.get = types.MethodType(get, self) - self.set = types.MethodType(set_, self) - self.clear = types.MethodType(clear, self) - - -class LRUMemo: - """ - A memoizing mapping that retains `capacity` deleted items - - The memo tracks retained items by their access order; once `capacity` items - are retained, the least recently used item is discarded. - """ - - def __init__(self, capacity): - self._capacity = capacity - self._active = {} - self._memory = collections.OrderedDict() - - def __getitem__(self, key): - try: - return self._active[key] - except KeyError: - self._memory.move_to_end(key) - return self._memory[key] - - def __setitem__(self, key, value): - self._memory.pop(key, None) - self._active[key] = value - - def __delitem__(self, key): - try: - value = self._active.pop(key) - except KeyError: - pass - else: - while len(self._memory) >= self._capacity: - self._memory.popitem(last=False) - self._memory[key] = value - - def clear(self): - self._active.clear() - self._memory.clear() - - -class UnboundedMemo(dict): - """ - A memoizing mapping that retains all deleted items - """ - - def __delitem__(self, key): - pass - - -def _escape_regex_range_chars(s: str) -> str: - # escape these chars: ^-[] - for c in r"\^-[]": - s = s.replace(c, _bslash + c) - s = s.replace("\n", r"\n") - s = s.replace("\t", r"\t") - return str(s) - - -def _collapse_string_to_ranges( - s: Union[str, Iterable[str]], re_escape: bool = True -) -> str: - def is_consecutive(c): - c_int = ord(c) - is_consecutive.prev, prev = c_int, is_consecutive.prev - if c_int - prev > 1: - is_consecutive.value = next(is_consecutive.counter) - return is_consecutive.value - - is_consecutive.prev = 0 - is_consecutive.counter = itertools.count() - is_consecutive.value = -1 - - def escape_re_range_char(c): - return "\\" + c if c in r"\^-][" else c - - def no_escape_re_range_char(c): - return c - - if not re_escape: - escape_re_range_char = no_escape_re_range_char - - ret = [] - s = "".join(sorted(set(s))) - if len(s) > 3: - for _, chars in itertools.groupby(s, key=is_consecutive): - first = last = next(chars) - last = collections.deque( - itertools.chain(iter([last]), chars), maxlen=1 - ).pop() - if first == last: - ret.append(escape_re_range_char(first)) - else: - sep = "" if ord(last) == ord(first) + 1 else "-" - ret.append( - "{}{}{}".format( - escape_re_range_char(first), sep, escape_re_range_char(last) - ) - ) - else: - ret = [escape_re_range_char(c) for c in s] - - return "".join(ret) - - -def _flatten(ll: list) -> list: - ret = [] - for i in ll: - if isinstance(i, list): - ret.extend(_flatten(i)) - else: - ret.append(i) - return ret diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__init__.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__init__.py deleted file mode 100755 index 4c6ec97..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2021 Taneli Hukkinen -# Licensed to PSF under a Contributor Agreement. - -__all__ = ("loads", "load", "TOMLDecodeError") -__version__ = "2.0.1" # DO NOT EDIT THIS LINE MANUALLY. LET bump2version UTILITY DO IT - -from ._parser import TOMLDecodeError, load, loads - -# Pretend this exception was created here. -TOMLDecodeError.__module__ = __name__ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 841df831690e5d11bee4c00c52c9f493a46bad0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 417 zcmZ`!Jxc>Y5Z%k(<&MN8m5qg^aD}%y(~36Qh#!SkhcK+!B{|)_J$5gFSmg&;3W9$? z{5L65$W?-sT_9a5_tZ3k!(-kXn3*^8(rPu3jrrsA?Sq5RM^&t&_A8cME1nQT31Uv- zuo}anCUJtLo4C?TJO}YQ$KbCAnR|&sFT|xM6lJD#D=Irz7iXtOyssEP)>`R%Z!hXb z@u#&#A=a)XjjL4oo`*r{15hCV$|k^=Ym=(X7Cz)u8?OHhlmS3SCAS?70IAqWSpABY zb{Se-lcAEFNUHmaoT!275t`>@%(F2O=?%#z#ZYCvD2|Cq3%;Av{v91~LkurQd7+dr z#NLoGrAeWrNC`lir3FBgPgcSHkKciATeIpPb7<27JC3txpeC96Z|%)#^Bu*r|FNi} Q?VV|7j<#ms&>MEg7Xwyu)&Kwi diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_parser.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_parser.cpython-311.pyc deleted file mode 100755 index b35a8ad124fb11a92a1e77e474f10db6fcf34ffb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30856 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 I0Hb;T4}^b>-T(jq diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_re.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_re.cpython-311.pyc deleted file mode 100755 index 5911fdb9739116a240ea9a0ea80fcc2f1cad01d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4496 zcmb6cS!^4}b@t%3B()+X%aT&ZtEfI!u|&zT8()d)Ly8+82_!cOC=1k@yOOAoTw!); z*z_(;6amTvDxw4~BBwU00Ez0>{;&%Nb%FN3pJXAR!~z107X9!a4eQH4?VF)UYvt5+ zM*dH1|GZ-&1MhXn*<<=R)XSAz)si%janQ$v_1Jq$u$A{D7j8fBO`!w{TJvl%YV zW!N~I;p2S96Zd4iac{;K_fa~R_Gbd|0LA&V5EnqklMZG=@er(eRbM)sX^J-i?vINs z(uCROx?wc{vq*h*M_6VNx((mjh)3Prnz#)9-G=Wvy~RyegPQmoq=s&CFVxzqZdW58 z^YJYp9Z>l@QMXoAQrkb~m%+sCx*-&AQ@hkoklCufroIaQ+f{xH$=#0#hs-!ZC7abv z#Z2j0L-snns+gMNC(uk~G>4}!K%lCnO~vsOG_Pkh$7|+O*(n`#1kyN{NGi!0?JUf= zquI-kNTh%Z?e;2PvDeS(~$Y+hcoepY68;wqOTM&{ZE6<36b_8v6no=cd_B zcGwPCd?8}4cRpgl3Rz*RX&LO@ZrB_{E*rdCkBjDc0nO{C*%7^t!67?MXi=Qo@GDm4}5C_dZ0JId|c07)UYWj(&XrH;>6K&!{>f>W_VJf^&^?O zG+8g0zB)1~>3GxfWS>BbcvMLlnjyWfq;uLZ#=w`FlFS)xU7e}}5t^-()G^i!IC3g6 zp-2~%bP9SmoEWMGBux8$91@{{*a0Bx6gV>Co(P9||C-vAn`m{b6Q|9Jk7q#rgSUPnfHh0;a z(X)en0|PN5Woo^1O7bIRS~FtMG;(vMuBVMy0=QKj$4otwPQ?2XKMaCHx#~-x)jV%RFm4l~Nf~QLSsVA@{psY1ZQ*RhF$gJZbb!tGY^n@5PM}xvXV8L4f$UF_7 zMvezz!Qn~x205psZgC&s?5Kke05Qe@6wt%w_Qm60hznwIpg6EJS~vmQz6!MyZM)gB z_~G?!H@20dJ1ed2HwPE<*N1Klm0NqN9xfm}MgZ0bc+7c1-ZccEiaZ`K?k84A4{_ah z#8tZIYk<7;eFy&6?>md%bPw=LjTbPeYz&oA*%$3E&9BEK{;UsIemCXIMf(AFr{!4& z-*1!srvtLepT(q~;4K8u-pb=Pf|CT|b^^$*$zIwuH{??yq%H#X05Av>$?1AlooJ(F zr1hkdChZX)2A&IqSp!f&mHz#I3jHy3ujzhMneQ!}EY2?OS~~QS2Y59o{+e4j`FZ$S z_@=RR==#+gSHI)#zI`urKlEU#92{N=4wv|0nsz4$FG530(AOmngKbRSImwNQB3nWW z;SYfP??O;FB?50_k;S~+Gs%4@H$6_!64-ryEW^^XA2ORu2-3%$bpnl7b1i>xF6pIM zJA!O2Z%06pK?1JlM{MLLo6B6#F#ahJX9(8_07#B6^vf&1xUz7#?AyNL+g?SCr>7!z z7OyPs|Lx(g4qt!s#+zkPUJ>PzUtSG16?30m`Si*s_Po8Ql!MYrP%7~f-F;{RQ>5;cr+lAHT^`Hl5RwUXd!d8JY$xpIdiBob3Oc=BqA z1SWl!-v0EBKr6b|ricalmVj-{Ws~#{#N>tLu$cV5yF8c5PSbL6ya||T1~ue_66BSX zfEUx)xlzZL)H8FbwC4EUA09pS?%1#s0Ls~)pE))>>VyD2{qFIjr-_6UgjxNOMK94> z|073(rr`Ie)~ZNreCj`v(bZg9dkdd|DQW(O1+dC73{w>l(_KQZZTvh$Bc&hmsi5s8 z_ospa1^QP(Z6){TA$qms{(uY3A2Nl|!%$oC*!(+HR`l>y2?fLRJ=N}Ln0<@@tPxNM zRCl80&LW=AFYYOeyH>=w{#osDsBGVmlhktsFA~YMz53j_D%H-wSAV F{tGk91YiIF diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_types.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_types.cpython-311.pyc deleted file mode 100755 index 43200037110e0b4924252ba25e2d24f1eaa82c19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 409 zcmZ`zze~eF6u!%)v5iCrL2z`^4)!QrMUa9NMJd!NOF5fontI6{cWEJ82ZxRs1jTD_h3)sQI_wIf7y~p={ym_9BjLn~3N8jfEER&6qU$W{L@{9r$V2)z! zO5PtAcXzZ#Gps@q?svQ7$eo@7O}%{XUw9E!^A zSaN9G)N6&4W->}bRUV-15-J7?qEl74U8Xc#aKX}oTtQZlC^4)n^gCJ^63_yZmN_m&RY+0S(jFTH#;_YSA-!r7j+ U^SxQ;QB29gsZB}g$} dict[str, Any]: - """Parse TOML from a binary file object.""" - b = __fp.read() - try: - s = b.decode() - except AttributeError: - raise TypeError( - "File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`" - ) from None - return loads(s, parse_float=parse_float) - - -def loads(__s: str, *, parse_float: ParseFloat = float) -> dict[str, Any]: # noqa: C901 - """Parse TOML from a string.""" - - # The spec allows converting "\r\n" to "\n", even in string - # literals. Let's do so to simplify parsing. - src = __s.replace("\r\n", "\n") - pos = 0 - out = Output(NestedDict(), Flags()) - header: Key = () - parse_float = make_safe_parse_float(parse_float) - - # Parse one statement at a time - # (typically means one line in TOML source) - while True: - # 1. Skip line leading whitespace - pos = skip_chars(src, pos, TOML_WS) - - # 2. Parse rules. Expect one of the following: - # - end of file - # - end of line - # - comment - # - key/value pair - # - append dict to list (and move to its namespace) - # - create dict (and move to its namespace) - # Skip trailing whitespace when applicable. - try: - char = src[pos] - except IndexError: - break - if char == "\n": - pos += 1 - continue - if char in KEY_INITIAL_CHARS: - pos = key_value_rule(src, pos, out, header, parse_float) - pos = skip_chars(src, pos, TOML_WS) - elif char == "[": - try: - second_char: str | None = src[pos + 1] - except IndexError: - second_char = None - out.flags.finalize_pending() - if second_char == "[": - pos, header = create_list_rule(src, pos, out) - else: - pos, header = create_dict_rule(src, pos, out) - pos = skip_chars(src, pos, TOML_WS) - elif char != "#": - raise suffixed_err(src, pos, "Invalid statement") - - # 3. Skip comment - pos = skip_comment(src, pos) - - # 4. Expect end of line or end of file - try: - char = src[pos] - except IndexError: - break - if char != "\n": - raise suffixed_err( - src, pos, "Expected newline or end of document after a statement" - ) - pos += 1 - - return out.data.dict - - -class Flags: - """Flags that map to parsed keys/namespaces.""" - - # Marks an immutable namespace (inline array or inline table). - FROZEN = 0 - # Marks a nest that has been explicitly created and can no longer - # be opened using the "[table]" syntax. - EXPLICIT_NEST = 1 - - def __init__(self) -> None: - self._flags: dict[str, dict] = {} - self._pending_flags: set[tuple[Key, int]] = set() - - def add_pending(self, key: Key, flag: int) -> None: - self._pending_flags.add((key, flag)) - - def finalize_pending(self) -> None: - for key, flag in self._pending_flags: - self.set(key, flag, recursive=False) - self._pending_flags.clear() - - def unset_all(self, key: Key) -> None: - cont = self._flags - for k in key[:-1]: - if k not in cont: - return - cont = cont[k]["nested"] - cont.pop(key[-1], None) - - def set(self, key: Key, flag: int, *, recursive: bool) -> None: # noqa: A003 - cont = self._flags - key_parent, key_stem = key[:-1], key[-1] - for k in key_parent: - if k not in cont: - cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}} - cont = cont[k]["nested"] - if key_stem not in cont: - cont[key_stem] = {"flags": set(), "recursive_flags": set(), "nested": {}} - cont[key_stem]["recursive_flags" if recursive else "flags"].add(flag) - - def is_(self, key: Key, flag: int) -> bool: - if not key: - return False # document root has no flags - cont = self._flags - for k in key[:-1]: - if k not in cont: - return False - inner_cont = cont[k] - if flag in inner_cont["recursive_flags"]: - return True - cont = inner_cont["nested"] - key_stem = key[-1] - if key_stem in cont: - cont = cont[key_stem] - return flag in cont["flags"] or flag in cont["recursive_flags"] - return False - - -class NestedDict: - def __init__(self) -> None: - # The parsed content of the TOML document - self.dict: dict[str, Any] = {} - - def get_or_create_nest( - self, - key: Key, - *, - access_lists: bool = True, - ) -> dict: - cont: Any = self.dict - for k in key: - if k not in cont: - cont[k] = {} - cont = cont[k] - if access_lists and isinstance(cont, list): - cont = cont[-1] - if not isinstance(cont, dict): - raise KeyError("There is no nest behind this key") - return cont - - def append_nest_to_list(self, key: Key) -> None: - cont = self.get_or_create_nest(key[:-1]) - last_key = key[-1] - if last_key in cont: - list_ = cont[last_key] - if not isinstance(list_, list): - raise KeyError("An object other than list found behind this key") - list_.append({}) - else: - cont[last_key] = [{}] - - -class Output(NamedTuple): - data: NestedDict - flags: Flags - - -def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos: - try: - while src[pos] in chars: - pos += 1 - except IndexError: - pass - return pos - - -def skip_until( - src: str, - pos: Pos, - expect: str, - *, - error_on: frozenset[str], - error_on_eof: bool, -) -> Pos: - try: - new_pos = src.index(expect, pos) - except ValueError: - new_pos = len(src) - if error_on_eof: - raise suffixed_err(src, new_pos, f"Expected {expect!r}") from None - - if not error_on.isdisjoint(src[pos:new_pos]): - while src[pos] not in error_on: - pos += 1 - raise suffixed_err(src, pos, f"Found invalid character {src[pos]!r}") - return new_pos - - -def skip_comment(src: str, pos: Pos) -> Pos: - try: - char: str | None = src[pos] - except IndexError: - char = None - if char == "#": - return skip_until( - src, pos + 1, "\n", error_on=ILLEGAL_COMMENT_CHARS, error_on_eof=False - ) - return pos - - -def skip_comments_and_array_ws(src: str, pos: Pos) -> Pos: - while True: - pos_before_skip = pos - pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE) - pos = skip_comment(src, pos) - if pos == pos_before_skip: - return pos - - -def create_dict_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]: - pos += 1 # Skip "[" - pos = skip_chars(src, pos, TOML_WS) - pos, key = parse_key(src, pos) - - if out.flags.is_(key, Flags.EXPLICIT_NEST) or out.flags.is_(key, Flags.FROZEN): - raise suffixed_err(src, pos, f"Cannot declare {key} twice") - out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False) - try: - out.data.get_or_create_nest(key) - except KeyError: - raise suffixed_err(src, pos, "Cannot overwrite a value") from None - - if not src.startswith("]", pos): - raise suffixed_err(src, pos, "Expected ']' at the end of a table declaration") - return pos + 1, key - - -def create_list_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]: - pos += 2 # Skip "[[" - pos = skip_chars(src, pos, TOML_WS) - pos, key = parse_key(src, pos) - - if out.flags.is_(key, Flags.FROZEN): - raise suffixed_err(src, pos, f"Cannot mutate immutable namespace {key}") - # Free the namespace now that it points to another empty list item... - out.flags.unset_all(key) - # ...but this key precisely is still prohibited from table declaration - out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False) - try: - out.data.append_nest_to_list(key) - except KeyError: - raise suffixed_err(src, pos, "Cannot overwrite a value") from None - - if not src.startswith("]]", pos): - raise suffixed_err(src, pos, "Expected ']]' at the end of an array declaration") - return pos + 2, key - - -def key_value_rule( - src: str, pos: Pos, out: Output, header: Key, parse_float: ParseFloat -) -> Pos: - pos, key, value = parse_key_value_pair(src, pos, parse_float) - key_parent, key_stem = key[:-1], key[-1] - abs_key_parent = header + key_parent - - relative_path_cont_keys = (header + key[:i] for i in range(1, len(key))) - for cont_key in relative_path_cont_keys: - # Check that dotted key syntax does not redefine an existing table - if out.flags.is_(cont_key, Flags.EXPLICIT_NEST): - raise suffixed_err(src, pos, f"Cannot redefine namespace {cont_key}") - # Containers in the relative path can't be opened with the table syntax or - # dotted key/value syntax in following table sections. - out.flags.add_pending(cont_key, Flags.EXPLICIT_NEST) - - if out.flags.is_(abs_key_parent, Flags.FROZEN): - raise suffixed_err( - src, pos, f"Cannot mutate immutable namespace {abs_key_parent}" - ) - - try: - nest = out.data.get_or_create_nest(abs_key_parent) - except KeyError: - raise suffixed_err(src, pos, "Cannot overwrite a value") from None - if key_stem in nest: - raise suffixed_err(src, pos, "Cannot overwrite a value") - # Mark inline table and array namespaces recursively immutable - if isinstance(value, (dict, list)): - out.flags.set(header + key, Flags.FROZEN, recursive=True) - nest[key_stem] = value - return pos - - -def parse_key_value_pair( - src: str, pos: Pos, parse_float: ParseFloat -) -> tuple[Pos, Key, Any]: - pos, key = parse_key(src, pos) - try: - char: str | None = src[pos] - except IndexError: - char = None - if char != "=": - raise suffixed_err(src, pos, "Expected '=' after a key in a key/value pair") - pos += 1 - pos = skip_chars(src, pos, TOML_WS) - pos, value = parse_value(src, pos, parse_float) - return pos, key, value - - -def parse_key(src: str, pos: Pos) -> tuple[Pos, Key]: - pos, key_part = parse_key_part(src, pos) - key: Key = (key_part,) - pos = skip_chars(src, pos, TOML_WS) - while True: - try: - char: str | None = src[pos] - except IndexError: - char = None - if char != ".": - return pos, key - pos += 1 - pos = skip_chars(src, pos, TOML_WS) - pos, key_part = parse_key_part(src, pos) - key += (key_part,) - pos = skip_chars(src, pos, TOML_WS) - - -def parse_key_part(src: str, pos: Pos) -> tuple[Pos, str]: - try: - char: str | None = src[pos] - except IndexError: - char = None - if char in BARE_KEY_CHARS: - start_pos = pos - pos = skip_chars(src, pos, BARE_KEY_CHARS) - return pos, src[start_pos:pos] - if char == "'": - return parse_literal_str(src, pos) - if char == '"': - return parse_one_line_basic_str(src, pos) - raise suffixed_err(src, pos, "Invalid initial character for a key part") - - -def parse_one_line_basic_str(src: str, pos: Pos) -> tuple[Pos, str]: - pos += 1 - return parse_basic_str(src, pos, multiline=False) - - -def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> tuple[Pos, list]: - pos += 1 - array: list = [] - - pos = skip_comments_and_array_ws(src, pos) - if src.startswith("]", pos): - return pos + 1, array - while True: - pos, val = parse_value(src, pos, parse_float) - array.append(val) - pos = skip_comments_and_array_ws(src, pos) - - c = src[pos : pos + 1] - if c == "]": - return pos + 1, array - if c != ",": - raise suffixed_err(src, pos, "Unclosed array") - pos += 1 - - pos = skip_comments_and_array_ws(src, pos) - if src.startswith("]", pos): - return pos + 1, array - - -def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> tuple[Pos, dict]: - pos += 1 - nested_dict = NestedDict() - flags = Flags() - - pos = skip_chars(src, pos, TOML_WS) - if src.startswith("}", pos): - return pos + 1, nested_dict.dict - while True: - pos, key, value = parse_key_value_pair(src, pos, parse_float) - key_parent, key_stem = key[:-1], key[-1] - if flags.is_(key, Flags.FROZEN): - raise suffixed_err(src, pos, f"Cannot mutate immutable namespace {key}") - try: - nest = nested_dict.get_or_create_nest(key_parent, access_lists=False) - except KeyError: - raise suffixed_err(src, pos, "Cannot overwrite a value") from None - if key_stem in nest: - raise suffixed_err(src, pos, f"Duplicate inline table key {key_stem!r}") - nest[key_stem] = value - pos = skip_chars(src, pos, TOML_WS) - c = src[pos : pos + 1] - if c == "}": - return pos + 1, nested_dict.dict - if c != ",": - raise suffixed_err(src, pos, "Unclosed inline table") - if isinstance(value, (dict, list)): - flags.set(key, Flags.FROZEN, recursive=True) - pos += 1 - pos = skip_chars(src, pos, TOML_WS) - - -def parse_basic_str_escape( - src: str, pos: Pos, *, multiline: bool = False -) -> tuple[Pos, str]: - escape_id = src[pos : pos + 2] - pos += 2 - if multiline and escape_id in {"\\ ", "\\\t", "\\\n"}: - # Skip whitespace until next non-whitespace character or end of - # the doc. Error if non-whitespace is found before newline. - if escape_id != "\\\n": - pos = skip_chars(src, pos, TOML_WS) - try: - char = src[pos] - except IndexError: - return pos, "" - if char != "\n": - raise suffixed_err(src, pos, "Unescaped '\\' in a string") - pos += 1 - pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE) - return pos, "" - if escape_id == "\\u": - return parse_hex_char(src, pos, 4) - if escape_id == "\\U": - return parse_hex_char(src, pos, 8) - try: - return pos, BASIC_STR_ESCAPE_REPLACEMENTS[escape_id] - except KeyError: - raise suffixed_err(src, pos, "Unescaped '\\' in a string") from None - - -def parse_basic_str_escape_multiline(src: str, pos: Pos) -> tuple[Pos, str]: - return parse_basic_str_escape(src, pos, multiline=True) - - -def parse_hex_char(src: str, pos: Pos, hex_len: int) -> tuple[Pos, str]: - hex_str = src[pos : pos + hex_len] - if len(hex_str) != hex_len or not HEXDIGIT_CHARS.issuperset(hex_str): - raise suffixed_err(src, pos, "Invalid hex value") - pos += hex_len - hex_int = int(hex_str, 16) - if not is_unicode_scalar_value(hex_int): - raise suffixed_err(src, pos, "Escaped character is not a Unicode scalar value") - return pos, chr(hex_int) - - -def parse_literal_str(src: str, pos: Pos) -> tuple[Pos, str]: - pos += 1 # Skip starting apostrophe - start_pos = pos - pos = skip_until( - src, pos, "'", error_on=ILLEGAL_LITERAL_STR_CHARS, error_on_eof=True - ) - return pos + 1, src[start_pos:pos] # Skip ending apostrophe - - -def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> tuple[Pos, str]: - pos += 3 - if src.startswith("\n", pos): - pos += 1 - - if literal: - delim = "'" - end_pos = skip_until( - src, - pos, - "'''", - error_on=ILLEGAL_MULTILINE_LITERAL_STR_CHARS, - error_on_eof=True, - ) - result = src[pos:end_pos] - pos = end_pos + 3 - else: - delim = '"' - pos, result = parse_basic_str(src, pos, multiline=True) - - # Add at maximum two extra apostrophes/quotes if the end sequence - # is 4 or 5 chars long instead of just 3. - if not src.startswith(delim, pos): - return pos, result - pos += 1 - if not src.startswith(delim, pos): - return pos, result + delim - pos += 1 - return pos, result + (delim * 2) - - -def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> tuple[Pos, str]: - if multiline: - error_on = ILLEGAL_MULTILINE_BASIC_STR_CHARS - parse_escapes = parse_basic_str_escape_multiline - else: - error_on = ILLEGAL_BASIC_STR_CHARS - parse_escapes = parse_basic_str_escape - result = "" - start_pos = pos - while True: - try: - char = src[pos] - except IndexError: - raise suffixed_err(src, pos, "Unterminated string") from None - if char == '"': - if not multiline: - return pos + 1, result + src[start_pos:pos] - if src.startswith('"""', pos): - return pos + 3, result + src[start_pos:pos] - pos += 1 - continue - if char == "\\": - result += src[start_pos:pos] - pos, parsed_escape = parse_escapes(src, pos) - result += parsed_escape - start_pos = pos - continue - if char in error_on: - raise suffixed_err(src, pos, f"Illegal character {char!r}") - pos += 1 - - -def parse_value( # noqa: C901 - src: str, pos: Pos, parse_float: ParseFloat -) -> tuple[Pos, Any]: - try: - char: str | None = src[pos] - except IndexError: - char = None - - # IMPORTANT: order conditions based on speed of checking and likelihood - - # Basic strings - if char == '"': - if src.startswith('"""', pos): - return parse_multiline_str(src, pos, literal=False) - return parse_one_line_basic_str(src, pos) - - # Literal strings - if char == "'": - if src.startswith("'''", pos): - return parse_multiline_str(src, pos, literal=True) - return parse_literal_str(src, pos) - - # Booleans - if char == "t": - if src.startswith("true", pos): - return pos + 4, True - if char == "f": - if src.startswith("false", pos): - return pos + 5, False - - # Arrays - if char == "[": - return parse_array(src, pos, parse_float) - - # Inline tables - if char == "{": - return parse_inline_table(src, pos, parse_float) - - # Dates and times - datetime_match = RE_DATETIME.match(src, pos) - if datetime_match: - try: - datetime_obj = match_to_datetime(datetime_match) - except ValueError as e: - raise suffixed_err(src, pos, "Invalid date or datetime") from e - return datetime_match.end(), datetime_obj - localtime_match = RE_LOCALTIME.match(src, pos) - if localtime_match: - return localtime_match.end(), match_to_localtime(localtime_match) - - # Integers and "normal" floats. - # The regex will greedily match any type starting with a decimal - # char, so needs to be located after handling of dates and times. - number_match = RE_NUMBER.match(src, pos) - if number_match: - return number_match.end(), match_to_number(number_match, parse_float) - - # Special floats - first_three = src[pos : pos + 3] - if first_three in {"inf", "nan"}: - return pos + 3, parse_float(first_three) - first_four = src[pos : pos + 4] - if first_four in {"-inf", "+inf", "-nan", "+nan"}: - return pos + 4, parse_float(first_four) - - raise suffixed_err(src, pos, "Invalid value") - - -def suffixed_err(src: str, pos: Pos, msg: str) -> TOMLDecodeError: - """Return a `TOMLDecodeError` where error message is suffixed with - coordinates in source.""" - - def coord_repr(src: str, pos: Pos) -> str: - if pos >= len(src): - return "end of document" - line = src.count("\n", 0, pos) + 1 - if line == 1: - column = pos + 1 - else: - column = pos - src.rindex("\n", 0, pos) - return f"line {line}, column {column}" - - return TOMLDecodeError(f"{msg} (at {coord_repr(src, pos)})") - - -def is_unicode_scalar_value(codepoint: int) -> bool: - return (0 <= codepoint <= 55295) or (57344 <= codepoint <= 1114111) - - -def make_safe_parse_float(parse_float: ParseFloat) -> ParseFloat: - """A decorator to make `parse_float` safe. - - `parse_float` must not return dicts or lists, because these types - would be mixed with parsed TOML tables and arrays, thus confusing - the parser. The returned decorated callable raises `ValueError` - instead of returning illegal types. - """ - # The default `float` callable never returns illegal types. Optimize it. - if parse_float is float: # type: ignore[comparison-overlap] - return float - - def safe_parse_float(float_str: str) -> Any: - float_value = parse_float(float_str) - if isinstance(float_value, (dict, list)): - raise ValueError("parse_float must not return dicts or lists") - return float_value - - return safe_parse_float diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_re.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_re.py deleted file mode 100755 index 994bb74..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_re.py +++ /dev/null @@ -1,107 +0,0 @@ -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2021 Taneli Hukkinen -# Licensed to PSF under a Contributor Agreement. - -from __future__ import annotations - -from datetime import date, datetime, time, timedelta, timezone, tzinfo -from functools import lru_cache -import re -from typing import Any - -from ._types import ParseFloat - -# E.g. -# - 00:32:00.999999 -# - 00:32:00 -_TIME_RE_STR = r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?" - -RE_NUMBER = re.compile( - r""" -0 -(?: - x[0-9A-Fa-f](?:_?[0-9A-Fa-f])* # hex - | - b[01](?:_?[01])* # bin - | - o[0-7](?:_?[0-7])* # oct -) -| -[+-]?(?:0|[1-9](?:_?[0-9])*) # dec, integer part -(?P - (?:\.[0-9](?:_?[0-9])*)? # optional fractional part - (?:[eE][+-]?[0-9](?:_?[0-9])*)? # optional exponent part -) -""", - flags=re.VERBOSE, -) -RE_LOCALTIME = re.compile(_TIME_RE_STR) -RE_DATETIME = re.compile( - rf""" -([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) # date, e.g. 1988-10-27 -(?: - [Tt ] - {_TIME_RE_STR} - (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))? # optional time offset -)? -""", - flags=re.VERBOSE, -) - - -def match_to_datetime(match: re.Match) -> datetime | date: - """Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`. - - Raises ValueError if the match does not correspond to a valid date - or datetime. - """ - ( - year_str, - month_str, - day_str, - hour_str, - minute_str, - sec_str, - micros_str, - zulu_time, - offset_sign_str, - offset_hour_str, - offset_minute_str, - ) = match.groups() - year, month, day = int(year_str), int(month_str), int(day_str) - if hour_str is None: - return date(year, month, day) - hour, minute, sec = int(hour_str), int(minute_str), int(sec_str) - micros = int(micros_str.ljust(6, "0")) if micros_str else 0 - if offset_sign_str: - tz: tzinfo | None = cached_tz( - offset_hour_str, offset_minute_str, offset_sign_str - ) - elif zulu_time: - tz = timezone.utc - else: # local date-time - tz = None - return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz) - - -@lru_cache(maxsize=None) -def cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone: - sign = 1 if sign_str == "+" else -1 - return timezone( - timedelta( - hours=sign * int(hour_str), - minutes=sign * int(minute_str), - ) - ) - - -def match_to_localtime(match: re.Match) -> time: - hour_str, minute_str, sec_str, micros_str = match.groups() - micros = int(micros_str.ljust(6, "0")) if micros_str else 0 - return time(int(hour_str), int(minute_str), int(sec_str), micros) - - -def match_to_number(match: re.Match, parse_float: ParseFloat) -> Any: - if match.group("floatpart"): - return parse_float(match.group()) - return int(match.group(), 0) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_types.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_types.py deleted file mode 100755 index d949412..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_types.py +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2021 Taneli Hukkinen -# Licensed to PSF under a Contributor Agreement. - -from typing import Any, Callable, Tuple - -# Type annotations -ParseFloat = Callable[[str], Any] -Key = Tuple[str, ...] -Pos = int diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/typing_extensions.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/typing_extensions.py deleted file mode 100755 index 9f1c7aa..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/typing_extensions.py +++ /dev/null @@ -1,2296 +0,0 @@ -import abc -import collections -import collections.abc -import operator -import sys -import typing - -# After PEP 560, internal typing API was substantially reworked. -# This is especially important for Protocol class which uses internal APIs -# quite extensively. -PEP_560 = sys.version_info[:3] >= (3, 7, 0) - -if PEP_560: - GenericMeta = type -else: - # 3.6 - from typing import GenericMeta, _type_vars # noqa - -# The two functions below are copies of typing internal helpers. -# They are needed by _ProtocolMeta - - -def _no_slots_copy(dct): - dict_copy = dict(dct) - if '__slots__' in dict_copy: - for slot in dict_copy['__slots__']: - dict_copy.pop(slot, None) - return dict_copy - - -def _check_generic(cls, parameters): - if not cls.__parameters__: - raise TypeError(f"{cls} is not a generic class") - alen = len(parameters) - elen = len(cls.__parameters__) - if alen != elen: - raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};" - f" actual {alen}, expected {elen}") - - -# Please keep __all__ alphabetized within each category. -__all__ = [ - # Super-special typing primitives. - 'ClassVar', - 'Concatenate', - 'Final', - 'ParamSpec', - 'Self', - 'Type', - - # ABCs (from collections.abc). - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', - 'Coroutine', - 'AsyncGenerator', - 'AsyncContextManager', - 'ChainMap', - - # Concrete collection types. - 'ContextManager', - 'Counter', - 'Deque', - 'DefaultDict', - 'OrderedDict', - 'TypedDict', - - # Structural checks, a.k.a. protocols. - 'SupportsIndex', - - # One-off things. - 'Annotated', - 'final', - 'IntVar', - 'Literal', - 'NewType', - 'overload', - 'Protocol', - 'runtime', - 'runtime_checkable', - 'Text', - 'TypeAlias', - 'TypeGuard', - 'TYPE_CHECKING', -] - -if PEP_560: - __all__.extend(["get_args", "get_origin", "get_type_hints"]) - -# 3.6.2+ -if hasattr(typing, 'NoReturn'): - NoReturn = typing.NoReturn -# 3.6.0-3.6.1 -else: - class _NoReturn(typing._FinalTypingBase, _root=True): - """Special type indicating functions that never return. - Example:: - - from typing import NoReturn - - def stop() -> NoReturn: - raise Exception('no way') - - This type is invalid in other positions, e.g., ``List[NoReturn]`` - will fail in static type checkers. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("NoReturn cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("NoReturn cannot be used with issubclass().") - - NoReturn = _NoReturn(_root=True) - -# 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. - -ClassVar = typing.ClassVar - -# On older versions of typing there is an internal class named "Final". -# 3.8+ -if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): - Final = typing.Final -# 3.7 -elif sys.version_info[:2] >= (3, 7): - class _FinalForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only single type') - return typing._GenericAlias(self, (item,)) - - Final = _FinalForm('Final', - doc="""A special typing construct to indicate that a name - cannot be re-assigned or overridden in a subclass. - For example: - - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker - - class Connection: - TIMEOUT: Final[int] = 10 - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker - - There is no runtime checking of these properties.""") -# 3.6 -else: - class _Final(typing._FinalTypingBase, _root=True): - """A special typing construct to indicate that a name - cannot be re-assigned or overridden in a subclass. - For example: - - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker - - class Connection: - TIMEOUT: Final[int] = 10 - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker - - There is no runtime checking of these properties. - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - f'{cls.__name__[1:]} accepts only single type.'), - _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += f'[{typing._type_repr(self.__type__)}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _Final): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - Final = _Final(_root=True) - - -# 3.8+ -if hasattr(typing, 'final'): - final = typing.final -# 3.6-3.7 -else: - 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. - """ - return f - - -def IntVar(name): - return typing.TypeVar(name) - - -# 3.8+: -if hasattr(typing, 'Literal'): - Literal = typing.Literal -# 3.7: -elif sys.version_info[:2] >= (3, 7): - class _LiteralForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - return typing._GenericAlias(self, parameters) - - Literal = _LiteralForm('Literal', - 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.""") -# 3.6: -else: - class _Literal(typing._FinalTypingBase, _root=True): - """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. - """ - - __slots__ = ('__values__',) - - def __init__(self, values=None, **kwds): - self.__values__ = values - - def __getitem__(self, values): - cls = type(self) - if self.__values__ is None: - if not isinstance(values, tuple): - values = (values,) - return cls(values, _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - return self - - def __repr__(self): - r = super().__repr__() - if self.__values__ is not None: - r += f'[{", ".join(map(typing._type_repr, self.__values__))}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__values__)) - - def __eq__(self, other): - if not isinstance(other, _Literal): - return NotImplemented - if self.__values__ is not None: - return self.__values__ == other.__values__ - return self is other - - Literal = _Literal(_root=True) - - -_overload_dummy = typing._overload_dummy # noqa -overload = typing.overload - - -# 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. - - -class _ExtensionsGenericMeta(GenericMeta): - def __subclasscheck__(self, subclass): - """This mimics a more modern GenericMeta.__subclasscheck__() logic - (that does not have problems with recursion) to work around interactions - between collections, typing, and typing_extensions on older - versions of Python, see https://github.com/python/typing/issues/501. - """ - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if not self.__extra__: - return super().__subclasscheck__(subclass) - res = self.__extra__.__subclasshook__(subclass) - if res is not NotImplemented: - return res - if self.__extra__ in subclass.__mro__: - return True - for scls in self.__extra__.__subclasses__(): - if isinstance(scls, GenericMeta): - continue - if issubclass(subclass, scls): - return True - return False - - -Awaitable = typing.Awaitable -Coroutine = typing.Coroutine -AsyncIterable = typing.AsyncIterable -AsyncIterator = typing.AsyncIterator - -# 3.6.1+ -if hasattr(typing, 'Deque'): - Deque = typing.Deque -# 3.6.0 -else: - class Deque(collections.deque, typing.MutableSequence[T], - metaclass=_ExtensionsGenericMeta, - extra=collections.deque): - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Deque: - return collections.deque(*args, **kwds) - return typing._generic_new(collections.deque, cls, *args, **kwds) - -ContextManager = typing.ContextManager -# 3.6.2+ -if hasattr(typing, 'AsyncContextManager'): - AsyncContextManager = typing.AsyncContextManager -# 3.6.0-3.6.1 -else: - from _collections_abc import _check_methods as _check_methods_in_mro # noqa - - class AsyncContextManager(typing.Generic[T_co]): - __slots__ = () - - async def __aenter__(self): - return self - - @abc.abstractmethod - async def __aexit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is AsyncContextManager: - return _check_methods_in_mro(C, "__aenter__", "__aexit__") - return NotImplemented - -DefaultDict = typing.DefaultDict - -# 3.7.2+ -if hasattr(typing, 'OrderedDict'): - OrderedDict = typing.OrderedDict -# 3.7.0-3.7.2 -elif (3, 7, 0) <= sys.version_info[:3] < (3, 7, 2): - OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) -# 3.6 -else: - class OrderedDict(collections.OrderedDict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.OrderedDict): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is OrderedDict: - return collections.OrderedDict(*args, **kwds) - return typing._generic_new(collections.OrderedDict, cls, *args, **kwds) - -# 3.6.2+ -if hasattr(typing, 'Counter'): - Counter = typing.Counter -# 3.6.0-3.6.1 -else: - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_ExtensionsGenericMeta, extra=collections.Counter): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Counter: - return collections.Counter(*args, **kwds) - return typing._generic_new(collections.Counter, cls, *args, **kwds) - -# 3.6.1+ -if hasattr(typing, 'ChainMap'): - ChainMap = typing.ChainMap -elif hasattr(collections, 'ChainMap'): - class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.ChainMap): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is ChainMap: - return collections.ChainMap(*args, **kwds) - return typing._generic_new(collections.ChainMap, cls, *args, **kwds) - -# 3.6.1+ -if hasattr(typing, 'AsyncGenerator'): - AsyncGenerator = typing.AsyncGenerator -# 3.6.0 -else: - class AsyncGenerator(AsyncIterator[T_co], typing.Generic[T_co, T_contra], - metaclass=_ExtensionsGenericMeta, - extra=collections.abc.AsyncGenerator): - __slots__ = () - -NewType = typing.NewType -Text = typing.Text -TYPE_CHECKING = typing.TYPE_CHECKING - - -def _gorg(cls): - """This function exists for compatibility with old typing versions.""" - assert isinstance(cls, GenericMeta) - if hasattr(cls, '_gorg'): - return cls._gorg - while cls.__origin__ is not None: - cls = cls.__origin__ - return cls - - -_PROTO_WHITELIST = ['Callable', 'Awaitable', - 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', - 'ContextManager', 'AsyncContextManager'] - - -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 list(base.__dict__.keys()) + list(annotations.keys()): - if (not attr.startswith('_abc_') and attr not in ( - '__abstractmethods__', '__annotations__', '__weakref__', - '_is_protocol', '_is_runtime_protocol', '__dict__', - '__args__', '__slots__', - '__next_in_mro__', '__parameters__', '__origin__', - '__orig_bases__', '__extra__', '__tree_hash__', - '__doc__', '__subclasshook__', '__init__', '__new__', - '__module__', '_MutableMapping__marker', '_gorg')): - attrs.add(attr) - return attrs - - -def _is_callable_members_only(cls): - return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) - - -# 3.8+ -if hasattr(typing, 'Protocol'): - Protocol = typing.Protocol -# 3.7 -elif PEP_560: - from typing import _collect_type_vars # noqa - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - class _ProtocolMeta(abc.ABCMeta): - # This metaclass is a bit unfortunate and exists only because of the lack - # of __instancehook__. - def __instancecheck__(cls, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if ((not getattr(cls, '_is_protocol', False) or - _is_callable_members_only(cls)) and - issubclass(instance.__class__, cls)): - return True - if cls._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(cls, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(cls)): - return True - return super().__instancecheck__(instance) - - class Protocol(metaclass=_ProtocolMeta): - # There is quite a lot of overlapping code with typing.Generic. - # Unfortunately it is hard to avoid this while these live in two different - # modules. The duplicated code will be removed when Protocol is moved to typing. - """Base class for protocol classes. Protocol classes are defined as:: - - class Proto(Protocol): - def meth(self) -> int: - ... - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self) -> int: - return 0 - - def func(x: Proto) -> int: - return x.meth() - - func(C()) # Passes static type check - - See PEP 544 for details. Protocol classes decorated with - @typing_extensions.runtime act as simple-minded runtime protocol that checks - only the presence of given attributes, ignoring their type signatures. - - Protocol classes can be generic, they are defined as:: - - class GenProto(Protocol[T]): - def meth(self) -> T: - ... - """ - __slots__ = () - _is_protocol = True - - def __new__(cls, *args, **kwds): - if cls is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can only be used as a base class") - return super().__new__(cls) - - @typing._tp_cache - def __class_getitem__(cls, params): - if not isinstance(params, tuple): - params = (params,) - if not params and cls is not typing.Tuple: - raise TypeError( - f"Parameter list to {cls.__qualname__}[...] cannot be empty") - msg = "Parameters to generic types must be types." - params = tuple(typing._type_check(p, msg) for p in params) # noqa - if cls is Protocol: - # Generic can only be subscripted with unique type variables. - if not all(isinstance(p, typing.TypeVar) for p in params): - i = 0 - while isinstance(params[i], typing.TypeVar): - i += 1 - raise TypeError( - "Parameters to Protocol[...] must all be type variables." - f" Parameter {i + 1} is {params[i]}") - if len(set(params)) != len(params): - raise TypeError( - "Parameters to Protocol[...] must all be unique") - else: - # Subscripting a regular Generic subclass. - _check_generic(cls, params) - return typing._GenericAlias(cls, params) - - def __init_subclass__(cls, *args, **kwargs): - tvars = [] - if '__orig_bases__' in cls.__dict__: - error = typing.Generic in cls.__orig_bases__ - else: - error = typing.Generic in cls.__bases__ - if error: - raise TypeError("Cannot inherit from plain Generic") - if '__orig_bases__' in cls.__dict__: - tvars = _collect_type_vars(cls.__orig_bases__) - # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. - # If found, tvars must be a subset of it. - # If not found, tvars is it. - # Also check for and reject plain Generic, - # and reject multiple Generic[...] and/or Protocol[...]. - gvars = None - for base in cls.__orig_bases__: - if (isinstance(base, typing._GenericAlias) and - base.__origin__ in (typing.Generic, Protocol)): - # for error messages - the_base = base.__origin__.__name__ - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...]" - " and/or Protocol[...] multiple types.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) - s_args = ', '.join(str(g) for g in gvars) - raise TypeError(f"Some type variables ({s_vars}) are" - f" not listed in {the_base}[{s_args}]") - tvars = gvars - cls.__parameters__ = tuple(tvars) - - # Determine if this is a protocol or a concrete subclass. - if not cls.__dict__.get('_is_protocol', None): - cls._is_protocol = any(b is Protocol for b in cls.__bases__) - - # Set (or override) the protocol subclass hook. - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): - return NotImplemented - if not getattr(cls, '_is_runtime_protocol', False): - if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: - return NotImplemented - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") - if not _is_callable_members_only(cls): - if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: - return NotImplemented - raise TypeError("Protocols with non-method members" - " don't support issubclass()") - if not isinstance(other, type): - # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') - for attr in _get_protocol_attrs(cls): - for base in other.__mro__: - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - # We have nothing more to do for non-protocols. - if not cls._is_protocol: - return - - # Check consistency of bases. - for base in cls.__bases__: - if not (base in (object, typing.Generic) or - base.__module__ == 'collections.abc' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, _ProtocolMeta) and base._is_protocol): - raise TypeError('Protocols can only inherit from other' - f' protocols, got {repr(base)}') - cls.__init__ = _no_init -# 3.6 -else: - from typing import _next_in_mro, _type_check # noqa - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - class _ProtocolMeta(GenericMeta): - """Internal metaclass for Protocol. - - This exists so Protocol classes can be generic without deriving - from Generic. - """ - def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None, orig_bases=None): - # This is just a version copied from GenericMeta.__new__ that - # includes "Protocol" special treatment. (Comments removed for brevity.) - assert extra is None # Protocols should not have extra - if tvars is not None: - assert origin is not None - assert all(isinstance(t, typing.TypeVar) for t in tvars), tvars - else: - tvars = _type_vars(bases) - gvars = None - for base in bases: - if base is typing.Generic: - raise TypeError("Cannot inherit from plain Generic") - if (isinstance(base, GenericMeta) and - base.__origin__ in (typing.Generic, Protocol)): - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...] or" - " Protocol[...] multiple times.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - s_vars = ", ".join(str(t) for t in tvars if t not in gvarset) - s_args = ", ".join(str(g) for g in gvars) - cls_name = "Generic" if any(b.__origin__ is typing.Generic - for b in bases) else "Protocol" - raise TypeError(f"Some type variables ({s_vars}) are" - f" not listed in {cls_name}[{s_args}]") - tvars = gvars - - initial_bases = bases - if (extra is not None and type(extra) is abc.ABCMeta and - extra not in bases): - bases = (extra,) + bases - bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b - for b in bases) - if any(isinstance(b, GenericMeta) and b is not typing.Generic for b in bases): - bases = tuple(b for b in bases if b is not typing.Generic) - namespace.update({'__origin__': origin, '__extra__': extra}) - self = super(GenericMeta, cls).__new__(cls, name, bases, namespace, - _root=True) - super(GenericMeta, self).__setattr__('_gorg', - self if not origin else - _gorg(origin)) - self.__parameters__ = tvars - self.__args__ = tuple(... if a is typing._TypingEllipsis else - () if a is typing._TypingEmpty else - a for a in args) if args else None - self.__next_in_mro__ = _next_in_mro(self) - if orig_bases is None: - self.__orig_bases__ = initial_bases - elif origin is not None: - self._abc_registry = origin._abc_registry - self._abc_cache = origin._abc_cache - if hasattr(self, '_subs_tree'): - self.__tree_hash__ = (hash(self._subs_tree()) if origin else - super(GenericMeta, self).__hash__()) - return self - - def __init__(cls, *args, **kwargs): - super().__init__(*args, **kwargs) - if not cls.__dict__.get('_is_protocol', None): - cls._is_protocol = any(b is Protocol or - isinstance(b, _ProtocolMeta) and - b.__origin__ is Protocol - for b in cls.__bases__) - if cls._is_protocol: - for base in cls.__mro__[1:]: - if not (base in (object, typing.Generic) or - base.__module__ == 'collections.abc' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, typing.TypingMeta) and base._is_protocol or - isinstance(base, GenericMeta) and - base.__origin__ is typing.Generic): - raise TypeError(f'Protocols can only inherit from other' - f' protocols, got {repr(base)}') - - cls.__init__ = _no_init - - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): - return NotImplemented - if not isinstance(other, type): - # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') - for attr in _get_protocol_attrs(cls): - for base in other.__mro__: - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - def __instancecheck__(self, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if ((not getattr(self, '_is_protocol', False) or - _is_callable_members_only(self)) and - issubclass(instance.__class__, self)): - return True - if self._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(self, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(self)): - return True - return super(GenericMeta, self).__instancecheck__(instance) - - def __subclasscheck__(self, cls): - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if (self.__dict__.get('_is_protocol', None) and - not self.__dict__.get('_is_runtime_protocol', None)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: - return False - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") - if (self.__dict__.get('_is_runtime_protocol', None) and - not _is_callable_members_only(self)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: - return super(GenericMeta, self).__subclasscheck__(cls) - raise TypeError("Protocols with non-method members" - " don't support issubclass()") - return super(GenericMeta, self).__subclasscheck__(cls) - - @typing._tp_cache - def __getitem__(self, params): - # We also need to copy this from GenericMeta.__getitem__ to get - # special treatment of "Protocol". (Comments removed for brevity.) - if not isinstance(params, tuple): - params = (params,) - if not params and _gorg(self) is not typing.Tuple: - raise TypeError( - f"Parameter list to {self.__qualname__}[...] cannot be empty") - msg = "Parameters to generic types must be types." - params = tuple(_type_check(p, msg) for p in params) - if self in (typing.Generic, Protocol): - if not all(isinstance(p, typing.TypeVar) for p in params): - raise TypeError( - f"Parameters to {repr(self)}[...] must all be type variables") - if len(set(params)) != len(params): - raise TypeError( - f"Parameters to {repr(self)}[...] must all be unique") - tvars = params - args = params - elif self in (typing.Tuple, typing.Callable): - tvars = _type_vars(params) - args = params - elif self.__origin__ in (typing.Generic, Protocol): - raise TypeError(f"Cannot subscript already-subscripted {repr(self)}") - else: - _check_generic(self, params) - tvars = _type_vars(params) - args = params - - prepend = (self,) if self.__origin__ is None else () - return self.__class__(self.__name__, - prepend + self.__bases__, - _no_slots_copy(self.__dict__), - tvars=tvars, - args=args, - origin=self, - extra=self.__extra__, - orig_bases=self.__orig_bases__) - - class Protocol(metaclass=_ProtocolMeta): - """Base class for protocol classes. Protocol classes are defined as:: - - class Proto(Protocol): - def meth(self) -> int: - ... - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self) -> int: - return 0 - - def func(x: Proto) -> int: - return x.meth() - - func(C()) # Passes static type check - - See PEP 544 for details. Protocol classes decorated with - @typing_extensions.runtime act as simple-minded runtime protocol that checks - only the presence of given attributes, ignoring their type signatures. - - Protocol classes can be generic, they are defined as:: - - class GenProto(Protocol[T]): - def meth(self) -> T: - ... - """ - __slots__ = () - _is_protocol = True - - def __new__(cls, *args, **kwds): - if _gorg(cls) is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can be used only as a base class") - return typing._generic_new(cls.__next_in_mro__, cls, *args, **kwds) - - -# 3.8+ -if hasattr(typing, 'runtime_checkable'): - runtime_checkable = typing.runtime_checkable -# 3.6-3.7 -else: - def runtime_checkable(cls): - """Mark a protocol class as a runtime protocol, so that it - 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 the - one-offs in collections.abc such as Hashable. - """ - if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: - raise TypeError('@runtime_checkable can be only applied to protocol classes,' - f' got {cls!r}') - cls._is_runtime_protocol = True - return cls - - -# Exists for backwards compatibility. -runtime = runtime_checkable - - -# 3.8+ -if hasattr(typing, 'SupportsIndex'): - SupportsIndex = typing.SupportsIndex -# 3.6-3.7 -else: - @runtime_checkable - class SupportsIndex(Protocol): - __slots__ = () - - @abc.abstractmethod - def __index__(self) -> int: - pass - - -if sys.version_info >= (3, 9, 2): - # The standard library TypedDict in Python 3.8 does not store runtime information - # about which (if any) keys are optional. See https://bugs.python.org/issue38834 - # 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 - TypedDict = typing.TypedDict -else: - def _check_fails(cls, other): - try: - if sys._getframe(1).f_globals['__name__'] not in ['abc', - 'functools', - 'typing']: - # Typed dicts are only for static structural subtyping. - raise TypeError('TypedDict does not support instance and class checks') - except (AttributeError, ValueError): - pass - return False - - def _dict_new(*args, **kwargs): - if not args: - raise TypeError('TypedDict.__new__(): not enough arguments') - _, args = args[0], args[1:] # allow the "cls" keyword be passed - return dict(*args, **kwargs) - - _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' - - def _typeddict_new(*args, total=True, **kwargs): - if not args: - raise TypeError('TypedDict.__new__(): not enough arguments') - _, args = args[0], args[1:] # allow the "cls" keyword be passed - if args: - typename, args = args[0], args[1:] # allow the "_typename" keyword be passed - elif '_typename' in kwargs: - typename = kwargs.pop('_typename') - import warnings - warnings.warn("Passing '_typename' as keyword argument is deprecated", - DeprecationWarning, stacklevel=2) - else: - raise TypeError("TypedDict.__new__() missing 1 required positional " - "argument: '_typename'") - if args: - try: - fields, = args # allow the "_fields" keyword be passed - except ValueError: - raise TypeError('TypedDict.__new__() takes from 2 to 3 ' - f'positional arguments but {len(args) + 2} ' - 'were given') - elif '_fields' in kwargs and len(kwargs) == 1: - fields = kwargs.pop('_fields') - import warnings - warnings.warn("Passing '_fields' as keyword argument is deprecated", - DeprecationWarning, stacklevel=2) - else: - fields = None - - if fields is None: - fields = kwargs - elif kwargs: - raise TypeError("TypedDict takes either a dict or keyword arguments," - " but not both") - - ns = {'__annotations__': dict(fields)} - try: - # Setting correct module is necessary to make typed dict classes pickleable. - ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - pass - - return _TypedDictMeta(typename, (), ns, total=total) - - _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' - ' /, *, total=True, **kwargs)') - - class _TypedDictMeta(type): - def __init__(cls, name, bases, ns, total=True): - super().__init__(name, bases, ns) - - def __new__(cls, name, bases, ns, total=True): - # Create new typed dict class object. - # This method is called directly when TypedDict is subclassed, - # or via _typeddict_new when TypedDict is instantiated. This way - # TypedDict supports all three syntaxes described in its docstring. - # Subclasses and instances of TypedDict return actual dictionaries - # via _dict_new. - ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new - tp_dict = super().__new__(cls, name, (dict,), ns) - - annotations = {} - own_annotations = ns.get('__annotations__', {}) - own_annotation_keys = set(own_annotations.keys()) - msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" - own_annotations = { - n: typing._type_check(tp, msg) for n, tp in own_annotations.items() - } - required_keys = set() - optional_keys = set() - - for base in bases: - annotations.update(base.__dict__.get('__annotations__', {})) - required_keys.update(base.__dict__.get('__required_keys__', ())) - optional_keys.update(base.__dict__.get('__optional_keys__', ())) - - annotations.update(own_annotations) - if total: - required_keys.update(own_annotation_keys) - else: - optional_keys.update(own_annotation_keys) - - tp_dict.__annotations__ = annotations - tp_dict.__required_keys__ = frozenset(required_keys) - tp_dict.__optional_keys__ = frozenset(optional_keys) - if not hasattr(tp_dict, '__total__'): - tp_dict.__total__ = total - return tp_dict - - __instancecheck__ = __subclasscheck__ = _check_fails - - TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) - TypedDict.__module__ = __name__ - TypedDict.__doc__ = \ - """A simple typed name space. At runtime it is equivalent to a plain dict. - - TypedDict creates a dictionary type that expects all of its - instances to have a certain set of keys, with each key - associated with a value of a consistent type. This expectation - is not checked at runtime but is only enforced by type checkers. - 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 two additional equivalent forms:: - - Point2D = TypedDict('Point2D', x=int, y=int, label=str) - Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) - - The class syntax is only supported in Python 3.6+, while two other - syntax forms work for Python 2.7 and 3.2+ - """ - - -# Python 3.9+ has PEP 593 (Annotated and modified get_type_hints) -if hasattr(typing, 'Annotated'): - Annotated = typing.Annotated - get_type_hints = typing.get_type_hints - # Not exported and not a public API, but needed for get_origin() and get_args() - # to work. - _AnnotatedAlias = typing._AnnotatedAlias -# 3.7-3.8 -elif PEP_560: - class _AnnotatedAlias(typing._GenericAlias, _root=True): - """Runtime representation of an annotated type. - - At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' - with extra annotations. The alias behaves like a normal typing alias, - instantiating is the same as instantiating the underlying type, binding - it to types is also the same. - """ - def __init__(self, origin, metadata): - if isinstance(origin, _AnnotatedAlias): - metadata = origin.__metadata__ + metadata - origin = origin.__origin__ - super().__init__(origin, origin) - self.__metadata__ = metadata - - def copy_with(self, params): - assert len(params) == 1 - new_type = params[0] - return _AnnotatedAlias(new_type, self.__metadata__) - - def __repr__(self): - return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " - f"{', '.join(repr(a) for a in self.__metadata__)}]") - - def __reduce__(self): - return operator.getitem, ( - Annotated, (self.__origin__,) + self.__metadata__ - ) - - def __eq__(self, other): - if not isinstance(other, _AnnotatedAlias): - return NotImplemented - if self.__origin__ != other.__origin__: - return False - return self.__metadata__ == other.__metadata__ - - def __hash__(self): - return hash((self.__origin__, self.__metadata__)) - - class Annotated: - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type (and will be in - the __origin__ field), the remaining arguments are kept as a tuple in - the __extra__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ - - __slots__ = () - - def __new__(cls, *args, **kwargs): - raise TypeError("Type Annotated cannot be instantiated.") - - @typing._tp_cache - def __class_getitem__(cls, params): - if not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be used " - "with at least two arguments (a type and an " - "annotation).") - msg = "Annotated[t, ...]: t must be a type." - origin = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return _AnnotatedAlias(origin, metadata) - - def __init_subclass__(cls, *args, **kwargs): - raise TypeError( - f"Cannot subclass {cls.__module__}.Annotated" - ) - - def _strip_annotations(t): - """Strips the annotations from a given type. - """ - if isinstance(t, _AnnotatedAlias): - return _strip_annotations(t.__origin__) - if isinstance(t, typing._GenericAlias): - stripped_args = tuple(_strip_annotations(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - res = t.copy_with(stripped_args) - res._special = t._special - return res - 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, ...]' 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) - if include_extras: - return hint - return {k: _strip_annotations(t) for k, t in hint.items()} -# 3.6 -else: - - def _is_dunder(name): - """Returns True if name is a __dunder_variable_name__.""" - return len(name) > 4 and name.startswith('__') and name.endswith('__') - - # Prior to Python 3.7 types did not have `copy_with`. A lot of the equality - # checks, argument expansion etc. are done on the _subs_tre. As a result we - # can't provide a get_type_hints function that strips out annotations. - - class AnnotatedMeta(typing.GenericMeta): - """Metaclass for Annotated""" - - def __new__(cls, name, bases, namespace, **kwargs): - if any(b is not object for b in bases): - raise TypeError("Cannot subclass " + str(Annotated)) - return super().__new__(cls, name, bases, namespace, **kwargs) - - @property - def __metadata__(self): - return self._subs_tree()[2] - - def _tree_repr(self, tree): - cls, origin, metadata = tree - if not isinstance(origin, tuple): - tp_repr = typing._type_repr(origin) - else: - tp_repr = origin[0]._tree_repr(origin) - metadata_reprs = ", ".join(repr(arg) for arg in metadata) - return f'{cls}[{tp_repr}, {metadata_reprs}]' - - def _subs_tree(self, tvars=None, args=None): # noqa - if self is Annotated: - return Annotated - res = super()._subs_tree(tvars=tvars, args=args) - # Flatten nested Annotated - if isinstance(res[1], tuple) and res[1][0] is Annotated: - sub_tp = res[1][1] - sub_annot = res[1][2] - return (Annotated, sub_tp, sub_annot + res[2]) - return res - - def _get_cons(self): - """Return the class used to create instance of this type.""" - if self.__origin__ is None: - raise TypeError("Cannot get the underlying type of a " - "non-specialized Annotated type.") - tree = self._subs_tree() - while isinstance(tree, tuple) and tree[0] is Annotated: - tree = tree[1] - if isinstance(tree, tuple): - return tree[0] - else: - return tree - - @typing._tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - if self.__origin__ is not None: # specializing an instantiated type - return super().__getitem__(params) - elif not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be instantiated " - "with at least two arguments (a type and an " - "annotation).") - else: - msg = "Annotated[t, ...]: t must be a type." - tp = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return self.__class__( - self.__name__, - self.__bases__, - _no_slots_copy(self.__dict__), - tvars=_type_vars((tp,)), - # Metadata is a tuple so it won't be touched by _replace_args et al. - args=(tp, metadata), - origin=self, - ) - - def __call__(self, *args, **kwargs): - cons = self._get_cons() - result = cons(*args, **kwargs) - try: - result.__orig_class__ = self - except AttributeError: - pass - return result - - def __getattr__(self, attr): - # For simplicity we just don't relay all dunder names - if self.__origin__ is not None and not _is_dunder(attr): - return getattr(self._get_cons(), attr) - raise AttributeError(attr) - - def __setattr__(self, attr, value): - if _is_dunder(attr) or attr.startswith('_abc_'): - super().__setattr__(attr, value) - elif self.__origin__ is None: - raise AttributeError(attr) - else: - setattr(self._get_cons(), attr, value) - - def __instancecheck__(self, obj): - raise TypeError("Annotated cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Annotated cannot be used with issubclass().") - - class Annotated(metaclass=AnnotatedMeta): - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type, the remaining - arguments are kept as a tuple in the __metadata__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ - -# Python 3.8 has get_origin() and get_args() but those implementations aren't -# Annotated-aware, so we can't use those. Python 3.9's versions don't support -# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. -if sys.version_info[:2] >= (3, 10): - get_origin = typing.get_origin - get_args = typing.get_args -# 3.7-3.9 -elif PEP_560: - try: - # 3.9+ - from typing import _BaseGenericAlias - except ImportError: - _BaseGenericAlias = typing._GenericAlias - try: - # 3.9+ - from typing import GenericAlias - except ImportError: - GenericAlias = typing._GenericAlias - - 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, _AnnotatedAlias): - return Annotated - if isinstance(tp, (typing._GenericAlias, GenericAlias, _BaseGenericAlias, - 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, _AnnotatedAlias): - return (tp.__origin__,) + tp.__metadata__ - if isinstance(tp, (typing._GenericAlias, GenericAlias)): - if getattr(tp, "_special", False): - return () - 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 -elif sys.version_info[:2] >= (3, 9): - class _TypeAliasForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_TypeAliasForm - 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") -# 3.7-3.8 -elif sys.version_info[:2] >= (3, 7): - class _TypeAliasForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - TypeAlias = _TypeAliasForm('TypeAlias', - doc="""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.""") -# 3.6 -else: - class _TypeAliasMeta(typing.TypingMeta): - """Metaclass for TypeAlias""" - - def __repr__(self): - return 'typing_extensions.TypeAlias' - - class _TypeAliasBase(typing._FinalTypingBase, metaclass=_TypeAliasMeta, _root=True): - """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. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("TypeAlias cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("TypeAlias cannot be used with issubclass().") - - def __repr__(self): - return 'typing_extensions.TypeAlias' - - TypeAlias = _TypeAliasBase(_root=True) - - -# Python 3.10+ has PEP 612 -if hasattr(typing, 'ParamSpecArgs'): - ParamSpecArgs = typing.ParamSpecArgs - ParamSpecKwargs = typing.ParamSpecKwargs -# 3.6-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" - - 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" - -# 3.10+ -if hasattr(typing, 'ParamSpec'): - ParamSpec = typing.ParamSpec -# 3.6-3.9 -else: - - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class ParamSpec(list): - """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): - super().__init__([self]) - self.__name__ = name - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - if bound: - self.__bound__ = typing._type_check(bound, 'Bound must be a type.') - else: - self.__bound__ = None - - # for pickling: - try: - def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - def_mod = None - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __repr__(self): - if 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 - - if not PEP_560: - # Only needed in 3.6. - def _get_type_vars(self, tvars): - if self not in tvars: - tvars.append(self) - - -# 3.6-3.9 -if not hasattr(typing, 'Concatenate'): - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class _ConcatenateGenericAlias(list): - - # Trick Generic into looking into this for __parameters__. - if PEP_560: - __class__ = typing._GenericAlias - else: - __class__ = typing._TypingBase - - # Flag in 3.8. - _special = False - # Attribute in 3.6 and earlier. - _gorg = typing.Generic - - def __init__(self, origin, args): - super().__init__(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)) - ) - - if not PEP_560: - # Only required in 3.6. - def _get_type_vars(self, tvars): - if self.__origin__ and self.__parameters__: - typing._get_type_vars(self.__parameters__, tvars) - - -# 3.6-3.9 -@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 isinstance(parameters[-1], ParamSpec): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable.") - msg = "Concatenate[arg, ...]: each arg must be a type." - parameters = tuple(typing._type_check(p, msg) for p in parameters) - return _ConcatenateGenericAlias(self, parameters) - - -# 3.10+ -if hasattr(typing, 'Concatenate'): - Concatenate = typing.Concatenate - _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa -# 3.9 -elif sys.version_info[:2] >= (3, 9): - @_TypeAliasForm - 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.7-8 -elif sys.version_info[:2] >= (3, 7): - class _ConcatenateForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - Concatenate = _ConcatenateForm( - 'Concatenate', - doc="""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. - """) -# 3.6 -else: - class _ConcatenateAliasMeta(typing.TypingMeta): - """Metaclass for Concatenate.""" - - def __repr__(self): - return 'typing_extensions.Concatenate' - - class _ConcatenateAliasBase(typing._FinalTypingBase, - metaclass=_ConcatenateAliasMeta, - _root=True): - """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. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("Concatenate cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Concatenate cannot be used with issubclass().") - - def __repr__(self): - return 'typing_extensions.Concatenate' - - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - Concatenate = _ConcatenateAliasBase(_root=True) - -# 3.10+ -if hasattr(typing, 'TypeGuard'): - TypeGuard = typing.TypeGuard -# 3.9 -elif sys.version_info[:2] >= (3, 9): - class _TypeGuardForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_TypeGuardForm - 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 single type.') - return typing._GenericAlias(self, (item,)) -# 3.7-3.8 -elif sys.version_info[:2] >= (3, 7): - class _TypeGuardForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type') - return typing._GenericAlias(self, (item,)) - - TypeGuard = _TypeGuardForm( - 'TypeGuard', - doc="""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). - """) -# 3.6 -else: - class _TypeGuard(typing._FinalTypingBase, _root=True): - """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). - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - f'{cls.__name__[1:]} accepts only a single type.'), - _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += f'[{typing._type_repr(self.__type__)}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _TypeGuard): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - TypeGuard = _TypeGuard(_root=True) - -if hasattr(typing, "Self"): - Self = typing.Self -elif sys.version_info[:2] >= (3, 7): - # Vendored from cpython typing._SpecialFrom - 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) - - @_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") -else: - class _Self(typing._FinalTypingBase, _root=True): - """Used to spell the type of "self" in classes. - - Example:: - - from typing import Self - - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self - - """ - - __slots__ = () - - 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().") - - Self = _Self(_root=True) - - -if hasattr(typing, 'Required'): - Required = typing.Required - NotRequired = typing.NotRequired -elif sys.version_info[:2] >= (3, 9): - class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_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 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 single type') - return typing._GenericAlias(self, (item,)) - -elif sys.version_info[:2] >= (3, 7): - class _RequiredForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - '{} accepts only single type'.format(self._name)) - return typing._GenericAlias(self, (item,)) - - Required = _RequiredForm( - 'Required', - doc="""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. - """) - NotRequired = _RequiredForm( - 'NotRequired', - doc="""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, - ) - """) -else: - # NOTE: Modeled after _Final's implementation when _FinalTypingBase available - class _MaybeRequired(typing._FinalTypingBase, _root=True): - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, type(self)): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - class _Required(_MaybeRequired, _root=True): - """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. - """ - - class _NotRequired(_MaybeRequired, _root=True): - """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, - ) - """ - - Required = _Required(_root=True) - NotRequired = _NotRequired(_root=True) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/zipp.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/zipp.py deleted file mode 100755 index 26b723c..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/zipp.py +++ /dev/null @@ -1,329 +0,0 @@ -import io -import posixpath -import zipfile -import itertools -import contextlib -import sys -import pathlib - -if sys.version_info < (3, 7): - from collections import OrderedDict -else: - OrderedDict = dict - - -__all__ = ['Path'] - - -def _parents(path): - """ - Given a path with elements separated by - posixpath.sep, generate all parents of that path. - - >>> list(_parents('b/d')) - ['b'] - >>> list(_parents('/b/d/')) - ['/b'] - >>> list(_parents('b/d/f/')) - ['b/d', 'b'] - >>> list(_parents('b')) - [] - >>> list(_parents('')) - [] - """ - return itertools.islice(_ancestry(path), 1, None) - - -def _ancestry(path): - """ - Given a path with elements separated by - posixpath.sep, generate all elements of that path - - >>> list(_ancestry('b/d')) - ['b/d', 'b'] - >>> list(_ancestry('/b/d/')) - ['/b/d', '/b'] - >>> list(_ancestry('b/d/f/')) - ['b/d/f', 'b/d', 'b'] - >>> list(_ancestry('b')) - ['b'] - >>> list(_ancestry('')) - [] - """ - path = path.rstrip(posixpath.sep) - while path and path != posixpath.sep: - yield path - path, tail = posixpath.split(path) - - -_dedupe = OrderedDict.fromkeys -"""Deduplicate an iterable in original order""" - - -def _difference(minuend, subtrahend): - """ - Return items in minuend not in subtrahend, retaining order - with O(1) lookup. - """ - return itertools.filterfalse(set(subtrahend).__contains__, minuend) - - -class CompleteDirs(zipfile.ZipFile): - """ - A ZipFile subclass that ensures that implied directories - are always included in the namelist. - """ - - @staticmethod - def _implied_dirs(names): - parents = itertools.chain.from_iterable(map(_parents, names)) - as_dirs = (p + posixpath.sep for p in parents) - return _dedupe(_difference(as_dirs, names)) - - def namelist(self): - names = super(CompleteDirs, self).namelist() - return names + list(self._implied_dirs(names)) - - def _name_set(self): - return set(self.namelist()) - - def resolve_dir(self, name): - """ - If the name represents a directory, return that name - as a directory (with the trailing slash). - """ - names = self._name_set() - dirname = name + '/' - dir_match = name not in names and dirname in names - return dirname if dir_match else name - - @classmethod - def make(cls, source): - """ - Given a source (filename or zipfile), return an - appropriate CompleteDirs subclass. - """ - if isinstance(source, CompleteDirs): - return source - - if not isinstance(source, zipfile.ZipFile): - return cls(_pathlib_compat(source)) - - # Only allow for FastLookup when supplied zipfile is read-only - if 'r' not in source.mode: - cls = CompleteDirs - - source.__class__ = cls - return source - - -class FastLookup(CompleteDirs): - """ - ZipFile subclass to ensure implicit - dirs exist and are resolved rapidly. - """ - - def namelist(self): - with contextlib.suppress(AttributeError): - return self.__names - self.__names = super(FastLookup, self).namelist() - return self.__names - - def _name_set(self): - with contextlib.suppress(AttributeError): - return self.__lookup - self.__lookup = super(FastLookup, self)._name_set() - return self.__lookup - - -def _pathlib_compat(path): - """ - For path-like objects, convert to a filename for compatibility - on Python 3.6.1 and earlier. - """ - try: - return path.__fspath__() - except AttributeError: - return str(path) - - -class Path: - """ - A pathlib-compatible interface for zip files. - - Consider a zip file with this structure:: - - . - ├── a.txt - └── b - ├── c.txt - └── d - └── e.txt - - >>> data = io.BytesIO() - >>> zf = zipfile.ZipFile(data, 'w') - >>> zf.writestr('a.txt', 'content of a') - >>> zf.writestr('b/c.txt', 'content of c') - >>> zf.writestr('b/d/e.txt', 'content of e') - >>> zf.filename = 'mem/abcde.zip' - - Path accepts the zipfile object itself or a filename - - >>> root = Path(zf) - - From there, several path operations are available. - - Directory iteration (including the zip file itself): - - >>> a, b = root.iterdir() - >>> a - Path('mem/abcde.zip', 'a.txt') - >>> b - Path('mem/abcde.zip', 'b/') - - name property: - - >>> b.name - 'b' - - join with divide operator: - - >>> c = b / 'c.txt' - >>> c - Path('mem/abcde.zip', 'b/c.txt') - >>> c.name - 'c.txt' - - Read text: - - >>> c.read_text() - 'content of c' - - existence: - - >>> c.exists() - True - >>> (b / 'missing.txt').exists() - False - - Coercion to string: - - >>> import os - >>> str(c).replace(os.sep, posixpath.sep) - 'mem/abcde.zip/b/c.txt' - - At the root, ``name``, ``filename``, and ``parent`` - resolve to the zipfile. Note these attributes are not - valid and will raise a ``ValueError`` if the zipfile - has no filename. - - >>> root.name - 'abcde.zip' - >>> str(root.filename).replace(os.sep, posixpath.sep) - 'mem/abcde.zip' - >>> str(root.parent) - 'mem' - """ - - __repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})" - - def __init__(self, root, at=""): - """ - Construct a Path from a ZipFile or filename. - - Note: When the source is an existing ZipFile object, - its type (__class__) will be mutated to a - specialized type. If the caller wishes to retain the - original type, the caller should either create a - separate ZipFile object or pass a filename. - """ - self.root = FastLookup.make(root) - self.at = at - - def open(self, mode='r', *args, pwd=None, **kwargs): - """ - Open this entry as text or binary following the semantics - of ``pathlib.Path.open()`` by passing arguments through - to io.TextIOWrapper(). - """ - if self.is_dir(): - raise IsADirectoryError(self) - zip_mode = mode[0] - if not self.exists() and zip_mode == 'r': - raise FileNotFoundError(self) - stream = self.root.open(self.at, zip_mode, pwd=pwd) - if 'b' in mode: - if args or kwargs: - raise ValueError("encoding args invalid for binary operation") - return stream - return io.TextIOWrapper(stream, *args, **kwargs) - - @property - def name(self): - return pathlib.Path(self.at).name or self.filename.name - - @property - def suffix(self): - return pathlib.Path(self.at).suffix or self.filename.suffix - - @property - def suffixes(self): - return pathlib.Path(self.at).suffixes or self.filename.suffixes - - @property - def stem(self): - return pathlib.Path(self.at).stem or self.filename.stem - - @property - def filename(self): - return pathlib.Path(self.root.filename).joinpath(self.at) - - def read_text(self, *args, **kwargs): - with self.open('r', *args, **kwargs) as strm: - return strm.read() - - def read_bytes(self): - with self.open('rb') as strm: - return strm.read() - - def _is_child(self, path): - return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/") - - def _next(self, at): - return self.__class__(self.root, at) - - def is_dir(self): - return not self.at or self.at.endswith("/") - - def is_file(self): - return self.exists() and not self.is_dir() - - def exists(self): - return self.at in self.root._name_set() - - def iterdir(self): - if not self.is_dir(): - raise ValueError("Can't listdir a file") - subs = map(self._next, self.root.namelist()) - return filter(self._is_child, subs) - - def __str__(self): - return posixpath.join(self.root.filename, self.at) - - def __repr__(self): - return self.__repr.format(self=self) - - def joinpath(self, *other): - next = posixpath.join(self.at, *map(_pathlib_compat, other)) - return self._next(self.root.resolve_dir(next)) - - __truediv__ = joinpath - - @property - def parent(self): - if not self.at: - return self.filename.parent - parent_at = posixpath.dirname(self.at.rstrip('/')) - if parent_at: - parent_at += '/' - return self._next(parent_at) diff --git a/venv/lib/python3.11/site-packages/setuptools/archive_util.py b/venv/lib/python3.11/site-packages/setuptools/archive_util.py deleted file mode 100755 index d8e10c1..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/archive_util.py +++ /dev/null @@ -1,213 +0,0 @@ -"""Utilities for extracting common archive formats""" - -import zipfile -import tarfile -import os -import shutil -import posixpath -import contextlib -from distutils.errors import DistutilsError - -from ._path import ensure_directory - -__all__ = [ - "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter", - "UnrecognizedFormat", "extraction_drivers", "unpack_directory", -] - - -class UnrecognizedFormat(DistutilsError): - """Couldn't recognize the archive type""" - - -def default_filter(src, dst): - """The default progress/filter callback; returns True for all files""" - return dst - - -def unpack_archive( - filename, extract_dir, progress_filter=default_filter, - drivers=None): - """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat`` - - `progress_filter` is a function taking two arguments: a source path - internal to the archive ('/'-separated), and a filesystem path where it - will be extracted. The callback must return the desired extract path - (which may be the same as the one passed in), or else ``None`` to skip - that file or directory. The callback can thus be used to report on the - progress of the extraction, as well as to filter the items extracted or - alter their extraction paths. - - `drivers`, if supplied, must be a non-empty sequence of functions with the - same signature as this function (minus the `drivers` argument), that raise - ``UnrecognizedFormat`` if they do not support extracting the designated - archive type. The `drivers` are tried in sequence until one is found that - does not raise an error, or until all are exhausted (in which case - ``UnrecognizedFormat`` is raised). If you do not supply a sequence of - drivers, the module's ``extraction_drivers`` constant will be used, which - means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that - order. - """ - for driver in drivers or extraction_drivers: - try: - driver(filename, extract_dir, progress_filter) - except UnrecognizedFormat: - continue - else: - return - else: - raise UnrecognizedFormat( - "Not a recognized archive type: %s" % filename - ) - - -def unpack_directory(filename, extract_dir, progress_filter=default_filter): - """"Unpack" a directory, using the same interface as for archives - - Raises ``UnrecognizedFormat`` if `filename` is not a directory - """ - if not os.path.isdir(filename): - raise UnrecognizedFormat("%s is not a directory" % filename) - - paths = { - filename: ('', extract_dir), - } - for base, dirs, files in os.walk(filename): - src, dst = paths[base] - for d in dirs: - paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d) - for f in files: - target = os.path.join(dst, f) - target = progress_filter(src + f, target) - if not target: - # skip non-files - continue - ensure_directory(target) - f = os.path.join(base, f) - shutil.copyfile(f, target) - shutil.copystat(f, target) - - -def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): - """Unpack zip `filename` to `extract_dir` - - Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined - by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation - of the `progress_filter` argument. - """ - - if not zipfile.is_zipfile(filename): - raise UnrecognizedFormat("%s is not a zip file" % (filename,)) - - with zipfile.ZipFile(filename) as z: - _unpack_zipfile_obj(z, extract_dir, progress_filter) - - -def _unpack_zipfile_obj(zipfile_obj, extract_dir, progress_filter=default_filter): - """Internal/private API used by other parts of setuptools. - Similar to ``unpack_zipfile``, but receives an already opened :obj:`zipfile.ZipFile` - object instead of a filename. - """ - for info in zipfile_obj.infolist(): - name = info.filename - - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name.split('/'): - continue - - target = os.path.join(extract_dir, *name.split('/')) - target = progress_filter(name, target) - if not target: - continue - if name.endswith('/'): - # directory - ensure_directory(target) - else: - # file - ensure_directory(target) - data = zipfile_obj.read(info.filename) - with open(target, 'wb') as f: - f.write(data) - unix_attributes = info.external_attr >> 16 - if unix_attributes: - os.chmod(target, unix_attributes) - - -def _resolve_tar_file_or_dir(tar_obj, tar_member_obj): - """Resolve any links and extract link targets as normal files.""" - while tar_member_obj is not None and ( - tar_member_obj.islnk() or tar_member_obj.issym()): - linkpath = tar_member_obj.linkname - if tar_member_obj.issym(): - base = posixpath.dirname(tar_member_obj.name) - linkpath = posixpath.join(base, linkpath) - linkpath = posixpath.normpath(linkpath) - tar_member_obj = tar_obj._getmember(linkpath) - - is_file_or_dir = ( - tar_member_obj is not None and - (tar_member_obj.isfile() or tar_member_obj.isdir()) - ) - if is_file_or_dir: - return tar_member_obj - - raise LookupError('Got unknown file type') - - -def _iter_open_tar(tar_obj, extract_dir, progress_filter): - """Emit member-destination pairs from a tar archive.""" - # don't do any chowning! - tar_obj.chown = lambda *args: None - - with contextlib.closing(tar_obj): - for member in tar_obj: - name = member.name - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name.split('/'): - continue - - prelim_dst = os.path.join(extract_dir, *name.split('/')) - - try: - member = _resolve_tar_file_or_dir(tar_obj, member) - except LookupError: - continue - - final_dst = progress_filter(name, prelim_dst) - if not final_dst: - continue - - if final_dst.endswith(os.sep): - final_dst = final_dst[:-1] - - yield member, final_dst - - -def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` - - Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined - by ``tarfile.open()``). See ``unpack_archive()`` for an explanation - of the `progress_filter` argument. - """ - try: - tarobj = tarfile.open(filename) - except tarfile.TarError as e: - raise UnrecognizedFormat( - "%s is not a compressed or uncompressed tar file" % (filename,) - ) from e - - for member, final_dst in _iter_open_tar( - tarobj, extract_dir, progress_filter, - ): - try: - # XXX Ugh - tarobj._extract_member(member, final_dst) - except tarfile.ExtractError: - # chown/chmod/mkfifo/mknode/makedev failed - pass - - return True - - -extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile diff --git a/venv/lib/python3.11/site-packages/setuptools/build_meta.py b/venv/lib/python3.11/site-packages/setuptools/build_meta.py deleted file mode 100755 index 1fb4c3b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/build_meta.py +++ /dev/null @@ -1,512 +0,0 @@ -"""A PEP 517 interface to setuptools - -Previously, when a user or a command line tool (let's call it a "frontend") -needed to make a request of setuptools to take a certain action, for -example, generating a list of installation requirements, the frontend would -would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line. - -PEP 517 defines a different method of interfacing with setuptools. Rather -than calling "setup.py" directly, the frontend should: - - 1. Set the current directory to the directory with a setup.py file - 2. Import this module into a safe python interpreter (one in which - setuptools can potentially set global variables or crash hard). - 3. Call one of the functions defined in PEP 517. - -What each function does is defined in PEP 517. However, here is a "casual" -definition of the functions (this definition should not be relied on for -bug reports or API stability): - - - `build_wheel`: build a wheel in the folder and return the basename - - `get_requires_for_build_wheel`: get the `setup_requires` to build - - `prepare_metadata_for_build_wheel`: get the `install_requires` - - `build_sdist`: build an sdist in the folder and return the basename - - `get_requires_for_build_sdist`: get the `setup_requires` to build - -Again, this is not a formal definition! Just a "taste" of the module. -""" - -import io -import os -import shlex -import sys -import tokenize -import shutil -import contextlib -import tempfile -import warnings -from pathlib import Path -from typing import Dict, Iterator, List, Optional, Union - -import setuptools -import distutils -from . import errors -from ._path import same_path -from ._reqs import parse_strings -from ._deprecation_warning import SetuptoolsDeprecationWarning -from distutils.util import strtobool - - -__all__ = ['get_requires_for_build_sdist', - 'get_requires_for_build_wheel', - 'prepare_metadata_for_build_wheel', - 'build_wheel', - 'build_sdist', - 'get_requires_for_build_editable', - 'prepare_metadata_for_build_editable', - 'build_editable', - '__legacy__', - 'SetupRequirementsError'] - -SETUPTOOLS_ENABLE_FEATURES = os.getenv("SETUPTOOLS_ENABLE_FEATURES", "").lower() -LEGACY_EDITABLE = "legacy-editable" in SETUPTOOLS_ENABLE_FEATURES.replace("_", "-") - - -class SetupRequirementsError(BaseException): - def __init__(self, specifiers): - self.specifiers = specifiers - - -class Distribution(setuptools.dist.Distribution): - def fetch_build_eggs(self, specifiers): - specifier_list = list(parse_strings(specifiers)) - - raise SetupRequirementsError(specifier_list) - - @classmethod - @contextlib.contextmanager - def patch(cls): - """ - Replace - distutils.dist.Distribution with this class - for the duration of this context. - """ - orig = distutils.core.Distribution - distutils.core.Distribution = cls - try: - yield - finally: - distutils.core.Distribution = orig - - -@contextlib.contextmanager -def no_install_setup_requires(): - """Temporarily disable installing setup_requires - - Under PEP 517, the backend reports build dependencies to the frontend, - and the frontend is responsible for ensuring they're installed. - So setuptools (acting as a backend) should not try to install them. - """ - orig = setuptools._install_setup_requires - setuptools._install_setup_requires = lambda attrs: None - try: - yield - finally: - setuptools._install_setup_requires = orig - - -def _get_immediate_subdirectories(a_dir): - return [name for name in os.listdir(a_dir) - if os.path.isdir(os.path.join(a_dir, name))] - - -def _file_with_extension(directory, extension): - matching = ( - f for f in os.listdir(directory) - if f.endswith(extension) - ) - try: - file, = matching - except ValueError: - raise ValueError( - 'No distribution was found. Ensure that `setup.py` ' - 'is not empty and that it calls `setup()`.') - return file - - -def _open_setup_script(setup_script): - if not os.path.exists(setup_script): - # Supply a default setup.py - return io.StringIO(u"from setuptools import setup; setup()") - - return getattr(tokenize, 'open', open)(setup_script) - - -@contextlib.contextmanager -def suppress_known_deprecation(): - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', 'setup.py install is deprecated') - yield - - -_ConfigSettings = Optional[Dict[str, Union[str, List[str], None]]] -""" -Currently the user can run:: - - pip install -e . --config-settings key=value - python -m build -C--key=value -C key=value - -- pip will pass both key and value as strings and overwriting repeated keys - (pypa/pip#11059). -- build will accumulate values associated with repeated keys in a list. - It will also accept keys with no associated value. - This means that an option passed by build can be ``str | list[str] | None``. -- PEP 517 specifies that ``config_settings`` is an optional dict. -""" - - -class _ConfigSettingsTranslator: - """Translate ``config_settings`` into distutils-style command arguments. - Only a limited number of options is currently supported. - """ - # See pypa/setuptools#1928 pypa/setuptools#2491 - - def _get_config(self, key: str, config_settings: _ConfigSettings) -> List[str]: - """ - Get the value of a specific key in ``config_settings`` as a list of strings. - - >>> fn = _ConfigSettingsTranslator()._get_config - >>> fn("--global-option", None) - [] - >>> fn("--global-option", {}) - [] - >>> fn("--global-option", {'--global-option': 'foo'}) - ['foo'] - >>> fn("--global-option", {'--global-option': ['foo']}) - ['foo'] - >>> fn("--global-option", {'--global-option': 'foo'}) - ['foo'] - >>> fn("--global-option", {'--global-option': 'foo bar'}) - ['foo', 'bar'] - """ - cfg = config_settings or {} - opts = cfg.get(key) or [] - return shlex.split(opts) if isinstance(opts, str) else opts - - def _valid_global_options(self): - """Global options accepted by setuptools (e.g. quiet or verbose).""" - options = (opt[:2] for opt in setuptools.dist.Distribution.global_options) - return {flag for long_and_short in options for flag in long_and_short if flag} - - def _global_args(self, config_settings: _ConfigSettings) -> Iterator[str]: - """ - Let the user specify ``verbose`` or ``quiet`` + escape hatch via - ``--global-option``. - Note: ``-v``, ``-vv``, ``-vvv`` have similar effects in setuptools, - so we just have to cover the basic scenario ``-v``. - - >>> fn = _ConfigSettingsTranslator()._global_args - >>> list(fn(None)) - [] - >>> list(fn({"verbose": "False"})) - ['-q'] - >>> list(fn({"verbose": "1"})) - ['-v'] - >>> list(fn({"--verbose": None})) - ['-v'] - >>> list(fn({"verbose": "true", "--global-option": "-q --no-user-cfg"})) - ['-v', '-q', '--no-user-cfg'] - >>> list(fn({"--quiet": None})) - ['-q'] - """ - cfg = config_settings or {} - falsey = {"false", "no", "0", "off"} - if "verbose" in cfg or "--verbose" in cfg: - level = str(cfg.get("verbose") or cfg.get("--verbose") or "1") - yield ("-q" if level.lower() in falsey else "-v") - if "quiet" in cfg or "--quiet" in cfg: - level = str(cfg.get("quiet") or cfg.get("--quiet") or "1") - yield ("-v" if level.lower() in falsey else "-q") - - valid = self._valid_global_options() - args = self._get_config("--global-option", config_settings) - yield from (arg for arg in args if arg.strip("-") in valid) - - def __dist_info_args(self, config_settings: _ConfigSettings) -> Iterator[str]: - """ - The ``dist_info`` command accepts ``tag-date`` and ``tag-build``. - - .. warning:: - We cannot use this yet as it requires the ``sdist`` and ``bdist_wheel`` - commands run in ``build_sdist`` and ``build_wheel`` to re-use the egg-info - directory created in ``prepare_metadata_for_build_wheel``. - - >>> fn = _ConfigSettingsTranslator()._ConfigSettingsTranslator__dist_info_args - >>> list(fn(None)) - [] - >>> list(fn({"tag-date": "False"})) - ['--no-date'] - >>> list(fn({"tag-date": None})) - ['--no-date'] - >>> list(fn({"tag-date": "true", "tag-build": ".a"})) - ['--tag-date', '--tag-build', '.a'] - """ - cfg = config_settings or {} - if "tag-date" in cfg: - val = strtobool(str(cfg["tag-date"] or "false")) - yield ("--tag-date" if val else "--no-date") - if "tag-build" in cfg: - yield from ["--tag-build", str(cfg["tag-build"])] - - def _editable_args(self, config_settings: _ConfigSettings) -> Iterator[str]: - """ - The ``editable_wheel`` command accepts ``editable-mode=strict``. - - >>> fn = _ConfigSettingsTranslator()._editable_args - >>> list(fn(None)) - [] - >>> list(fn({"editable-mode": "strict"})) - ['--mode', 'strict'] - """ - cfg = config_settings or {} - mode = cfg.get("editable-mode") or cfg.get("editable_mode") - if not mode: - return - yield from ["--mode", str(mode)] - - def _arbitrary_args(self, config_settings: _ConfigSettings) -> Iterator[str]: - """ - Users may expect to pass arbitrary lists of arguments to a command - via "--global-option" (example provided in PEP 517 of a "escape hatch"). - - >>> fn = _ConfigSettingsTranslator()._arbitrary_args - >>> list(fn(None)) - [] - >>> list(fn({})) - [] - >>> list(fn({'--build-option': 'foo'})) - ['foo'] - >>> list(fn({'--build-option': ['foo']})) - ['foo'] - >>> list(fn({'--build-option': 'foo'})) - ['foo'] - >>> list(fn({'--build-option': 'foo bar'})) - ['foo', 'bar'] - >>> warnings.simplefilter('error', SetuptoolsDeprecationWarning) - >>> list(fn({'--global-option': 'foo'})) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - SetuptoolsDeprecationWarning: ...arguments given via `--global-option`... - """ - args = self._get_config("--global-option", config_settings) - global_opts = self._valid_global_options() - bad_args = [] - - for arg in args: - if arg.strip("-") not in global_opts: - bad_args.append(arg) - yield arg - - yield from self._get_config("--build-option", config_settings) - - if bad_args: - msg = f""" - The arguments {bad_args!r} were given via `--global-option`. - Please use `--build-option` instead, - `--global-option` is reserved to flags like `--verbose` or `--quiet`. - """ - warnings.warn(msg, SetuptoolsDeprecationWarning) - - -class _BuildMetaBackend(_ConfigSettingsTranslator): - def _get_build_requires(self, config_settings, requirements): - sys.argv = [ - *sys.argv[:1], - *self._global_args(config_settings), - "egg_info", - *self._arbitrary_args(config_settings), - ] - try: - with Distribution.patch(): - self.run_setup() - except SetupRequirementsError as e: - requirements += e.specifiers - - return requirements - - def run_setup(self, setup_script='setup.py'): - # Note that we can reuse our build directory between calls - # Correctness comes first, then optimization later - __file__ = setup_script - __name__ = '__main__' - - with _open_setup_script(__file__) as f: - code = f.read().replace(r'\r\n', r'\n') - - exec(code, locals()) - - def get_requires_for_build_wheel(self, config_settings=None): - return self._get_build_requires(config_settings, requirements=['wheel']) - - def get_requires_for_build_sdist(self, config_settings=None): - return self._get_build_requires(config_settings, requirements=[]) - - def _bubble_up_info_directory(self, metadata_directory: str, suffix: str) -> str: - """ - PEP 517 requires that the .dist-info directory be placed in the - metadata_directory. To comply, we MUST copy the directory to the root. - - Returns the basename of the info directory, e.g. `proj-0.0.0.dist-info`. - """ - info_dir = self._find_info_directory(metadata_directory, suffix) - if not same_path(info_dir.parent, metadata_directory): - shutil.move(str(info_dir), metadata_directory) - # PEP 517 allow other files and dirs to exist in metadata_directory - return info_dir.name - - def _find_info_directory(self, metadata_directory: str, suffix: str) -> Path: - for parent, dirs, _ in os.walk(metadata_directory): - candidates = [f for f in dirs if f.endswith(suffix)] - - if len(candidates) != 0 or len(dirs) != 1: - assert len(candidates) == 1, f"Multiple {suffix} directories found" - return Path(parent, candidates[0]) - - msg = f"No {suffix} directory found in {metadata_directory}" - raise errors.InternalError(msg) - - def prepare_metadata_for_build_wheel(self, metadata_directory, - config_settings=None): - sys.argv = [ - *sys.argv[:1], - *self._global_args(config_settings), - "dist_info", - "--output-dir", metadata_directory, - "--keep-egg-info", - ] - with no_install_setup_requires(): - self.run_setup() - - self._bubble_up_info_directory(metadata_directory, ".egg-info") - return self._bubble_up_info_directory(metadata_directory, ".dist-info") - - def _build_with_temp_dir(self, setup_command, result_extension, - result_directory, config_settings): - result_directory = os.path.abspath(result_directory) - - # Build in a temporary directory, then copy to the target. - os.makedirs(result_directory, exist_ok=True) - temp_opts = {"prefix": ".tmp-", "dir": result_directory} - with tempfile.TemporaryDirectory(**temp_opts) as tmp_dist_dir: - sys.argv = [ - *sys.argv[:1], - *self._global_args(config_settings), - *setup_command, - "--dist-dir", tmp_dist_dir, - *self._arbitrary_args(config_settings), - ] - with no_install_setup_requires(): - self.run_setup() - - result_basename = _file_with_extension( - tmp_dist_dir, result_extension) - result_path = os.path.join(result_directory, result_basename) - if os.path.exists(result_path): - # os.rename will fail overwriting on non-Unix. - os.remove(result_path) - os.rename(os.path.join(tmp_dist_dir, result_basename), result_path) - - return result_basename - - def build_wheel(self, wheel_directory, config_settings=None, - metadata_directory=None): - with suppress_known_deprecation(): - return self._build_with_temp_dir(['bdist_wheel'], '.whl', - wheel_directory, config_settings) - - def build_sdist(self, sdist_directory, config_settings=None): - return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], - '.tar.gz', sdist_directory, - config_settings) - - def _get_dist_info_dir(self, metadata_directory: Optional[str]) -> Optional[str]: - if not metadata_directory: - return None - dist_info_candidates = list(Path(metadata_directory).glob("*.dist-info")) - assert len(dist_info_candidates) <= 1 - return str(dist_info_candidates[0]) if dist_info_candidates else None - - if not LEGACY_EDITABLE: - - # PEP660 hooks: - # build_editable - # get_requires_for_build_editable - # prepare_metadata_for_build_editable - def build_editable( - self, wheel_directory, config_settings=None, metadata_directory=None - ): - # XXX can or should we hide our editable_wheel command normally? - info_dir = self._get_dist_info_dir(metadata_directory) - opts = ["--dist-info-dir", info_dir] if info_dir else [] - cmd = ["editable_wheel", *opts, *self._editable_args(config_settings)] - with suppress_known_deprecation(): - return self._build_with_temp_dir( - cmd, ".whl", wheel_directory, config_settings - ) - - def get_requires_for_build_editable(self, config_settings=None): - return self.get_requires_for_build_wheel(config_settings) - - def prepare_metadata_for_build_editable(self, metadata_directory, - config_settings=None): - return self.prepare_metadata_for_build_wheel( - metadata_directory, config_settings - ) - - -class _BuildMetaLegacyBackend(_BuildMetaBackend): - """Compatibility backend for setuptools - - This is a version of setuptools.build_meta that endeavors - to maintain backwards - compatibility with pre-PEP 517 modes of invocation. It - exists as a temporary - bridge between the old packaging mechanism and the new - packaging mechanism, - and will eventually be removed. - """ - def run_setup(self, setup_script='setup.py'): - # In order to maintain compatibility with scripts assuming that - # the setup.py script is in a directory on the PYTHONPATH, inject - # '' into sys.path. (pypa/setuptools#1642) - sys_path = list(sys.path) # Save the original path - - script_dir = os.path.dirname(os.path.abspath(setup_script)) - if script_dir not in sys.path: - sys.path.insert(0, script_dir) - - # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to - # get the directory of the source code. They expect it to refer to the - # setup.py script. - sys_argv_0 = sys.argv[0] - sys.argv[0] = setup_script - - try: - super(_BuildMetaLegacyBackend, - self).run_setup(setup_script=setup_script) - finally: - # While PEP 517 frontends should be calling each hook in a fresh - # subprocess according to the standard (and thus it should not be - # strictly necessary to restore the old sys.path), we'll restore - # the original path so that the path manipulation does not persist - # within the hook after run_setup is called. - sys.path[:] = sys_path - sys.argv[0] = sys_argv_0 - - -# The primary backend -_BACKEND = _BuildMetaBackend() - -get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel -get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist -prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel -build_wheel = _BACKEND.build_wheel -build_sdist = _BACKEND.build_sdist - -if not LEGACY_EDITABLE: - get_requires_for_build_editable = _BACKEND.get_requires_for_build_editable - prepare_metadata_for_build_editable = _BACKEND.prepare_metadata_for_build_editable - build_editable = _BACKEND.build_editable - - -# The legacy backend -__legacy__ = _BuildMetaLegacyBackend() diff --git a/venv/lib/python3.11/site-packages/setuptools/cli-32.exe b/venv/lib/python3.11/site-packages/setuptools/cli-32.exe deleted file mode 100755 index b1487b7819e7286577a043c7726fbe0ca1543083..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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

@|$jDp4t7maBT@by!vG1&J_?=DS4W3Hu6w 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[c}iI#RErv3nvcIClH@!{vM)zJ_weD zu_-L8NU*GlC{d0L!!VW10^+~>qmNB~Y8H+F}!P8_d(PpvjzMJQmr z)FkX;2B~<|3JfJeWv@IXo~nTtp$}Gjie> zs8UDG*kid(%i5QCBp~MA;#I186PI-nZ&k7!k8BiLJSuR>h7ArSYHD~B0I z=T6L{zqglekt0JjG5z&|GWb4?+B5+{p^fgTufl_KesA{@I&g7rNq==^SGc5GcM%$N zDBG2)qExz*Z;jGN_-iD-y8i2BCq)p}2lKcspLg>w-;qwg(()HXrZa3jd!}spuwBVX zwmX!iwU?#7uoQnunw|OlU~+c z^L5Ak3zWhaA4B^FhMMboO0k*O2GL)lD9_<$5b>czbCvKcSt+u*gA*=%dH>Q-Bc11h zzO7jbXN)&5mBf=w2anK6P$YcJZQoWa2#E!v{hFKxxm7Fc)Fc9iC35{|Lp7bIDjrhC zgMiGf4r2yquH{U7WdMio;XS4Y%Ry{q7#kv#gZ07i`7eo#MMh_o68E*Fd_#nrri^4b zX+slbsv>+8pmck%oLDUL()8NRJ#Z z8DReF_eq2zsjEXGs)yS{k}ykS1B!ZrY0f6O65^lslJv3g&wfpDg-&EwF8wrc=hSwm zPlV&n%%yE_@onOwK?)`GNJ6MQ0drMuBYWCH5dkD)uErh@*k}#GcFl<-;;TN+5vb|b zctkCv;*zL7f)A;QuO%(81r0)&aUz4EQu;kA!k@7i8RZ)koMaWW`5cC6n@{w!!J$5d zx}l)4VP4xL=BKi&c^{n_Qi`q@G{vimblcVR53b#*X$FUOQFm!A8JKahNSiBdY+x3bJZfD8n{--FLUM4+Mx@{vM_ep zkk)U=K8R(rhU(X_faI*ZO}cn`5t*O}lx^j8|0rt-)o=Axn^DGcQTi!#7hxLTq?|HQ zB;T6(nrsCeYK0_o%)IO+CP{n#+|;w1ZmvD2c-J{i88bp63RjyKOE!B!D3U{RCs*Zh z&^%65VM(J34230U4bHS}M@SYS9TEK}c%)2<$h1|T;##zRtjRt@#1T%J=kAhOiw+Z% z7DpyWVK@6%9K^uVD9LDKj)dR^aZK6$@Lt)l;sj@`QSzBm{TlLG{JKM_^60Zr2w~nr zr>P-BaV8OjjWm?hQ3$ZCx+lyD%q`~4iNF9xWKi$t&pzBhwN9Dq-o^v9@=abLR#|

KZqkLal4YCRR9VNhIM|rBqmzzcImvcx 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/cli-64.exe b/venv/lib/python3.11/site-packages/setuptools/cli-64.exe deleted file mode 100755 index 675e6bf3743f3d3011c238657e7128ee9960ef7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74752 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/cli-arm64.exe b/venv/lib/python3.11/site-packages/setuptools/cli-arm64.exe deleted file mode 100755 index 7a87ce48093d2c984b2ceb7b1f8e1ba6f5fc94f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137216 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

x5%&be+vRm^Y>egOSbwaL4{e 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/cli.exe b/venv/lib/python3.11/site-packages/setuptools/cli.exe deleted file mode 100755 index b1487b7819e7286577a043c7726fbe0ca1543083..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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

@|$jDp4t7maBT@by!vG1&J_?=DS4W3Hu6w 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[c}iI#RErv3nvcIClH@!{vM)zJ_weD zu_-L8NU*GlC{d0L!!VW10^+~>qmNB~Y8H+F}!P8_d(PpvjzMJQmr z)FkX;2B~<|3JfJeWv@IXo~nTtp$}Gjie> zs8UDG*kid(%i5QCBp~MA;#I186PI-nZ&k7!k8BiLJSuR>h7ArSYHD~B0I z=T6L{zqglekt0JjG5z&|GWb4?+B5+{p^fgTufl_KesA{@I&g7rNq==^SGc5GcM%$N zDBG2)qExz*Z;jGN_-iD-y8i2BCq)p}2lKcspLg>w-;qwg(()HXrZa3jd!}spuwBVX zwmX!iwU?#7uoQnunw|OlU~+c z^L5Ak3zWhaA4B^FhMMboO0k*O2GL)lD9_<$5b>czbCvKcSt+u*gA*=%dH>Q-Bc11h zzO7jbXN)&5mBf=w2anK6P$YcJZQoWa2#E!v{hFKxxm7Fc)Fc9iC35{|Lp7bIDjrhC zgMiGf4r2yquH{U7WdMio;XS4Y%Ry{q7#kv#gZ07i`7eo#MMh_o68E*Fd_#nrri^4b zX+slbsv>+8pmck%oLDUL()8NRJ#Z z8DReF_eq2zsjEXGs)yS{k}ykS1B!ZrY0f6O65^lslJv3g&wfpDg-&EwF8wrc=hSwm zPlV&n%%yE_@onOwK?)`GNJ6MQ0drMuBYWCH5dkD)uErh@*k}#GcFl<-;;TN+5vb|b zctkCv;*zL7f)A;QuO%(81r0)&aUz4EQu;kA!k@7i8RZ)koMaWW`5cC6n@{w!!J$5d zx}l)4VP4xL=BKi&c^{n_Qi`q@G{vimblcVR53b#*X$FUOQFm!A8JKahNSiBdY+x3bJZfD8n{--FLUM4+Mx@{vM_ep zkk)U=K8R(rhU(X_faI*ZO}cn`5t*O}lx^j8|0rt-)o=Axn^DGcQTi!#7hxLTq?|HQ zB;T6(nrsCeYK0_o%)IO+CP{n#+|;w1ZmvD2c-J{i88bp63RjyKOE!B!D3U{RCs*Zh z&^%65VM(J34230U4bHS}M@SYS9TEK}c%)2<$h1|T;##zRtjRt@#1T%J=kAhOiw+Z% z7DpyWVK@6%9K^uVD9LDKj)dR^aZK6$@Lt)l;sj@`QSzBm{TlLG{JKM_^60Zr2w~nr zr>P-BaV8OjjWm?hQ3$ZCx+lyD%q`~4iNF9xWKi$t&pzBhwN9Dq-o^v9@=abLR#|

KZqkLal4YCRR9VNhIM|rBqmzzcImvcx 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__init__.py b/venv/lib/python3.11/site-packages/setuptools/command/__init__.py deleted file mode 100755 index 5acd768..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from distutils.command.bdist import bdist -import sys - -if 'egg' not in bdist.format_commands: - try: - bdist.format_commands['egg'] = ('bdist_egg', "Python .egg file") - except TypeError: - # For backward compatibility with older distutils (stdlib) - bdist.format_command['egg'] = ('bdist_egg', "Python .egg file") - bdist.format_commands.append('egg') - -del bdist, sys diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 8e1c46133021d15825f533fedd4b3213ab3bc92f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 636 zcmY*V&ui2`6n>N0w6m#edl0-REHqj|YlgB%i{L>N4Gu@_5G9i=Qx}H4t z;6YHac-m7%{44wqwz6Qzso=?5pqHg5XSN&MzW3(Md+&Q6@6CK`G%Qdu`t)`GJp%Zn zlS*pS;QT}dUw{EaAw*~kAsri`v1KsK(LSySJ(S+B1FOx}7~W8DOqYSzY)DrWSL0^I zxx{A~gSiTuy%|1H`~6VoQV?uHTswp}coPoMHrh6r@d6z4uZA5|m^&t83R?PWH!ejOw&h<7Iuj!tMIF0xW#zmgj>qHD0@FHbX_b1x&sGx#&ckc?=K@mxA2i*m A#sB~S diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/alias.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/alias.cpython-311.pyc deleted file mode 100755 index 5f70bcdadac257c3a141d38eb2104252c5f3532c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3903 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π-P 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 JZ3yc<{~sh6!%+YL diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-311.pyc deleted file mode 100755 index 33962ab0b77e8d5e2ac3e2e2469c0af9d0e65bf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2191 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 CDb@1; diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_clib.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_clib.cpython-311.pyc deleted file mode 100755 index 63a0163d6701eca0d360df8feb4033589ed03736..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4166 zcmb_fO>Eo96&~u}vSib7Y{!4`Bwkx9|48d3bz(Q(qNt0cKbxZ1F0eI{60|sy=}@9N zq@38Gl5MdEA964j*(MEAM3=f=I00Iq0g3`W_AUhiLJ$ZLpy;7DxyfE~>Kjs&ENxr_ zMMvc0o8g=HzV|ru-slg}Xc$4O-hHrssRyBdu#VgOb>`J7F!zvzBu+tDF6H4+*0bW} z*oa5*W&JCDoA)Y#Y;YxL^FAe%?O5sHkOy5tlK*og1&DXu;(^fnZ_c4kG z|HZmj;+)mHENgl}mlf?}q8IYtr&Ogd>{ZkZJdWqc4MK&yDAOCVMuZGi3;9%Cm;K=C zomVG-xrYc^;UvVYtav5Q=V-+zdBL8~3a=JqMG{hqyee)0xG;wHlMO!$DCDj&7tBRuDkaL;Eu&rY*fq#(ADt2T4RDFrQ=QIpw7AH=OFf9x31X_TEnu~F!0mF`)SKinJX;{$s{hxV-swspq`RpCh74b;WNWYJ)1%FK>p_>7yha-e z4jt*MPlr_Hwq0QM-41H?r08#nfM4euf^Cv*KKtM9a|RUyhQHKQa)^@xhokUcQ3YF2 z1^>tIas)=hw~VgcEryIxhAVa$9i>CxvI*A+wtg3gw!hSTeTXwc@9bB&#jo)H*{`EK z34g-}|qqn>aS1#o{wKR+o?AYyk=dl%G5$nq7f&P#o)H&D7miW3;V4yIitT z!8Ag-VHP*7kXs|SuD&A>cR~|MOCeO#Sl`S;d3F#i+J!AO`XKt5`mEcCdV`idz9N07n%o0Ck)_ zLv9(fc;|2+xaC@NPgZc8$x~Jwte`8*fLJ{#N<^Iq0792j0*f>&1@Ugnrx7J>bu_-V z6#`aZX8>0xLqu6pqimO3k;8@G>U0XceWYQYuv3H;(rC&V2|F=j2Of(jH{rkoo(c|n ztr<(oc8A7DOX=zZI}0S51{P_REk=47&l zKH@sM4s2S9oZkL)XUpuz_i|t4N4~CJ$)AsyxxJO*9b@rd3%<=4xxe3-~Fr<`|Y)d*DC$f)&A-2 zOaF{?-??1wo7r2dM9x%TFivmMXmq)!v17Qrd-vPuEa5ny|@Ez#KV!|H4klb1@{7jjjF-IpJU43wMZ?f*j=t6aLVJG}z;8bbqiT?DHy=-ORVs+pmSnXMSF*FOo z8%(_X-~zZZxB#vUFM=z>i{MJ%BKXiVXzLGG_~|M?UFN4ve&jhn{)`_lU9Rx6RerW? zUoXeT9~PgFEj=4sGWh{>c_5S)*O$ULnj|j)uO0p@&E;Uj=g52W|I>r+H>cl=aK1W z5%38^AZ^fQ|Ipp_S_g{G93X!bkOQePVs~pl^{|ENEZ0}CgyFxQ-wFx#?iK_qEC^Xu zDkuc_h#>s3AS!I%LoX-@lA00(It`P)LUaZmbczv{HEhBd?F^958o!z+>JQZrBPXwL zelYxY>Zr5xPuLof+`pcQ`aVrG_o1D|*xt2GT0WJ^8H;bufIp5Z)tofi(HM3zX>T(F zBq09??C-6e8tEMKq2bb-&_yQ-AJPl(f}QBK-vFt3IgT^Yboq$OL?4t}FB1)xTQ3ux dE4N;?z%MusBJ*~-bNueuf&K3F5fV1;{{X(`?ic_7 diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_ext.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_ext.cpython-311.pyc deleted file mode 100755 index b91b53e32d2db97544d5caa157c22647a2ae8775..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22011 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 Y#smJUJ$UK>_p1Z;Q%9}8I>H0~Z|hKJLjV8( diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_py.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_py.cpython-311.pyc deleted file mode 100755 index e733cd6928d9c8e900d190360497bcd65ca5605a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23177 zcmbt+du$tbp5O3IQItqiltjHpl5L5OL|JzHj30?@S$5*c-q?ApHoG(>j%3=DsLW8d zrBWN;BG=G{anS}2tj#(Nd&uUrO>(DOY;ne6+cWN3AShaZ)J-9Fa0b$D1N5#hx!%R) zwtuvr?{7H68A{G>+R^CC-^~2x_x%38@8A4UO^t`cA>Voba`!%t`z2jyhoh8u?6q** zT`tbWElF<5GHS6<+M2XZSx2obZA;pw?4x#;wkI7^&T-tIa*eu6cdACK@P<9<8TGK= z>d|WU>mBv7-`koS7YLIVtNwKeY4YvH)e&XfC?o+m>$PO>4y_3>e%D! z0C%~x;n`(9oiX3nJDTA>MxIafe3$hhO561sxXXHa9s_C~Dw=}x+)phdVTWQ(Ns43q z(o`z0*rjwVt+=Fg6jvC8^U>3(QQ;cmrT-yisT~wkeK!SUH9fm~h6M@Lqeo8E>xMHcM-~ho4A^ z{8S3H#D#P$k(458GoDLIsXjD3A@Q{6k(EzP;2Py^>|ZRIOkI=sxzsGRL2d3FKbA^g zVy)J~p z0A-2_latZJ^h7EePlzU(L{xUWWk*>RVq`W3>Vd@ zk|~GA&bS#%0`Erk>$nB^h+4AaDkr*)*Kx~XZj$nA%bU@)uysW7&@@LG!i3$5JtZb4 z#TJyI_$Lw|7KLu}*gye)uFvUhxEp`ITH)$_KDjTvDkEQPcfYQ0Ww`g^-F?MYUT*D|TMuUKvb(9cwO8J{N8b8;e(Sl<$LLmPvAS{T>3fIs)x9{2{@|UO zrDWd!RI#Iz9=GP%DH6^2TcYFR`l#W;jej=#Bv8C(xyxl7;_F7fl%}VpBV#dhpv|$u zOa{zvELfgcw$+^T|DkMa+R!s|D{?yiX?>yJj3r~u*fREvBjfxS*!GEzapyVFj|||G zHXw;e_Z62YNU7viL2*d4Sa(X*cnXV^a4qZ>dntz#3k;WvD>a*Di5dt9k|16cRL)wf zU#1gNf~44!iRmkfBMDg{sZ>RyrT$=U+1hsnL)YEyrqX+UloDAezi>vv{PK5S_EVC&MgANAks zUuzy%Z5}8z56aDhg@#>n!>;V`LtpUbwcFR$eEh19&owMJuJk`>FLrLr%|5bO{E=UA z0PCEkD#B38L`!I#7&h$$HUXEo%ebK)k_%Uae(VtGN~bBJHEua?$}I*nT+V=b+Ix^_ zkSsG9Msdoe_TsHgXL{pXIi1#&%igT?9QA3#k*+P@x=ho>j$DDn15W+wpU&?37%QMzH}X614~7vuNV+f%sda8dq%nou<}Y#3=-6CZ z7>86B_9&h*Yf;=9R}owBf>NVmR;ga4wuERU@lDYX&qxftRB{wtdj=RU@+d_mwABz7 zqrm@}*|a3~;I@GjDmHO;dfrbRQqlprOVEu*T3d%U-h;Zyu9q?^Io2w;U#O;cJ{1e)!R|llj$ z6P__#{{tj|>z26X3VSZ{z(U;Hc$l#e{7c7NN^#8PsgXEnt#$z9|`- zPbB9^tintf#U!x<4Fh5GMQNtW{F2=_PGpoa#L{Uo8Vy@j0%xa7iF(QNDq%W?^n6gC zQNue!cp^OufSIlKEgo8}?#Nen6x+Mj+IOwC?<%xEEw?|NJ#qVNv99sX(Y&|op|9@t z!kVvl)z`ZmTuv8!Ps_fi^X{kBp*JpTT9Rz&ZzJ(dMHZFle~j`z(aU@tU0Sd&IKcdx zF%`dU$nBNOmsrSzRc9K8Q7j?5y0XOWXs_ag&Lm97!_E@ZP@gH)>Mvs`q{K48L)^*U zz{-b6D^b6RDQJUFLp)!v55AgEi#dZw(hC5PDw^8~!=GMletPA?{k;#K$)9_*(EOU* z{Mt=l*0tDBtlmOvY7pxNOKHv9v+C_xb``ukW$(_scW2Spu;k3XnRmB;4ZY8xCZhK_ z{BAtVcyHm1GDX@^&Tkxgr1j~U!P+w8xOoB?#vdIPrb!wW_#^~7lE8aq z_NgO8DPqsl5TvDW4-ZKi;`UEzQTSt!66YW#LPt$Z2rvPFM+4fXVlzq|TQM_NCXK7+ z0GeM(=fvl5b3UX`OvOrj2~VZH09YAr@0z=9)!kNbcgXIJyt@Od;JxEZb~&_jW$VxT z^Sg!~>?#CL%E6Nb->~c(&bx=dW*TmxP&3=j=_Ce^^dk;&+dQC{6vIRq1u5f1Ag$-Z zq*%>mY?u_={6A$%4Poqt*|~V}cbcAy7fbWgrxyivjA?`5GCU;s$w@(kh65Hk$Adlz zQ!`AxE6pSiosCTd)198>gGBK>Zm~cA6jpBgZMMdv58wykYXoOBdH8YN`!5SHL_E&tJ*<{8cD=v zGztGVoGBCCKM-fD480MC8Z-sXm2D?l0+CuY5-@e_mlyos$bi<8sF{V zch25AyL2MgQ}FJPy*t)zrfiI;gk6e{@KV=$6C&%4_!{fdO=+0=vMg}tZby{8J@r}Dw) zvsLR(Q@`0jeGzJ13-zsr`j%f^nJk2k$e|Eq83LMN-Xc!CjG;<@MT{z0N zl$=3FR-X~fRERVSjx?ch=|~5(6iU)dy1F_pBd{0eei1U*2c_k$8F&P(H4yBgd z9a2=dJ_Ey{5Lar{>#10J{1U7U9=cSSoZ_IGB%`6BB+rkba)abjv9wcoDt!ik1z6X( zRu@^Vi!iaVt>~@8`N(AtV!;4p-M{v5&21mN`jZPQ7xHZf3vCDGwuARi6`F?RrlD-@ zm!ZykzO~Sv)zF@m=|X5o4h>~%9@e*faO~djy^-Y?3-t%(`h!`|Lx0m9AFHBc%}Xj= zZg}}6RW>bp8y-1qTWEo9@njveK!a<(?W;b}gcaBQ`hxGM>^quwA7v|5af%EJ#*Ms? zri$k5@t*@Q>zBb|A?`NvJ7AshP2^V(vuyjj*euN4589r=YEV&{E^KMF(QhSR298^P zGf3v^gUo<*@M78B5-FM0r3fRek@K@-$5jW+MaVdTAN`T0|stZ7NxZOOg|r+D;><@h_Iepa_=BlWriJ^dbO}?P{M~-A3xh!H0E?OZK(U zz-nlq5E_(2gKMF^tD(Jx(0)0zzfgBTt~-$T9?*?ZU8}w>5cLYJP!}RlyiR_9hKnaV z*M662#AH+FHXP>ZsUS=i<3t(>Aejc<;wlMtB^qFSucAVeyh0eqo#8KiFGUKWT zX+5gJN0mG*isib&*zz0qp=4}oEFL>D->-Ak^0a8vY!oNd?6*<8L{$C;x6--t+|Re( z;8f|rqS$~Ez?(~WD3Z*f@G40(7=|jbNL89jx~+~{WJgz=Qc8s7Tr)1XN>5Gpg=?r~ zzU6D$|BsPDBH7^v_hq2v&H%Ii46b?y3*OzbcQ?D-y6W9p@NSpA+d(kuh+x!tATJQX zc<Tcz;4ELmCeSKsHBK@KGH-H<2LhFh|%Xtgmo)Ef((fkvI$!;DURYmmBJF z3Qj5>ZYa&n$j^wdH;$7E)eE0nx{n7348!)A5T%It3K};OwlfDxJc`#e_mmjJ6P0k3 zW*78>F|dnxU=#wyVcZZ;QFb?FU_4lp{z`o3O+2lX{>(^2W;SUC;J@Gxlq9liEpmJ{ za=Z{3k|RTqf*%Gm10BN-Klq{a>ok|y>dfucDUHsvep<`ZHz3ZKmGpw zYo9v{jc4V?v)NO{x|XHyutU`YzK=WeVSUB_HUje=vP&6& z5?bs%`18~{XRqpIpx}i=WAW9c#Bx)ybsO-b2KNCL-4B~u?lpec`hIIJu@WjY9h936 zE;=7Jx8Cddun-_Voymrq~^O0sFyY>pzdMj!tVfG6t$ z8|XxonIb_au=Y2l65q%+T%l>3Sq}M5HrLRhL08z@SgUN%DGXA3r5plUbFqX{TaQ<` zDiYJ1I4i;~ktSPlPF*1-*&qtLpf3`Y5F>cb;z2ZeLf9i_=`9CwnhC`P9|SXwRuGg! z$YWp}C44e4st=Gsk^n$UI=a_7PONsED0G~ZJ5CZA>0;pK+3d;1VepW5Ubywb2iAM8 z4}I_ZmYs#rfDEZcw~)4Ve)zrjzqdTR@=BrYklc3Y=16vEaoRY5@q5cSt+6?0qcp8Cy>1qB&P?w#+I=f#gZq^ zxXp|k<|`V@+r6f_hfgccnRP93GVRma3n`T=`^DlFy6NVAGV@vxpEZ^M%rlm4uPl*F z_c>iNEw_S#dOmfSdy_NhrsbUG+83PDhcQ;Vwpz}I5}oGq*g7(-i*nw|oX}lemut1> zU<|Iydao|~_503rx0bH-NG_0d%%F{z^MSZ;u#PQSzFWUgmEK;?b(!L-*paK(QpR5s zu2h-(X})3prW3#w7#K5zKl<-$Ghb$h7vM9b4|c8ORm|FK~I`%skENtDEMW=k*Szj z3%6*w-AI%q>>6RpgxH3c=Bv-2efg#1L+2yu>*;w1sBQm#*hJh2YD~pRLv(9FMd4Ov zwGg}TmJ-x_&$<~AF*(d$uJ{n&KyjEbiy~|Za_INy1sAjuaxAhi3s$q@WN}Lp*#U_AuF`%#fI@%fuTPcBGO7tkfr_W}v~4IVUR3j+MHr*smcN zR6LLR#FGGFzv}0+PE9Co&Gf4pN4?tkk#kCMYmNxDtxh2k9iNJm`A8VQqMBeWam6wL z+p;KJMQ~FxKA~9g?X)T*-B3LvlbO*hrbve$)0*In!B*J?ZE1`1NVCh z+m6ZGjuq;U%k{?#-V=H62^eZ?f{Q2e&4VjX7rgsr@BVdLb=8h9{lUcxa{a(cTfu)+ z_8(pIpIr5yEcj2!{!{A?WPpVSp-?S*vS%JPwk(}l?k_a%mmBv(eh;>;1-GvTx39SJ z!R>|MemS^*EqHu2c)SoCl7mB8{Czh{TX`);1dK9_w1Ztm=fVqFj*P{)MO zCCk!<_p6qwa`R)5~78^s0_J^Tn2pTo-*W_Y_P_G>7{h?#gvbgJEu;I?|-81i= z$pv!XDg=AvV9%mu-Nn@fpHLVX#I`J+$}VIVQ0RIbNwAy*-{%a3nzxdAQorTUba_5=F=ZlSlzZdemE~Ope?<02*8F=`{d-p81^+X$|Czl1nSWUC#1OH; zVxkYjaJE9n8M^@P(Lo{{vA)NLKxW@|X_{3Iw>BOd)Mbb|Mj-9|77wm8| z!Q{QcedNfH*c65Nn#8fvQTBK~!7WuG4%~7*;qA>0?-g&0Ek?t8)&-ZC4K6W9Wn0bc zL9}O_C3XKIi-vc^7BGam$MoVwRsNjW0SsM!S6XO;LFAJSY2wF5Rwc`TC@=nZ7k5g?m) z=IMw3ajV(?sIm+9H2f6I|7aCQQKMp+F&Wpsi+e_A<3<)}v<_;{#{Yn~q<(-KTt0YA zJ(s`rz=9OT=&#jpTdm&)+Ew2x*Z1l{gz#9x=qeIS zSU9HUVWqx^KLJpxsE2G@huNE2b!ZaNAlGNaBlG2*2Ai;WL;tiF9->^S7vL+^qLA;u zfb+q(mSZb(`N*^Cr4h28jfAVjC2H110L7y&H^MP3Jr;xHQ#O_SF=cZkq}Z6G*kD!D z%qAqJFv2K)YA6U;3R#Htm6GCjDA%6?7(F;8KkAQh+h|GKIH~`RUi>qFQV-XI+?M(^ z|BhAvj^%v?|8Cj88_ceuJ!k)@cEus@eD=XM`PfVO`tw;&kxlr@4oqtycuWo+%T|36 zY$9E`g#mCu;$CZ^-qjGIxKuWgJ*~6GT(D5LU9Q^>Zc@|oS+{W*KM&)o(0@S&+;KtP zae?J2HZ(7K=Wl;rs5(~f-=PI}u{{I~2)EQDW3ttEb4K&uR!+28xNmdQ_G{dA+qb!E zmTzR&fi|$wZwy`ER6A+y8Jp!Tg|3zx4WqZBRjjSd%7~%dSlkm_Ha+u;Xg(VpQs%GT)=i6`ZK?e8mqgx zK~Az?v#KLX<7>fR9Ly1#Xm{G6EB-b=bR43=IyHFfPC+CkjzLBQvNgR&i`ZB5JVV`FzU=g{2wG)L835e*PnH zPCmA=+CIcMVcSev@@TbVUlkuufhkR=(mditlGwCT(UjhBCx0#}fG~l#UB}xIPcOL< zY3EAWg$QY3dN!8iXW>&8`L1&7&Xs!HRqCj^B_{0Y3fC%rZ8)M#dx10B{emzzB#J3f ze)WS_v?J=N_ly)DUYiv*x(-K8fDb_>^st*Dv6+7vMN)>J6!2X=11f`M6 zmy}xCwZm?)3Snj>a;~ae)uo0pjmyO*3LDUD2@Z3PJ`+OKjnjEPz8*p#B2S z=NoidVQTv?@l3h`B7pcCyRB*qgnhZLcNt(X?;ZT=p|26ttct~1ssJ{{>MJNjh=J{23-qrB`j_J?!}q^a2%MG!r?akNcqb`hZA+5{_x3M*4OC3aQe18yklT;3 zi(*}Kb_Cvdxo#_T4YGQJN&;k$7kz=n$y?vgem__DN9}*u4xf1UpVkyQkI0=zvfnTI z>lYpCHqPG;xj)#F9r+S5La)M99xv2%%Qf9pHlKR~8p++O?_T}k^*h(Ir>MO=d%(aW z%7X0x#(U+bCkv16^x@!PUTEJ}?N)<S}+*0jzV5n%Z?QLUFRSQac9y2VNidj;Gc3V@s>;FZuf87TaH0?8hChzj9ju zO~MxuYDTQ5ksuSR(ZFgX&SkwJNBK7#8@D~tcBS$br#O|YlT~I`v5uUC-}GOgCq~A)vzl`b;*Dg2>TuHKff9#mzbL+>8S*=2rE z<`3RKUZ{Iku6s7`eHJS>>rp3!CP6z0r`Uw_qNcZPZ@bM=4mT^9)h!4Fn>&#p66h1X zi6~*u+Mst@pm%PfBd1B|DIMi0c!DFT!t@T!x<-2!!byehd&`}5qh5r7-n3Qfy9+MU z#xdP&j#6A^;lq5zT;F?7GTYua4FEGy4;uU3_zj3A zTCt7A;{X5MYNBrS7`heMmk;b)>RJx0>|SnLZd=?%kp6HRC+iOMtP#8-P7zEcft%oJ_6ZDX|Ex`zv$v*;7};1ZIh z@CGl7i&+Z{tOf>FyoJDFIdC}ZdRV({_9C3k z4Htraaz94~d3V2x7DmoUssW=*?<4WH)l8MjD+1I=r#i@}AMuSrpHIlSF+9{v z_!n$ht4cvK8z=~)1b?GjhUO9iY&tWgV9x&1zVUI$@oby98dAykO0(*IY9`}S0Ht04 z_7zM_BZ>-BALc2xlaKL~p`SGUINRAxua95iW0L+7?G29TECb#L+Md8}YPev07}noo z)lh^^=`q>RO1=bx#mO8zMzg{etB8bQu?~K-aQB<0ZMBt7fAjd4DBLc6=_5v@Z1W%n zD-sMp*YR1!P)(YgeTzSwuH1W_%pZ8EH(b5 zZ~0oGYoFY;ujGMn=y}U;=_!?T*bKB{in?LPW^a6Nzz~e<6=T=P90gC(v?LMlCIX=9 z4@7e2JAO;I+Nci#_2CBhYd;t2yz?f7ADp^%YVoC|K*8H8dt0>|uP%+L;RT3l3sF>C z$dmQ1yEo~GlWXl=cj3V!>JkEU*|=1xA_nFtj0zbTVK8h_e|l)kJLzNC@(#ta6ps~E zywT_zPzg&RFt3!|}VXrAoj1lZEdym}%z-o>W~bP|XVI7)zc zsyIa8IRY05kcm_rBS3zA7GEk7N{iPB5OEdBJukjVfZ|9*GI)qD5^xhBGAjN#fxjR? z^0O)d5*1dw^wE>VI4t6qQgOx(l$z2G>~R56Zcz*Zi*m(;a3#}P3l%|t{JqjEAZD1Q z^544E<#4Za1pHhJf8)i)r}Op>oCSMF@u`8ly=iHG?l?B;+mRk9*az0_P6q-)bl~Tn zx4d8}c5hv`xg6MI{Ui{mb&$i&0C|T44musw+8rH0d<}SQj#J2QfF3uyV}L=gWA8er zgI1s8S-fI^U3RJhU?sRR{&U#;wChb%UZ>+g?!)kflA+La^=V4pc7(csC_Xc&bvk-idhhRfQ1@W`LFgAp9$w1SPbhQ zq_a4LZTd{qf(6_EXmOT~vXu~4HsJp!vk>&ePXSn6YO5uXUcst`Dk~C|(*D6WG_MeclB|uxTE)^Hh>HHxti3sD6uuge^L@ zN#$#1%jym5AAf;!X%;&~cf^v{Vsp|Ca$XJeO9H+dMIZ8DrAfRNqCieEqeqDq#*Ay) zru#mA$25KIX@|K%@F%HF;duz1WiI&7F_4O1w^~J1qm}q~blXjl4%bBNHFaVG2h324 zGf5vQnE}Uq4H?v2wkc`Ste3t^&j`?W7o-^^pn_J{+}`)j;ai87f`#gKxw@TDIS6-t zwz_BsVKSYtKviwI?E?j?@jkLuRe?tU{C$9{-g0aE&EDI+MNjRcdQX)P79)_iX0EzD z?`c~aFL=6SPgmaFr3!_pSU)tJc}!%!{NW|-vrBMma-)v89S|Q`0(8acBTMeM3xb+k zBuR4q$Z34AMx5dipdm__1$-GulYiKkc<3t$WDqR{oWvn%@jbLxhG}{|vCpttXbw(K zgV-k#Ix@-sqjIc7r?@~bu>2?_UizAs5XW~HRI4Zjj=(HR!q&x7#nMG}T01*EDuQ)? z&A||$n?I)-O8INdjR@+ zS(&i~HxAS-ts1yj34PV?C&4$HoMSy6!&lQVr!=(WiYAjQd5ZO!lT>py^Dd7Gmtt2F zm~ON`nYbdL269{D15%T!n-?!m%wm6+pnZG^epqAU`CipiErBqujbL3!3S zKXl0=PM;*>B`TKTT}9t3kS?Z;I6pQAYz3mRetzu;<0Dm2K+rMD1?M>wM;fki3eTV8 zRk=h}9D3=yQ^NJw6wp$yfWOH0W^J^V_eLU-@Wp|O#|JO67QqpphSi)#NX?+3wehWk z7qzkYHoj6t?tQYft6#o~jls#ycWKK|Z*UiLu6LEEu!~&rWfWqyLri2}-(pfBhHO$$ z7n8?>#!c&KmtMFmK=UJ9+iYMRt6@4#-%S%syK$I{ z*%T~r4-KF1dg2i2VR2(LMthMNUQ=J)I}5iKmR>ISx@BK?-gkQ0zWn-U(#oEn&VM?; zd}aA{x%c2&@9=8xaH03K+N~l=_hZaE!!+N zH#{R&h|~;rn6+DTUF0AYLvc%vl#LAsEESfF{SPYw@F8+R?4oU3uiy<>n5b`x6Ospp zUo}i!qB~V-P@ij;Xg4TRm;Rn^I_SfelDf&Fw8i=#a9<4u_&1dL-vIiy>XO#^0q)I5 zo;+=vg)j;W#66BGdu|e z%xzM?zR3{4j*pOv{|xW{EsX+VYRSVneuaGq3|R5Ma8vwm1pYgK;(BrD{Q2jGhZHAC zL-{?Hq|{o+#hzwdbFb4%X) ze8Ky??0p^ySSw`utPE|!%OUo%^jR5vSq3NK7rnbsJVObJq4|&0bixAhmjwPZf&W9` zF#)1MB4M=J@iUa7_-WO^LNX&09EYeE7jbn%|0~*0=HOG^D$0{@x-5e%`8fCb&AF9)SBA>6G*TGDg0msd5M z5TQ~HCmu?X!pBS~N=KPbN1~cUgvd9>GU;`OVFqpvzXMsgBJ?p#wxykkiOg)ycIz-* zgiVDSO|H)oHl?aoq$6TAT8opD-T{PX*Cm;gwLHGo3~5SpJ)wUvQ`L=CjBh%A3!1 zr^Nz0hz{H@+bysfY!0*O+Y67_vtJo=%(w#1BTcC7u<~u Aj{pDw diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/develop.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/develop.cpython-311.pyc deleted file mode 100755 index 228a27f979af7029088c613a2b9eac6ad2e3b0e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10919 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/dist_info.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/dist_info.cpython-311.pyc deleted file mode 100755 index c0149f2657da96bd33b39c3e2ff37451173d7cb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7981 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 TaUhE}@bTPBNW|TMG2wpzKqX0S diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/easy_install.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/easy_install.cpython-311.pyc deleted file mode 100755 index fc683811a02341a9cff7d663722d1051f2252719..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121501 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�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 diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/egg_info.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/egg_info.cpython-311.pyc deleted file mode 100755 index 5a9e4acede8bfe5eac71e2c354b778ca6caaf5d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40839 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 LXtc&YCi?#Z&8$nx diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-311.pyc deleted file mode 100755 index 8bb5fa15de77d81d1914a30e22af23678b8a41f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5342 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_lib.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_lib.cpython-311.pyc deleted file mode 100755 index 98be08bb9e2f1026a9d584c8e3b37d49e0b7ea43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8413 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 bN{+WI6rA(tD3v7QWSZ@oQ+TAq6Q+4&|9N!_YRH zWAnZY%b+}$<{geN=g$Yyf!3&y796QyItWiL7s`jz;k=j@VVqa|xt@F^9bpiQt|BFH zA1Q*$FL3VCk9`O|g@3c8IfcE6#)Dte?l?nyIX!zFo`aK`VU|oSXUynIDW^_htmAQ( zh?I}DSs2m_MEt32&d;c(tjMPPHQQ9trxuJ7RwYHlYR1&@Ql`07lTsmCUK|FphE$Yh z6qIHaChb$$`v~mu0p*o|!ry1oe#H;g38Ysm7^a-dNk#^1MblWmFsUaBI?l_vM3a?h zNt{R&b0s4o7nTxgHY;g`IX$t63JaiT0t{4Ij1eFl3t{4GzeeNCAA1{ z=L|JBXHboa?>v=VmmvKfYiG-m&$3gsp673uNU5$ICUyzXr_9y zC}-}8} z+bs&)?cFlkJ;e*|4MI3!itZeQ7U+6TsS0kZ{keC~3V|%xAO&41SjD-ww2xW3hhSmY z9c_PhTUcSuq22K^yFgv+6f^F&;MBD7q223_Jccv&)H`P|(&vsqJL>y;tGPF;@rJz$u)9I+38l2VeiDe3v$Vhc>vSN}x+ypfL0%GU+9674xXuLTHXn zB21AjPzl^d1#S_2=(~*;nKH8wbEPUmIe>$TP~m~QuZ_!_6K)Uo`+(cN>-Y})%6yiA zIYPBH%ArpXgI0SSlnGwP^!170Vjk(4EonK$#Y+-WKU6a%Q=ZMKFr)y8 zON(&V0aZy@(hLcg3ed}5Sq?Q}Wdh{KN6F|emQ1v;WI~mVCBRh&k4d1#C1M9V4EiK* zh%V>Fj6e&*F}<}-Nc4d;5%iKdr{z=wQ^X;$tZGVgTEPKI#npxBwQs)VtZb;*Pjw7< zyn>upNtpWJo{9|`p#q>rHcd>z*YZUjn@$|V^a2s_rV~rv#{iy~47{%u6n)X?VET+D z1Je^pxLFlk)!%w0$tbEBDU*{8gM{X=o|lR;mh(iQM$0&Bkf3Zx^Qx?XW^s|O(AtUd zFs3)2u&PG^Sdcf0(KI!t`dRJxc!(J8T8Fhveb z56bdDH@<_X`(eQNJH(h3)DTYBUQ@RPaZ@<3AskpgSQnDEkgN&GM!44wkJ#bl4)O&@ zx5PeMOl*qD4KZ2$d0jkai^pnC-5xn)O|H&>`0Cp`hz$;Gi~ZJ>?PzQ>dVC{#{K<4Z zde)AfwftMX!ws>2^~Ps+o*e!%_56o_{ZT#st{s2ZVXoh@NU%q^~9UXWyYWW-C z7=51;jiE7Xx)IxN$BtW9fce?L9}aDVkJQ3PcKm2~Y<@# zkt3Ut6C05e^~i)Bnb?e+--w)leykpuvLjQLuQ7OV?Z(3!)yXGs{`usePJWU4GF2aZ z+a3h}F~Kp1Sd$GgZcW-^eBG>x$!4VnHir$muV3{Y{>fSN)!Bi`9^cM1jwI9Cb4 zDqbY6dT|)+^-4L=8H;G1TlVk4b+q8cY~xNxT;4O^Y{T?&K;g>1Wmv7tvLN6#1*Scv zyf;q?R=ud+F5YRQV>b`$L9AMaH|<;xVk2a}PWBsEKILE(goYfbb9z)y@BZUPOu#tgzNYX5x$SxEL(W!DJvh8RR!x3-qAnh>#UnMh?u20hXBAAdNBF42=ixaXAcEw0S&~RdlEA<4c?WG# zl73l|bJYLP3rLcpXC%q_OmJcerq28VIm((5hI-ry;Pj>$GeB0nUxS;faZ@`S%MSx$ zx3oki&*2+h-^)w7wi(m>&oR%*G)Uj>43&P& z8cr5~FHOFLoeYBWFZtNo&19E5RJ`w=LF-MluP~TxZpeCV$*+@@NMAH z?>6HvKme5)rh$fPowb3!Uwch$pi{NZ+Cae-=hr}?73a5&PS;*l8z@=ptULY-3^;Z# Td7#+)j(tN1zJ0~0^J4!62*3x6 diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/py36compat.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/py36compat.cpython-311.pyc deleted file mode 100755 index 59c4872de83bb776fdab7af50d5d854e55d63a6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8037 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 D-&$cl diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/sdist.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/sdist.cpython-311.pyc deleted file mode 100755 index c95532ce0a0c392d8aada5185b5c7af06be4c3b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13439 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 V_tLN-he7fEee8Yyk|DBJ{|9q{3yA;# diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/test.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/test.cpython-311.pyc deleted file mode 100755 index 7544506f25591d06f35a150fe5b10a12f0d62c28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14620 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 H%tQJIEcOu= diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload_docs.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload_docs.cpython-311.pyc deleted file mode 100755 index 781ab4ebbfc7dc9261134b4e812489acf03eb2d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11942 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.+)\.(?P[^.]+)\.pyc' - m = re.match(pattern, name) - path_new = os.path.join( - base, os.pardir, m.group('name') + '.pyc') - log.info( - "Renaming file from [%s] to [%s]" - % (path_old, path_new)) - try: - os.remove(path_new) - except OSError: - pass - os.rename(path_old, path_new) - - def zip_safe(self): - safe = getattr(self.distribution, 'zip_safe', None) - if safe is not None: - return safe - log.warn("zip_safe flag not set; analyzing archive contents...") - return analyze_egg(self.bdist_dir, self.stubs) - - def gen_header(self): - return 'w' - - def copy_metadata_to(self, target_dir): - "Copy metadata (egg info) to the target_dir" - # normalize the path (so that a forward-slash in egg_info will - # match using startswith below) - norm_egg_info = os.path.normpath(self.egg_info) - prefix = os.path.join(norm_egg_info, '') - for path in self.ei_cmd.filelist.files: - if path.startswith(prefix): - target = os.path.join(target_dir, path[len(prefix):]) - ensure_directory(target) - self.copy_file(path, target) - - def get_ext_outputs(self): - """Get a list of relative paths to C extensions in the output distro""" - - all_outputs = [] - ext_outputs = [] - - paths = {self.bdist_dir: ''} - for base, dirs, files in sorted_walk(self.bdist_dir): - for filename in files: - if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS: - all_outputs.append(paths[base] + filename) - for filename in dirs: - paths[os.path.join(base, filename)] = (paths[base] + - filename + '/') - - if self.distribution.has_ext_modules(): - build_cmd = self.get_finalized_command('build_ext') - for ext in build_cmd.extensions: - if isinstance(ext, Library): - continue - fullname = build_cmd.get_ext_fullname(ext.name) - filename = build_cmd.get_ext_filename(fullname) - if not os.path.basename(filename).startswith('dl-'): - if os.path.exists(os.path.join(self.bdist_dir, filename)): - ext_outputs.append(filename) - - return all_outputs, ext_outputs - - -NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split()) - - -def walk_egg(egg_dir): - """Walk an unpacked egg's contents, skipping the metadata directory""" - walker = sorted_walk(egg_dir) - base, dirs, files = next(walker) - if 'EGG-INFO' in dirs: - dirs.remove('EGG-INFO') - yield base, dirs, files - for bdf in walker: - yield bdf - - -def analyze_egg(egg_dir, stubs): - # check for existing flag in EGG-INFO - for flag, fn in safety_flags.items(): - if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)): - return flag - if not can_scan(): - return False - safe = True - for base, dirs, files in walk_egg(egg_dir): - for name in files: - if name.endswith('.py') or name.endswith('.pyw'): - continue - elif name.endswith('.pyc') or name.endswith('.pyo'): - # always scan, even if we already know we're not safe - safe = scan_module(egg_dir, base, name, stubs) and safe - return safe - - -def write_safety_flag(egg_dir, safe): - # Write or remove zip safety flag file(s) - for flag, fn in safety_flags.items(): - fn = os.path.join(egg_dir, fn) - if os.path.exists(fn): - if safe is None or bool(safe) != flag: - os.unlink(fn) - elif safe is not None and bool(safe) == flag: - f = open(fn, 'wt') - f.write('\n') - f.close() - - -safety_flags = { - True: 'zip-safe', - False: 'not-zip-safe', -} - - -def scan_module(egg_dir, base, name, stubs): - """Check whether module possibly uses unsafe-for-zipfile stuff""" - - filename = os.path.join(base, name) - if filename[:-1] in stubs: - return True # Extension module - pkg = base[len(egg_dir) + 1:].replace(os.sep, '.') - module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0] - if sys.version_info < (3, 7): - skip = 12 # skip magic & date & file size - else: - skip = 16 # skip magic & reserved? & date & file size - f = open(filename, 'rb') - f.read(skip) - code = marshal.load(f) - f.close() - safe = True - symbols = dict.fromkeys(iter_symbols(code)) - for bad in ['__file__', '__path__']: - if bad in symbols: - log.warn("%s: module references %s", module, bad) - safe = False - if 'inspect' in symbols: - for bad in [ - 'getsource', 'getabsfile', 'getsourcefile', 'getfile' - 'getsourcelines', 'findsource', 'getcomments', 'getframeinfo', - 'getinnerframes', 'getouterframes', 'stack', 'trace' - ]: - if bad in symbols: - log.warn("%s: module MAY be using inspect.%s", module, bad) - safe = False - return safe - - -def iter_symbols(code): - """Yield names and strings used by `code` and its nested code objects""" - for name in code.co_names: - yield name - for const in code.co_consts: - if isinstance(const, str): - yield const - elif isinstance(const, CodeType): - for name in iter_symbols(const): - yield name - - -def can_scan(): - if not sys.platform.startswith('java') and sys.platform != 'cli': - # CPython, PyPy, etc. - return True - log.warn("Unable to analyze compiled code on this platform.") - log.warn("Please ask the author to include a 'zip_safe'" - " setting (either True or False) in the package's setup.py") - - -# Attribute names of options for commands that might need to be convinced to -# install to the egg build directory - -INSTALL_DIRECTORY_ATTRS = [ - 'install_lib', 'install_dir', 'install_data', 'install_base' -] - - -def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True, - mode='w'): - """Create a zip file from all the files under 'base_dir'. The output - zip file will be named 'base_dir' + ".zip". Uses either the "zipfile" - Python module (if available) or the InfoZIP "zip" utility (if installed - and found on the default search path). If neither tool is available, - raises DistutilsExecError. Returns the name of the output zip file. - """ - import zipfile - - mkpath(os.path.dirname(zip_filename), dry_run=dry_run) - log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir) - - def visit(z, dirname, names): - for name in names: - path = os.path.normpath(os.path.join(dirname, name)) - if os.path.isfile(path): - p = path[len(base_dir) + 1:] - if not dry_run: - z.write(path, p) - log.debug("adding '%s'", p) - - compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED - if not dry_run: - z = zipfile.ZipFile(zip_filename, mode, compression=compression) - for dirname, dirs, files in sorted_walk(base_dir): - visit(z, dirname, files) - z.close() - else: - for dirname, dirs, files in sorted_walk(base_dir): - visit(None, dirname, files) - return zip_filename diff --git a/venv/lib/python3.11/site-packages/setuptools/command/bdist_rpm.py b/venv/lib/python3.11/site-packages/setuptools/command/bdist_rpm.py deleted file mode 100755 index 98bf5de..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/bdist_rpm.py +++ /dev/null @@ -1,40 +0,0 @@ -import distutils.command.bdist_rpm as orig -import warnings - -from setuptools import SetuptoolsDeprecationWarning - - -class bdist_rpm(orig.bdist_rpm): - """ - Override the default bdist_rpm behavior to do the following: - - 1. Run egg_info to ensure the name and version are properly calculated. - 2. Always run 'install' using --single-version-externally-managed to - disable eggs in RPM distributions. - """ - - def run(self): - warnings.warn( - "bdist_rpm is deprecated and will be removed in a future " - "version. Use bdist_wheel (wheel packages) instead.", - SetuptoolsDeprecationWarning, - ) - - # ensure distro name is up-to-date - self.run_command('egg_info') - - orig.bdist_rpm.run(self) - - def _make_spec_file(self): - spec = orig.bdist_rpm._make_spec_file(self) - spec = [ - line.replace( - "setup.py install ", - "setup.py install --single-version-externally-managed " - ).replace( - "%setup", - "%setup -n %{name}-%{unmangled_version}" - ) - for line in spec - ] - return spec diff --git a/venv/lib/python3.11/site-packages/setuptools/command/build.py b/venv/lib/python3.11/site-packages/setuptools/command/build.py deleted file mode 100755 index fa3c99e..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/build.py +++ /dev/null @@ -1,146 +0,0 @@ -import sys -import warnings -from typing import TYPE_CHECKING, List, Dict -from distutils.command.build import build as _build - -from setuptools import SetuptoolsDeprecationWarning - -if sys.version_info >= (3, 8): - from typing import Protocol -elif TYPE_CHECKING: - from typing_extensions import Protocol -else: - from abc import ABC as Protocol - - -_ORIGINAL_SUBCOMMANDS = {"build_py", "build_clib", "build_ext", "build_scripts"} - - -class build(_build): - # copy to avoid sharing the object with parent class - sub_commands = _build.sub_commands[:] - - def get_sub_commands(self): - subcommands = {cmd[0] for cmd in _build.sub_commands} - if subcommands - _ORIGINAL_SUBCOMMANDS: - msg = """ - It seems that you are using `distutils.command.build` to add - new subcommands. Using `distutils` directly is considered deprecated, - please use `setuptools.command.build`. - """ - warnings.warn(msg, SetuptoolsDeprecationWarning) - self.sub_commands = _build.sub_commands - return super().get_sub_commands() - - -class SubCommand(Protocol): - """In order to support editable installations (see :pep:`660`) all - build subcommands **SHOULD** implement this protocol. They also **MUST** inherit - from ``setuptools.Command``. - - When creating an :pep:`editable wheel <660>`, ``setuptools`` will try to evaluate - custom ``build`` subcommands using the following procedure: - - 1. ``setuptools`` will set the ``editable_mode`` attribute to ``True`` - 2. ``setuptools`` will execute the ``run()`` command. - - .. important:: - Subcommands **SHOULD** take advantage of ``editable_mode=True`` to adequate - its behaviour or perform optimisations. - - For example, if a subcommand doesn't need to generate an extra file and - all it does is to copy a source file into the build directory, - ``run()`` **SHOULD** simply "early return". - - Similarly, if the subcommand creates files that would be placed alongside - Python files in the final distribution, during an editable install - the command **SHOULD** generate these files "in place" (i.e. write them to - the original source directory, instead of using the build directory). - Note that ``get_output_mapping()`` should reflect that and include mappings - for "in place" builds accordingly. - - 3. ``setuptools`` use any knowledge it can derive from the return values of - ``get_outputs()`` and ``get_output_mapping()`` to create an editable wheel. - When relevant ``setuptools`` **MAY** attempt to use file links based on the value - of ``get_output_mapping()``. Alternatively, ``setuptools`` **MAY** attempt to use - :doc:`import hooks ` to redirect any attempt to import - to the directory with the original source code and other files built in place. - - Please note that custom sub-commands **SHOULD NOT** rely on ``run()`` being - executed (or not) to provide correct return values for ``get_outputs()``, - ``get_output_mapping()`` or ``get_source_files()``. The ``get_*`` methods should - work independently of ``run()``. - """ - - editable_mode: bool = False - """Boolean flag that will be set to ``True`` when setuptools is used for an - editable installation (see :pep:`660`). - Implementations **SHOULD** explicitly set the default value of this attribute to - ``False``. - When subcommands run, they can use this flag to perform optimizations or change - their behaviour accordingly. - """ - - build_lib: str - """String representing the directory where the build artifacts should be stored, - e.g. ``build/lib``. - For example, if a distribution wants to provide a Python module named ``pkg.mod``, - then a corresponding file should be written to ``{build_lib}/package/module.py``. - A way of thinking about this is that the files saved under ``build_lib`` - would be eventually copied to one of the directories in :obj:`site.PREFIXES` - upon installation. - - A command that produces platform-independent files (e.g. compiling text templates - into Python functions), **CAN** initialize ``build_lib`` by copying its value from - the ``build_py`` command. On the other hand, a command that produces - platform-specific files **CAN** initialize ``build_lib`` by copying its value from - the ``build_ext`` command. In general this is done inside the ``finalize_options`` - method with the help of the ``set_undefined_options`` command:: - - def finalize_options(self): - self.set_undefined_options("build_py", ("build_lib", "build_lib")) - ... - """ - - def initialize_options(self): - """(Required by the original :class:`setuptools.Command` interface)""" - - def finalize_options(self): - """(Required by the original :class:`setuptools.Command` interface)""" - - def run(self): - """(Required by the original :class:`setuptools.Command` interface)""" - - def get_source_files(self) -> List[str]: - """ - Return a list of all files that are used by the command to create the expected - outputs. - For example, if your build command transpiles Java files into Python, you should - list here all the Java files. - The primary purpose of this function is to help populating the ``sdist`` - with all the files necessary to build the distribution. - All files should be strings relative to the project root directory. - """ - - def get_outputs(self) -> List[str]: - """ - Return a list of files intended for distribution as they would have been - produced by the build. - These files should be strings in the form of - ``"{build_lib}/destination/file/path"``. - - .. note:: - The return value of ``get_output()`` should include all files used as keys - in ``get_output_mapping()`` plus files that are generated during the build - and don't correspond to any source file already present in the project. - """ - - def get_output_mapping(self) -> Dict[str, str]: - """ - Return a mapping between destination files as they would be produced by the - build (dict keys) into the respective existing (source) files (dict values). - Existing (source) files should be represented as strings relative to the project - root directory. - Destination files should be strings in the form of - ``"{build_lib}/destination/file/path"``. - """ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/build_clib.py b/venv/lib/python3.11/site-packages/setuptools/command/build_clib.py deleted file mode 100755 index 09483e6..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/build_clib.py +++ /dev/null @@ -1,101 +0,0 @@ -import distutils.command.build_clib as orig -from distutils.errors import DistutilsSetupError -from distutils import log -from setuptools.dep_util import newer_pairwise_group - - -class build_clib(orig.build_clib): - """ - Override the default build_clib behaviour to do the following: - - 1. Implement a rudimentary timestamp-based dependency system - so 'compile()' doesn't run every time. - 2. Add more keys to the 'build_info' dictionary: - * obj_deps - specify dependencies for each object compiled. - this should be a dictionary mapping a key - with the source filename to a list of - dependencies. Use an empty string for global - dependencies. - * cflags - specify a list of additional flags to pass to - the compiler. - """ - - def build_libraries(self, libraries): - for (lib_name, build_info) in libraries: - sources = build_info.get('sources') - if sources is None or not isinstance(sources, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'sources' must be present and must be " - "a list of source filenames" % lib_name) - sources = sorted(list(sources)) - - log.info("building '%s' library", lib_name) - - # Make sure everything is the correct type. - # obj_deps should be a dictionary of keys as sources - # and a list/tuple of files that are its dependencies. - obj_deps = build_info.get('obj_deps', dict()) - if not isinstance(obj_deps, dict): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - dependencies = [] - - # Get the global dependencies that are specified by the '' key. - # These will go into every source's dependency list. - global_deps = obj_deps.get('', list()) - if not isinstance(global_deps, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - - # Build the list to be used by newer_pairwise_group - # each source will be auto-added to its dependencies. - for source in sources: - src_deps = [source] - src_deps.extend(global_deps) - extra_deps = obj_deps.get(source, list()) - if not isinstance(extra_deps, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - src_deps.extend(extra_deps) - dependencies.append(src_deps) - - expected_objects = self.compiler.object_filenames( - sources, - output_dir=self.build_temp, - ) - - if ( - newer_pairwise_group(dependencies, expected_objects) - != ([], []) - ): - # First, compile the source code to object files in the library - # directory. (This should probably change to putting object - # files in a temporary build directory.) - macros = build_info.get('macros') - include_dirs = build_info.get('include_dirs') - cflags = build_info.get('cflags') - self.compiler.compile( - sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=include_dirs, - extra_postargs=cflags, - debug=self.debug - ) - - # Now "link" the object files together into a static library. - # (On Unix at least, this isn't really linking -- it just - # builds an archive. Whatever.) - self.compiler.create_static_lib( - expected_objects, - lib_name, - output_dir=self.build_clib, - debug=self.debug - ) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/build_ext.py b/venv/lib/python3.11/site-packages/setuptools/command/build_ext.py deleted file mode 100755 index cbfe3ec..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/build_ext.py +++ /dev/null @@ -1,383 +0,0 @@ -import os -import sys -import itertools -from importlib.machinery import EXTENSION_SUFFIXES -from importlib.util import cache_from_source as _compiled_file_name -from typing import Dict, Iterator, List, Tuple - -from distutils.command.build_ext import build_ext as _du_build_ext -from distutils.ccompiler import new_compiler -from distutils.sysconfig import customize_compiler, get_config_var -from distutils import log - -from setuptools.errors import BaseError -from setuptools.extension import Extension, Library - -try: - # Attempt to use Cython for building extensions, if available - from Cython.Distutils.build_ext import build_ext as _build_ext - # Additionally, assert that the compiler module will load - # also. Ref #1229. - __import__('Cython.Compiler.Main') -except ImportError: - _build_ext = _du_build_ext - -# make sure _config_vars is initialized -get_config_var("LDSHARED") -from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa - - -def _customize_compiler_for_shlib(compiler): - if sys.platform == "darwin": - # building .dylib requires additional compiler flags on OSX; here we - # temporarily substitute the pyconfig.h variables so that distutils' - # 'customize_compiler' uses them before we build the shared libraries. - tmp = _CONFIG_VARS.copy() - try: - # XXX Help! I don't have any idea whether these are right... - _CONFIG_VARS['LDSHARED'] = ( - "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup") - _CONFIG_VARS['CCSHARED'] = " -dynamiclib" - _CONFIG_VARS['SO'] = ".dylib" - customize_compiler(compiler) - finally: - _CONFIG_VARS.clear() - _CONFIG_VARS.update(tmp) - else: - customize_compiler(compiler) - - -have_rtld = False -use_stubs = False -libtype = 'shared' - -if sys.platform == "darwin": - use_stubs = True -elif os.name != 'nt': - try: - import dl - use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW') - except ImportError: - pass - - -def if_dl(s): - return s if have_rtld else '' - - -def get_abi3_suffix(): - """Return the file extension for an abi3-compliant Extension()""" - for suffix in EXTENSION_SUFFIXES: - if '.abi3' in suffix: # Unix - return suffix - elif suffix == '.pyd': # Windows - return suffix - - -class build_ext(_build_ext): - editable_mode: bool = False - inplace: bool = False - - def run(self): - """Build extensions in build directory, then copy if --inplace""" - old_inplace, self.inplace = self.inplace, 0 - _build_ext.run(self) - self.inplace = old_inplace - if old_inplace: - self.copy_extensions_to_source() - - def _get_inplace_equivalent(self, build_py, ext: Extension) -> Tuple[str, str]: - fullname = self.get_ext_fullname(ext.name) - filename = self.get_ext_filename(fullname) - modpath = fullname.split('.') - package = '.'.join(modpath[:-1]) - package_dir = build_py.get_package_dir(package) - inplace_file = os.path.join(package_dir, os.path.basename(filename)) - regular_file = os.path.join(self.build_lib, filename) - return (inplace_file, regular_file) - - def copy_extensions_to_source(self): - build_py = self.get_finalized_command('build_py') - for ext in self.extensions: - inplace_file, regular_file = self._get_inplace_equivalent(build_py, ext) - - # Always copy, even if source is older than destination, to ensure - # that the right extensions for the current Python/platform are - # used. - if os.path.exists(regular_file) or not ext.optional: - self.copy_file(regular_file, inplace_file, level=self.verbose) - - if ext._needs_stub: - inplace_stub = self._get_equivalent_stub(ext, inplace_file) - self._write_stub_file(inplace_stub, ext, compile=True) - # Always compile stub and remove the original (leave the cache behind) - # (this behaviour was observed in previous iterations of the code) - - def _get_equivalent_stub(self, ext: Extension, output_file: str) -> str: - dir_ = os.path.dirname(output_file) - _, _, name = ext.name.rpartition(".") - return f"{os.path.join(dir_, name)}.py" - - def _get_output_mapping(self) -> Iterator[Tuple[str, str]]: - if not self.inplace: - return - - build_py = self.get_finalized_command('build_py') - opt = self.get_finalized_command('install_lib').optimize or "" - - for ext in self.extensions: - inplace_file, regular_file = self._get_inplace_equivalent(build_py, ext) - yield (regular_file, inplace_file) - - if ext._needs_stub: - # This version of `build_ext` always builds artifacts in another dir, - # when "inplace=True" is given it just copies them back. - # This is done in the `copy_extensions_to_source` function, which - # always compile stub files via `_compile_and_remove_stub`. - # At the end of the process, a `.pyc` stub file is created without the - # corresponding `.py`. - - inplace_stub = self._get_equivalent_stub(ext, inplace_file) - regular_stub = self._get_equivalent_stub(ext, regular_file) - inplace_cache = _compiled_file_name(inplace_stub, optimization=opt) - output_cache = _compiled_file_name(regular_stub, optimization=opt) - yield (output_cache, inplace_cache) - - def get_ext_filename(self, fullname): - so_ext = os.getenv('SETUPTOOLS_EXT_SUFFIX') - if so_ext: - filename = os.path.join(*fullname.split('.')) + so_ext - else: - filename = _build_ext.get_ext_filename(self, fullname) - so_ext = get_config_var('EXT_SUFFIX') - - if fullname in self.ext_map: - ext = self.ext_map[fullname] - use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix() - if use_abi3: - filename = filename[:-len(so_ext)] - so_ext = get_abi3_suffix() - filename = filename + so_ext - if isinstance(ext, Library): - fn, ext = os.path.splitext(filename) - return self.shlib_compiler.library_filename(fn, libtype) - elif use_stubs and ext._links_to_dynamic: - d, fn = os.path.split(filename) - return os.path.join(d, 'dl-' + fn) - return filename - - def initialize_options(self): - _build_ext.initialize_options(self) - self.shlib_compiler = None - self.shlibs = [] - self.ext_map = {} - self.editable_mode = False - - def finalize_options(self): - _build_ext.finalize_options(self) - self.extensions = self.extensions or [] - self.check_extensions_list(self.extensions) - self.shlibs = [ext for ext in self.extensions - if isinstance(ext, Library)] - if self.shlibs: - self.setup_shlib_compiler() - for ext in self.extensions: - ext._full_name = self.get_ext_fullname(ext.name) - for ext in self.extensions: - fullname = ext._full_name - self.ext_map[fullname] = ext - - # distutils 3.1 will also ask for module names - # XXX what to do with conflicts? - self.ext_map[fullname.split('.')[-1]] = ext - - ltd = self.shlibs and self.links_to_dynamic(ext) or False - ns = ltd and use_stubs and not isinstance(ext, Library) - ext._links_to_dynamic = ltd - ext._needs_stub = ns - filename = ext._file_name = self.get_ext_filename(fullname) - libdir = os.path.dirname(os.path.join(self.build_lib, filename)) - if ltd and libdir not in ext.library_dirs: - ext.library_dirs.append(libdir) - if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs: - ext.runtime_library_dirs.append(os.curdir) - - if self.editable_mode: - self.inplace = True - - def setup_shlib_compiler(self): - compiler = self.shlib_compiler = new_compiler( - compiler=self.compiler, dry_run=self.dry_run, force=self.force - ) - _customize_compiler_for_shlib(compiler) - - if self.include_dirs is not None: - compiler.set_include_dirs(self.include_dirs) - if self.define is not None: - # 'define' option is a list of (name,value) tuples - for (name, value) in self.define: - compiler.define_macro(name, value) - if self.undef is not None: - for macro in self.undef: - compiler.undefine_macro(macro) - if self.libraries is not None: - compiler.set_libraries(self.libraries) - if self.library_dirs is not None: - compiler.set_library_dirs(self.library_dirs) - if self.rpath is not None: - compiler.set_runtime_library_dirs(self.rpath) - if self.link_objects is not None: - compiler.set_link_objects(self.link_objects) - - # hack so distutils' build_extension() builds a library instead - compiler.link_shared_object = link_shared_object.__get__(compiler) - - def get_export_symbols(self, ext): - if isinstance(ext, Library): - return ext.export_symbols - return _build_ext.get_export_symbols(self, ext) - - def build_extension(self, ext): - ext._convert_pyx_sources_to_lang() - _compiler = self.compiler - try: - if isinstance(ext, Library): - self.compiler = self.shlib_compiler - _build_ext.build_extension(self, ext) - if ext._needs_stub: - build_lib = self.get_finalized_command('build_py').build_lib - self.write_stub(build_lib, ext) - finally: - self.compiler = _compiler - - def links_to_dynamic(self, ext): - """Return true if 'ext' links to a dynamic lib in the same package""" - # XXX this should check to ensure the lib is actually being built - # XXX as dynamic, and not just using a locally-found version or a - # XXX static-compiled version - libnames = dict.fromkeys([lib._full_name for lib in self.shlibs]) - pkg = '.'.join(ext._full_name.split('.')[:-1] + ['']) - return any(pkg + libname in libnames for libname in ext.libraries) - - def get_outputs(self) -> List[str]: - if self.inplace: - return list(self.get_output_mapping().keys()) - return sorted(_build_ext.get_outputs(self) + self.__get_stubs_outputs()) - - def get_output_mapping(self) -> Dict[str, str]: - """See :class:`setuptools.commands.build.SubCommand`""" - mapping = self._get_output_mapping() - return dict(sorted(mapping, key=lambda x: x[0])) - - def __get_stubs_outputs(self): - # assemble the base name for each extension that needs a stub - ns_ext_bases = ( - os.path.join(self.build_lib, *ext._full_name.split('.')) - for ext in self.extensions - if ext._needs_stub - ) - # pair each base with the extension - pairs = itertools.product(ns_ext_bases, self.__get_output_extensions()) - return list(base + fnext for base, fnext in pairs) - - def __get_output_extensions(self): - yield '.py' - yield '.pyc' - if self.get_finalized_command('build_py').optimize: - yield '.pyo' - - def write_stub(self, output_dir, ext, compile=False): - stub_file = os.path.join(output_dir, *ext._full_name.split('.')) + '.py' - self._write_stub_file(stub_file, ext, compile) - - def _write_stub_file(self, stub_file: str, ext: Extension, compile=False): - log.info("writing stub loader for %s to %s", ext._full_name, stub_file) - if compile and os.path.exists(stub_file): - raise BaseError(stub_file + " already exists! Please delete.") - if not self.dry_run: - f = open(stub_file, 'w') - f.write( - '\n'.join([ - "def __bootstrap__():", - " global __bootstrap__, __file__, __loader__", - " import sys, os, pkg_resources, importlib.util" + - if_dl(", dl"), - " __file__ = pkg_resources.resource_filename" - "(__name__,%r)" - % os.path.basename(ext._file_name), - " del __bootstrap__", - " if '__loader__' in globals():", - " del __loader__", - if_dl(" old_flags = sys.getdlopenflags()"), - " old_dir = os.getcwd()", - " try:", - " os.chdir(os.path.dirname(__file__))", - if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"), - " spec = importlib.util.spec_from_file_location(", - " __name__, __file__)", - " mod = importlib.util.module_from_spec(spec)", - " spec.loader.exec_module(mod)", - " finally:", - if_dl(" sys.setdlopenflags(old_flags)"), - " os.chdir(old_dir)", - "__bootstrap__()", - "" # terminal \n - ]) - ) - f.close() - if compile: - self._compile_and_remove_stub(stub_file) - - def _compile_and_remove_stub(self, stub_file: str): - from distutils.util import byte_compile - - byte_compile([stub_file], optimize=0, - force=True, dry_run=self.dry_run) - optimize = self.get_finalized_command('install_lib').optimize - if optimize > 0: - byte_compile([stub_file], optimize=optimize, - force=True, dry_run=self.dry_run) - if os.path.exists(stub_file) and not self.dry_run: - os.unlink(stub_file) - - -if use_stubs or os.name == 'nt': - # Build shared libraries - # - def link_shared_object( - self, objects, output_libname, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, - target_lang=None): - self.link( - self.SHARED_LIBRARY, objects, output_libname, - output_dir, libraries, library_dirs, runtime_library_dirs, - export_symbols, debug, extra_preargs, extra_postargs, - build_temp, target_lang - ) -else: - # Build static libraries everywhere else - libtype = 'static' - - def link_shared_object( - self, objects, output_libname, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, - target_lang=None): - # XXX we need to either disallow these attrs on Library instances, - # or warn/abort here if set, or something... - # libraries=None, library_dirs=None, runtime_library_dirs=None, - # export_symbols=None, extra_preargs=None, extra_postargs=None, - # build_temp=None - - assert output_dir is None # distutils build_ext doesn't pass this - output_dir, filename = os.path.split(output_libname) - basename, ext = os.path.splitext(filename) - if self.library_filename("x").startswith('lib'): - # strip 'lib' prefix; this is kludgy if some platform uses - # a different prefix - basename = basename[3:] - - self.create_static_lib( - objects, basename, output_dir, debug, target_lang - ) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/build_py.py b/venv/lib/python3.11/site-packages/setuptools/command/build_py.py deleted file mode 100755 index ec06274..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/build_py.py +++ /dev/null @@ -1,368 +0,0 @@ -from functools import partial -from glob import glob -from distutils.util import convert_path -import distutils.command.build_py as orig -import os -import fnmatch -import textwrap -import io -import distutils.errors -import itertools -import stat -import warnings -from pathlib import Path -from typing import Dict, Iterable, Iterator, List, Optional, Tuple - -from setuptools._deprecation_warning import SetuptoolsDeprecationWarning -from setuptools.extern.more_itertools import unique_everseen - - -def make_writable(target): - os.chmod(target, os.stat(target).st_mode | stat.S_IWRITE) - - -class build_py(orig.build_py): - """Enhanced 'build_py' command that includes data files with packages - - The data files are specified via a 'package_data' argument to 'setup()'. - See 'setuptools.dist.Distribution' for more details. - - Also, this version of the 'build_py' command allows you to specify both - 'py_modules' and 'packages' in the same setup operation. - """ - editable_mode: bool = False - existing_egg_info_dir: Optional[str] = None #: Private API, internal use only. - - def finalize_options(self): - orig.build_py.finalize_options(self) - self.package_data = self.distribution.package_data - self.exclude_package_data = self.distribution.exclude_package_data or {} - if 'data_files' in self.__dict__: - del self.__dict__['data_files'] - self.__updated_files = [] - - def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, - link=None, level=1): - # Overwrite base class to allow using links - if link: - infile = str(Path(infile).resolve()) - outfile = str(Path(outfile).resolve()) - return super().copy_file(infile, outfile, preserve_mode, preserve_times, - link, level) - - def run(self): - """Build modules, packages, and copy data files to build directory""" - if not (self.py_modules or self.packages) or self.editable_mode: - return - - if self.py_modules: - self.build_modules() - - if self.packages: - self.build_packages() - self.build_package_data() - - # Only compile actual .py files, using our base class' idea of what our - # output files are. - self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0)) - - def __getattr__(self, attr): - "lazily compute data files" - if attr == 'data_files': - self.data_files = self._get_data_files() - return self.data_files - return orig.build_py.__getattr__(self, attr) - - def build_module(self, module, module_file, package): - outfile, copied = orig.build_py.build_module(self, module, module_file, package) - if copied: - self.__updated_files.append(outfile) - return outfile, copied - - def _get_data_files(self): - """Generate list of '(package,src_dir,build_dir,filenames)' tuples""" - self.analyze_manifest() - return list(map(self._get_pkg_data_files, self.packages or ())) - - def get_data_files_without_manifest(self): - """ - Generate list of ``(package,src_dir,build_dir,filenames)`` tuples, - but without triggering any attempt to analyze or build the manifest. - """ - # Prevent eventual errors from unset `manifest_files` - # (that would otherwise be set by `analyze_manifest`) - self.__dict__.setdefault('manifest_files', {}) - return list(map(self._get_pkg_data_files, self.packages or ())) - - def _get_pkg_data_files(self, package): - # Locate package source directory - src_dir = self.get_package_dir(package) - - # Compute package build directory - build_dir = os.path.join(*([self.build_lib] + package.split('.'))) - - # Strip directory from globbed filenames - filenames = [ - os.path.relpath(file, src_dir) - for file in self.find_data_files(package, src_dir) - ] - return package, src_dir, build_dir, filenames - - def find_data_files(self, package, src_dir): - """Return filenames for package's data files in 'src_dir'""" - patterns = self._get_platform_patterns( - self.package_data, - package, - src_dir, - ) - globs_expanded = map(partial(glob, recursive=True), patterns) - # flatten the expanded globs into an iterable of matches - globs_matches = itertools.chain.from_iterable(globs_expanded) - glob_files = filter(os.path.isfile, globs_matches) - files = itertools.chain( - self.manifest_files.get(package, []), - glob_files, - ) - return self.exclude_data_files(package, src_dir, files) - - def get_outputs(self, include_bytecode=1) -> List[str]: - """See :class:`setuptools.commands.build.SubCommand`""" - if self.editable_mode: - return list(self.get_output_mapping().keys()) - return super().get_outputs(include_bytecode) - - def get_output_mapping(self) -> Dict[str, str]: - """See :class:`setuptools.commands.build.SubCommand`""" - mapping = itertools.chain( - self._get_package_data_output_mapping(), - self._get_module_mapping(), - ) - return dict(sorted(mapping, key=lambda x: x[0])) - - def _get_module_mapping(self) -> Iterator[Tuple[str, str]]: - """Iterate over all modules producing (dest, src) pairs.""" - for (package, module, module_file) in self.find_all_modules(): - package = package.split('.') - filename = self.get_module_outfile(self.build_lib, package, module) - yield (filename, module_file) - - def _get_package_data_output_mapping(self) -> Iterator[Tuple[str, str]]: - """Iterate over package data producing (dest, src) pairs.""" - for package, src_dir, build_dir, filenames in self.data_files: - for filename in filenames: - target = os.path.join(build_dir, filename) - srcfile = os.path.join(src_dir, filename) - yield (target, srcfile) - - def build_package_data(self): - """Copy data files into build directory""" - for target, srcfile in self._get_package_data_output_mapping(): - self.mkpath(os.path.dirname(target)) - _outf, _copied = self.copy_file(srcfile, target) - make_writable(target) - - def analyze_manifest(self): - self.manifest_files = mf = {} - if not self.distribution.include_package_data: - return - src_dirs = {} - for package in self.packages or (): - # Locate package source directory - src_dirs[assert_relative(self.get_package_dir(package))] = package - - if ( - getattr(self, 'existing_egg_info_dir', None) - and Path(self.existing_egg_info_dir, "SOURCES.txt").exists() - ): - egg_info_dir = self.existing_egg_info_dir - manifest = Path(egg_info_dir, "SOURCES.txt") - files = manifest.read_text(encoding="utf-8").splitlines() - else: - self.run_command('egg_info') - ei_cmd = self.get_finalized_command('egg_info') - egg_info_dir = ei_cmd.egg_info - files = ei_cmd.filelist.files - - check = _IncludePackageDataAbuse() - for path in self._filter_build_files(files, egg_info_dir): - d, f = os.path.split(assert_relative(path)) - prev = None - oldf = f - while d and d != prev and d not in src_dirs: - prev = d - d, df = os.path.split(d) - f = os.path.join(df, f) - if d in src_dirs: - if f == oldf: - if check.is_module(f): - continue # it's a module, not data - else: - importable = check.importable_subpackage(src_dirs[d], f) - if importable: - check.warn(importable) - mf.setdefault(src_dirs[d], []).append(path) - - def _filter_build_files(self, files: Iterable[str], egg_info: str) -> Iterator[str]: - """ - ``build_meta`` may try to create egg_info outside of the project directory, - and this can be problematic for certain plugins (reported in issue #3500). - - Extensions might also include between their sources files created on the - ``build_lib`` and ``build_temp`` directories. - - This function should filter this case of invalid files out. - """ - build = self.get_finalized_command("build") - build_dirs = (egg_info, self.build_lib, build.build_temp, build.build_base) - norm_dirs = [os.path.normpath(p) for p in build_dirs if p] - - for file in files: - norm_path = os.path.normpath(file) - if not os.path.isabs(file) or all(d not in norm_path for d in norm_dirs): - yield file - - def get_data_files(self): - pass # Lazily compute data files in _get_data_files() function. - - def check_package(self, package, package_dir): - """Check namespace packages' __init__ for declare_namespace""" - try: - return self.packages_checked[package] - except KeyError: - pass - - init_py = orig.build_py.check_package(self, package, package_dir) - self.packages_checked[package] = init_py - - if not init_py or not self.distribution.namespace_packages: - return init_py - - for pkg in self.distribution.namespace_packages: - if pkg == package or pkg.startswith(package + '.'): - break - else: - return init_py - - with io.open(init_py, 'rb') as f: - contents = f.read() - if b'declare_namespace' not in contents: - raise distutils.errors.DistutilsError( - "Namespace package problem: %s is a namespace package, but " - "its\n__init__.py does not call declare_namespace()! Please " - 'fix it.\n(See the setuptools manual under ' - '"Namespace Packages" for details.)\n"' % (package,) - ) - return init_py - - def initialize_options(self): - self.packages_checked = {} - orig.build_py.initialize_options(self) - self.editable_mode = False - self.existing_egg_info_dir = None - - def get_package_dir(self, package): - res = orig.build_py.get_package_dir(self, package) - if self.distribution.src_root is not None: - return os.path.join(self.distribution.src_root, res) - return res - - def exclude_data_files(self, package, src_dir, files): - """Filter filenames for package's data files in 'src_dir'""" - files = list(files) - patterns = self._get_platform_patterns( - self.exclude_package_data, - package, - src_dir, - ) - match_groups = (fnmatch.filter(files, pattern) for pattern in patterns) - # flatten the groups of matches into an iterable of matches - matches = itertools.chain.from_iterable(match_groups) - bad = set(matches) - keepers = (fn for fn in files if fn not in bad) - # ditch dupes - return list(unique_everseen(keepers)) - - @staticmethod - def _get_platform_patterns(spec, package, src_dir): - """ - yield platform-specific path patterns (suitable for glob - or fn_match) from a glob-based spec (such as - self.package_data or self.exclude_package_data) - matching package in src_dir. - """ - raw_patterns = itertools.chain( - spec.get('', []), - spec.get(package, []), - ) - return ( - # Each pattern has to be converted to a platform-specific path - os.path.join(src_dir, convert_path(pattern)) - for pattern in raw_patterns - ) - - -def assert_relative(path): - if not os.path.isabs(path): - return path - from distutils.errors import DistutilsSetupError - - msg = ( - textwrap.dedent( - """ - Error: setup script specifies an absolute path: - - %s - - setup() arguments must *always* be /-separated paths relative to the - setup.py directory, *never* absolute paths. - """ - ).lstrip() - % path - ) - raise DistutilsSetupError(msg) - - -class _IncludePackageDataAbuse: - """Inform users that package or module is included as 'data file'""" - - MESSAGE = """\ - Installing {importable!r} as data is deprecated, please list it in `packages`. - !!\n\n - ############################ - # Package would be ignored # - ############################ - Python recognizes {importable!r} as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - {importable!r} has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that {importable!r} is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - \n\n!! - """ - - def __init__(self): - self._already_warned = set() - - def is_module(self, file): - return file.endswith(".py") and file[:-len(".py")].isidentifier() - - def importable_subpackage(self, parent, file): - pkg = Path(file).parent - parts = list(itertools.takewhile(str.isidentifier, pkg.parts)) - if parts: - return ".".join([parent, *parts]) - return None - - def warn(self, importable): - if importable not in self._already_warned: - msg = textwrap.dedent(self.MESSAGE).format(importable=importable) - warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2) - self._already_warned.add(importable) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/develop.py b/venv/lib/python3.11/site-packages/setuptools/command/develop.py deleted file mode 100755 index 24fb0a7..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/develop.py +++ /dev/null @@ -1,193 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsError, DistutilsOptionError -import os -import glob -import io - -import pkg_resources -from setuptools.command.easy_install import easy_install -from setuptools import namespaces -import setuptools - - -class develop(namespaces.DevelopInstaller, easy_install): - """Set up package for development""" - - description = "install package in 'development mode'" - - user_options = easy_install.user_options + [ - ("uninstall", "u", "Uninstall this source package"), - ("egg-path=", None, "Set the path to be used in the .egg-link file"), - ] - - boolean_options = easy_install.boolean_options + ['uninstall'] - - command_consumes_arguments = False # override base - - def run(self): - if self.uninstall: - self.multi_version = True - self.uninstall_link() - self.uninstall_namespaces() - else: - self.install_for_development() - self.warn_deprecated_options() - - def initialize_options(self): - self.uninstall = None - self.egg_path = None - easy_install.initialize_options(self) - self.setup_path = None - self.always_copy_from = '.' # always copy eggs installed in curdir - - def finalize_options(self): - ei = self.get_finalized_command("egg_info") - if ei.broken_egg_info: - template = "Please rename %r to %r before using 'develop'" - args = ei.egg_info, ei.broken_egg_info - raise DistutilsError(template % args) - self.args = [ei.egg_name] - - easy_install.finalize_options(self) - self.expand_basedirs() - self.expand_dirs() - # pick up setup-dir .egg files only: no .egg-info - self.package_index.scan(glob.glob('*.egg')) - - egg_link_fn = ei.egg_name + '.egg-link' - self.egg_link = os.path.join(self.install_dir, egg_link_fn) - self.egg_base = ei.egg_base - if self.egg_path is None: - self.egg_path = os.path.abspath(ei.egg_base) - - target = pkg_resources.normalize_path(self.egg_base) - egg_path = pkg_resources.normalize_path( - os.path.join(self.install_dir, self.egg_path) - ) - if egg_path != target: - raise DistutilsOptionError( - "--egg-path must be a relative path from the install" - " directory to " + target - ) - - # Make a distribution for the package's source - self.dist = pkg_resources.Distribution( - target, - pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)), - project_name=ei.egg_name, - ) - - self.setup_path = self._resolve_setup_path( - self.egg_base, - self.install_dir, - self.egg_path, - ) - - @staticmethod - def _resolve_setup_path(egg_base, install_dir, egg_path): - """ - Generate a path from egg_base back to '.' where the - setup script resides and ensure that path points to the - setup path from $install_dir/$egg_path. - """ - path_to_setup = egg_base.replace(os.sep, '/').rstrip('/') - if path_to_setup != os.curdir: - path_to_setup = '../' * (path_to_setup.count('/') + 1) - resolved = pkg_resources.normalize_path( - os.path.join(install_dir, egg_path, path_to_setup) - ) - if resolved != pkg_resources.normalize_path(os.curdir): - raise DistutilsOptionError( - "Can't get a consistent path to setup script from" - " installation directory", - resolved, - pkg_resources.normalize_path(os.curdir), - ) - return path_to_setup - - def install_for_development(self): - self.run_command('egg_info') - - # Build extensions in-place - self.reinitialize_command('build_ext', inplace=1) - self.run_command('build_ext') - - if setuptools.bootstrap_install_from: - self.easy_install(setuptools.bootstrap_install_from) - setuptools.bootstrap_install_from = None - - self.install_namespaces() - - # create an .egg-link in the installation dir, pointing to our egg - log.info("Creating %s (link to %s)", self.egg_link, self.egg_base) - if not self.dry_run: - with open(self.egg_link, "w") as f: - f.write(self.egg_path + "\n" + self.setup_path) - # postprocess the installed distro, fixing up .pth, installing scripts, - # and handling requirements - self.process_distribution(None, self.dist, not self.no_deps) - - def uninstall_link(self): - if os.path.exists(self.egg_link): - log.info("Removing %s (link to %s)", self.egg_link, self.egg_base) - egg_link_file = open(self.egg_link) - contents = [line.rstrip() for line in egg_link_file] - egg_link_file.close() - if contents not in ([self.egg_path], [self.egg_path, self.setup_path]): - log.warn("Link points to %s: uninstall aborted", contents) - return - if not self.dry_run: - os.unlink(self.egg_link) - if not self.dry_run: - self.update_pth(self.dist) # remove any .pth link to us - if self.distribution.scripts: - # XXX should also check for entry point scripts! - log.warn("Note: you must uninstall or replace scripts manually!") - - def install_egg_scripts(self, dist): - if dist is not self.dist: - # Installing a dependency, so fall back to normal behavior - return easy_install.install_egg_scripts(self, dist) - - # create wrapper scripts in the script dir, pointing to dist.scripts - - # new-style... - self.install_wrapper_scripts(dist) - - # ...and old-style - for script_name in self.distribution.scripts or []: - script_path = os.path.abspath(convert_path(script_name)) - script_name = os.path.basename(script_path) - with io.open(script_path) as strm: - script_text = strm.read() - self.install_script(dist, script_name, script_text, script_path) - - def install_wrapper_scripts(self, dist): - dist = VersionlessRequirement(dist) - return easy_install.install_wrapper_scripts(self, dist) - - -class VersionlessRequirement: - """ - Adapt a pkg_resources.Distribution to simply return the project - name as the 'requirement' so that scripts will work across - multiple versions. - - >>> from pkg_resources import Distribution - >>> dist = Distribution(project_name='foo', version='1.0') - >>> str(dist.as_requirement()) - 'foo==1.0' - >>> adapted_dist = VersionlessRequirement(dist) - >>> str(adapted_dist.as_requirement()) - 'foo' - """ - - def __init__(self, dist): - self.__dist = dist - - def __getattr__(self, name): - return getattr(self.__dist, name) - - def as_requirement(self): - return self.project_name diff --git a/venv/lib/python3.11/site-packages/setuptools/command/dist_info.py b/venv/lib/python3.11/site-packages/setuptools/command/dist_info.py deleted file mode 100755 index 0685c94..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/dist_info.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -Create a dist_info directory -As defined in the wheel specification -""" - -import os -import re -import shutil -import sys -import warnings -from contextlib import contextmanager -from inspect import cleandoc -from pathlib import Path - -from distutils.core import Command -from distutils import log -from setuptools.extern import packaging -from setuptools._deprecation_warning import SetuptoolsDeprecationWarning - - -class dist_info(Command): - - description = 'create a .dist-info directory' - - user_options = [ - ('egg-base=', 'e', "directory containing .egg-info directories" - " (default: top of the source tree)" - " DEPRECATED: use --output-dir."), - ('output-dir=', 'o', "directory inside of which the .dist-info will be" - "created (default: top of the source tree)"), - ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), - ('tag-build=', 'b', "Specify explicit tag to add to version number"), - ('no-date', 'D', "Don't include date stamp [default]"), - ('keep-egg-info', None, "*TRANSITIONAL* will be removed in the future"), - ] - - boolean_options = ['tag-date', 'keep-egg-info'] - negative_opt = {'no-date': 'tag-date'} - - def initialize_options(self): - self.egg_base = None - self.output_dir = None - self.name = None - self.dist_info_dir = None - self.tag_date = None - self.tag_build = None - self.keep_egg_info = False - - def finalize_options(self): - if self.egg_base: - msg = "--egg-base is deprecated for dist_info command. Use --output-dir." - warnings.warn(msg, SetuptoolsDeprecationWarning) - self.output_dir = self.egg_base or self.output_dir - - dist = self.distribution - project_dir = dist.src_root or os.curdir - self.output_dir = Path(self.output_dir or project_dir) - - egg_info = self.reinitialize_command("egg_info") - egg_info.egg_base = str(self.output_dir) - - if self.tag_date: - egg_info.tag_date = self.tag_date - else: - self.tag_date = egg_info.tag_date - - if self.tag_build: - egg_info.tag_build = self.tag_build - else: - self.tag_build = egg_info.tag_build - - egg_info.finalize_options() - self.egg_info = egg_info - - name = _safe(dist.get_name()) - version = _version(dist.get_version()) - self.name = f"{name}-{version}" - self.dist_info_dir = os.path.join(self.output_dir, f"{self.name}.dist-info") - - @contextmanager - def _maybe_bkp_dir(self, dir_path: str, requires_bkp: bool): - if requires_bkp: - bkp_name = f"{dir_path}.__bkp__" - _rm(bkp_name, ignore_errors=True) - _copy(dir_path, bkp_name, dirs_exist_ok=True, symlinks=True) - try: - yield - finally: - _rm(dir_path, ignore_errors=True) - shutil.move(bkp_name, dir_path) - else: - yield - - def run(self): - self.output_dir.mkdir(parents=True, exist_ok=True) - self.egg_info.run() - egg_info_dir = self.egg_info.egg_info - assert os.path.isdir(egg_info_dir), ".egg-info dir should have been created" - - log.info("creating '{}'".format(os.path.abspath(self.dist_info_dir))) - bdist_wheel = self.get_finalized_command('bdist_wheel') - - # TODO: if bdist_wheel if merged into setuptools, just add "keep_egg_info" there - with self._maybe_bkp_dir(egg_info_dir, self.keep_egg_info): - bdist_wheel.egg2dist(egg_info_dir, self.dist_info_dir) - - -def _safe(component: str) -> str: - """Escape a component used to form a wheel name according to PEP 491""" - return re.sub(r"[^\w\d.]+", "_", component) - - -def _version(version: str) -> str: - """Convert an arbitrary string to a version string.""" - v = version.replace(' ', '.') - try: - return str(packaging.version.Version(v)).replace("-", "_") - except packaging.version.InvalidVersion: - msg = f"""Invalid version: {version!r}. - !!\n\n - ################### - # Invalid version # - ################### - {version!r} is not valid according to PEP 440.\n - Please make sure specify a valid version for your package. - Also note that future releases of setuptools may halt the build process - if an invalid version is given. - \n\n!! - """ - warnings.warn(cleandoc(msg)) - return _safe(v).strip("_") - - -def _rm(dir_name, **opts): - if os.path.isdir(dir_name): - shutil.rmtree(dir_name, **opts) - - -def _copy(src, dst, **opts): - if sys.version_info < (3, 8): - opts.pop("dirs_exist_ok", None) - shutil.copytree(src, dst, **opts) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/easy_install.py b/venv/lib/python3.11/site-packages/setuptools/command/easy_install.py deleted file mode 100755 index f4b67b5..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/easy_install.py +++ /dev/null @@ -1,2366 +0,0 @@ -""" -Easy Install ------------- - -A tool for doing automatic download/extract/build of distutils-based Python -packages. For detailed documentation, see the accompanying EasyInstall.txt -file, or visit the `EasyInstall home page`__. - -__ https://setuptools.pypa.io/en/latest/deprecated/easy_install.html - -""" - -from glob import glob -from distutils.util import get_platform -from distutils.util import convert_path, subst_vars -from distutils.errors import ( - DistutilsArgError, DistutilsOptionError, - DistutilsError, DistutilsPlatformError, -) -from distutils import log, dir_util -from distutils.command.build_scripts import first_line_re -from distutils.spawn import find_executable -from distutils.command import install -import sys -import os -import zipimport -import shutil -import tempfile -import zipfile -import re -import stat -import random -import textwrap -import warnings -import site -import struct -import contextlib -import subprocess -import shlex -import io -import configparser -import sysconfig - - -from sysconfig import get_path - -from setuptools import SetuptoolsDeprecationWarning - -from setuptools import Command -from setuptools.sandbox import run_setup -from setuptools.command import setopt -from setuptools.archive_util import unpack_archive -from setuptools.package_index import ( - PackageIndex, parse_requirement_arg, URL_SCHEME, -) -from setuptools.command import bdist_egg, egg_info -from setuptools.wheel import Wheel -from pkg_resources import ( - normalize_path, resource_string, - get_distribution, find_distributions, Environment, Requirement, - Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound, - VersionConflict, DEVELOP_DIST, -) -import pkg_resources -from .._path import ensure_directory -from ..extern.jaraco.text import yield_lines - - -# Turn on PEP440Warnings -warnings.filterwarnings("default", category=pkg_resources.PEP440Warning) - -__all__ = [ - 'easy_install', 'PthDistributions', 'extract_wininst_cfg', - 'get_exe_prefixes', -] - - -def is_64bit(): - return struct.calcsize("P") == 8 - - -def _to_bytes(s): - return s.encode('utf8') - - -def isascii(s): - try: - s.encode('ascii') - return True - except UnicodeError: - return False - - -def _one_liner(text): - return textwrap.dedent(text).strip().replace('\n', '; ') - - -class easy_install(Command): - """Manage a download/build/install process""" - description = "Find/get/install Python packages" - command_consumes_arguments = True - - user_options = [ - ('prefix=', None, "installation prefix"), - ("zip-ok", "z", "install package as a zipfile"), - ("multi-version", "m", "make apps have to require() a version"), - ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"), - ("install-dir=", "d", "install package to DIR"), - ("script-dir=", "s", "install scripts to DIR"), - ("exclude-scripts", "x", "Don't install scripts"), - ("always-copy", "a", "Copy all needed packages to install dir"), - ("index-url=", "i", "base URL of Python Package Index"), - ("find-links=", "f", "additional URL(s) to search for packages"), - ("build-directory=", "b", - "download/extract/build in DIR; keep the results"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), - ('record=', None, - "filename in which to record list of installed files"), - ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), - ('site-dirs=', 'S', "list of directories where .pth files work"), - ('editable', 'e', "Install specified packages in editable form"), - ('no-deps', 'N', "don't install dependencies"), - ('allow-hosts=', 'H', "pattern(s) that hostnames must match"), - ('local-snapshots-ok', 'l', - "allow building eggs from local checkouts"), - ('version', None, "print version information and exit"), - ('install-layout=', None, "installation layout to choose (known values: deb)"), - ('force-installation-into-system-dir', '0', "force installation into /usr"), - ('no-find-links', None, - "Don't load find-links defined in packages being installed"), - ('user', None, "install in user site-package '%s'" % site.USER_SITE) - ] - boolean_options = [ - 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', - 'editable', - 'no-deps', 'local-snapshots-ok', 'version', 'force-installation-into-system-dir' - 'user' - ] - - negative_opt = {'always-unzip': 'zip-ok'} - create_index = PackageIndex - - def initialize_options(self): - warnings.warn( - "easy_install command is deprecated. " - "Use build and pip and other standards-based tools.", - EasyInstallDeprecationWarning, - ) - - # the --user option seems to be an opt-in one, - # so the default should be False. - self.user = 0 - self.zip_ok = self.local_snapshots_ok = None - self.install_dir = self.script_dir = self.exclude_scripts = None - self.index_url = None - self.find_links = None - self.build_directory = None - self.args = None - self.optimize = self.record = None - self.upgrade = self.always_copy = self.multi_version = None - self.editable = self.no_deps = self.allow_hosts = None - self.root = self.prefix = self.no_report = None - self.version = None - self.install_purelib = None # for pure module distributions - self.install_platlib = None # non-pure (dists w/ extensions) - self.install_headers = None # for C/C++ headers - self.install_lib = None # set to either purelib or platlib - self.install_scripts = None - self.install_data = None - self.install_base = None - self.install_platbase = None - self.install_userbase = site.USER_BASE - self.install_usersite = site.USER_SITE - self.no_find_links = None - - # Options not specifiable via command line - self.package_index = None - self.pth_file = self.always_copy_from = None - self.site_dirs = None - self.installed_projects = {} - # enable custom installation, known values: deb - self.install_layout = None - self.force_installation_into_system_dir = None - self.multiarch = None - - # Always read easy_install options, even if we are subclassed, or have - # an independent instance created. This ensures that defaults will - # always come from the standard configuration file(s)' "easy_install" - # section, even if this is a "develop" or "install" command, or some - # other embedding. - self._dry_run = None - self.verbose = self.distribution.verbose - self.distribution._set_command_options( - self, self.distribution.get_option_dict('easy_install') - ) - - def delete_blockers(self, blockers): - extant_blockers = ( - filename for filename in blockers - if os.path.exists(filename) or os.path.islink(filename) - ) - list(map(self._delete_path, extant_blockers)) - - def _delete_path(self, path): - log.info("Deleting %s", path) - if self.dry_run: - return - - is_tree = os.path.isdir(path) and not os.path.islink(path) - remover = rmtree if is_tree else os.unlink - remover(path) - - @staticmethod - def _render_version(): - """ - Render the Setuptools version and installation details, then exit. - """ - ver = '{}.{}'.format(*sys.version_info) - dist = get_distribution('setuptools') - tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})' - print(tmpl.format(**locals())) - raise SystemExit() - - def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME - self.version and self._render_version() - - py_version = sys.version.split()[0] - - self.config_vars = dict(sysconfig.get_config_vars()) - - self.config_vars.update({ - 'dist_name': self.distribution.get_name(), - 'dist_version': self.distribution.get_version(), - 'dist_fullname': self.distribution.get_fullname(), - 'py_version': py_version, - 'py_version_short': f'{sys.version_info.major}.{sys.version_info.minor}', - 'py_version_nodot': f'{sys.version_info.major}{sys.version_info.minor}', - 'sys_prefix': self.config_vars['prefix'], - 'sys_exec_prefix': self.config_vars['exec_prefix'], - # Only python 3.2+ has abiflags - 'abiflags': getattr(sys, 'abiflags', ''), - 'platlibdir': getattr(sys, 'platlibdir', 'lib'), - }) - with contextlib.suppress(AttributeError): - # only for distutils outside stdlib - self.config_vars.update({ - 'implementation_lower': install._get_implementation().lower(), - 'implementation': install._get_implementation(), - }) - - # pypa/distutils#113 Python 3.9 compat - self.config_vars.setdefault( - 'py_version_nodot_plat', - getattr(sys, 'windir', '').replace('.', ''), - ) - - self.config_vars['userbase'] = self.install_userbase - self.config_vars['usersite'] = self.install_usersite - if self.user and not site.ENABLE_USER_SITE: - log.warn("WARNING: The user site-packages directory is disabled.") - - self._fix_install_dir_for_user_site() - - self.expand_basedirs() - self.expand_dirs() - - if self.install_layout: - if not self.install_layout.lower() in ['deb']: - raise DistutilsOptionError("unknown value for --install-layout") - self.install_layout = self.install_layout.lower() - - if sys.version_info[:2] >= (3, 3): - self.multiarch = sysconfig.get_config_var('MULTIARCH') - - self._expand( - 'install_dir', 'script_dir', 'build_directory', - 'site_dirs', - ) - # If a non-default installation directory was specified, default the - # script directory to match it. - if self.script_dir is None: - self.script_dir = self.install_dir - - if self.no_find_links is None: - self.no_find_links = False - - # Let install_dir get set by install_lib command, which in turn - # gets its info from the install command, and takes into account - # --prefix and --home and all that other crud. - self.set_undefined_options( - 'install_lib', ('install_dir', 'install_dir') - ) - # Likewise, set default script_dir from 'install_scripts.install_dir' - self.set_undefined_options( - 'install_scripts', ('install_dir', 'script_dir') - ) - - if self.user and self.install_purelib: - self.install_dir = self.install_purelib - self.script_dir = self.install_scripts - - if self.prefix == '/usr' and not self.force_installation_into_system_dir: - raise DistutilsOptionError("""installation into /usr - -Trying to install into the system managed parts of the file system. Please -consider to install to another location, or use the option ---force-installation-into-system-dir to overwrite this warning. -""") - - # default --record from the install command - self.set_undefined_options('install', ('record', 'record')) - self.all_site_dirs = get_site_dirs() - self.all_site_dirs.extend(self._process_site_dirs(self.site_dirs)) - - if not self.editable: - self.check_site_dir() - default_index = os.getenv("__EASYINSTALL_INDEX", "https://pypi.org/simple/") - # ^ Private API for testing purposes only - self.index_url = self.index_url or default_index - self.shadow_path = self.all_site_dirs[:] - for path_item in self.install_dir, normalize_path(self.script_dir): - if path_item not in self.shadow_path: - self.shadow_path.insert(0, path_item) - - if self.allow_hosts is not None: - hosts = [s.strip() for s in self.allow_hosts.split(',')] - else: - hosts = ['*'] - if self.package_index is None: - self.package_index = self.create_index( - self.index_url, search_path=self.shadow_path, hosts=hosts, - ) - self.local_index = Environment(self.shadow_path + sys.path) - - if self.find_links is not None: - if isinstance(self.find_links, str): - self.find_links = self.find_links.split() - else: - self.find_links = [] - if self.local_snapshots_ok: - self.package_index.scan_egg_links(self.shadow_path + sys.path) - if not self.no_find_links: - self.package_index.add_find_links(self.find_links) - self.set_undefined_options('install_lib', ('optimize', 'optimize')) - self.optimize = self._validate_optimize(self.optimize) - - if self.editable and not self.build_directory: - raise DistutilsArgError( - "Must specify a build directory (-b) when using --editable" - ) - if not self.args: - raise DistutilsArgError( - "No urls, filenames, or requirements specified (see --help)") - - self.outputs = [] - - @staticmethod - def _process_site_dirs(site_dirs): - if site_dirs is None: - return - - normpath = map(normalize_path, sys.path) - site_dirs = [ - os.path.expanduser(s.strip()) for s in - site_dirs.split(',') - ] - for d in site_dirs: - if not os.path.isdir(d): - log.warn("%s (in --site-dirs) does not exist", d) - elif normalize_path(d) not in normpath: - raise DistutilsOptionError( - d + " (in --site-dirs) is not on sys.path" - ) - else: - yield normalize_path(d) - - @staticmethod - def _validate_optimize(value): - try: - value = int(value) - if value not in range(3): - raise ValueError - except ValueError as e: - raise DistutilsOptionError( - "--optimize must be 0, 1, or 2" - ) from e - - return value - - def _fix_install_dir_for_user_site(self): - """ - Fix the install_dir if "--user" was used. - """ - if not self.user: - return - - self.create_home_path() - if self.install_userbase is None: - msg = "User base directory is not specified" - raise DistutilsPlatformError(msg) - self.install_base = self.install_platbase = self.install_userbase - scheme_name = f'{os.name}_user' - self.select_scheme(scheme_name) - - def _expand_attrs(self, attrs): - for attr in attrs: - val = getattr(self, attr) - if val is not None: - if os.name == 'posix' or os.name == 'nt': - val = os.path.expanduser(val) - val = subst_vars(val, self.config_vars) - setattr(self, attr, val) - - def expand_basedirs(self): - """Calls `os.path.expanduser` on install_base, install_platbase and - root.""" - self._expand_attrs(['install_base', 'install_platbase', 'root']) - - def expand_dirs(self): - """Calls `os.path.expanduser` on install dirs.""" - dirs = [ - 'install_purelib', - 'install_platlib', - 'install_lib', - 'install_headers', - 'install_scripts', - 'install_data', - ] - self._expand_attrs(dirs) - - def run(self, show_deprecation=True): - if show_deprecation: - self.announce( - "WARNING: The easy_install command is deprecated " - "and will be removed in a future version.", - log.WARN, - ) - if self.verbose != self.distribution.verbose: - log.set_verbosity(self.verbose) - try: - for spec in self.args: - self.easy_install(spec, not self.no_deps) - if self.record: - outputs = list(sorted(self.outputs)) - if self.root: # strip any package prefix - root_len = len(self.root) - for counter in range(len(outputs)): - outputs[counter] = outputs[counter][root_len:] - from distutils import file_util - - self.execute( - file_util.write_file, (self.record, outputs), - "writing list of installed files to '%s'" % - self.record - ) - self.warn_deprecated_options() - finally: - log.set_verbosity(self.distribution.verbose) - - def pseudo_tempname(self): - """Return a pseudo-tempname base in the install directory. - This code is intentionally naive; if a malicious party can write to - the target directory you're already in deep doodoo. - """ - try: - pid = os.getpid() - except Exception: - pid = random.randint(0, sys.maxsize) - return os.path.join(self.install_dir, "test-easy-install-%s" % pid) - - def warn_deprecated_options(self): - pass - - def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME - """Verify that self.install_dir is .pth-capable dir, if needed""" - - instdir = normalize_path(self.install_dir) - pth_file = os.path.join(instdir, 'easy-install.pth') - - if not os.path.exists(instdir): - try: - os.makedirs(instdir) - except (OSError, IOError): - self.cant_write_to_target() - - # Is it a configured, PYTHONPATH, implicit, or explicit site dir? - is_site_dir = instdir in self.all_site_dirs - - if not is_site_dir and not self.multi_version: - # No? Then directly test whether it does .pth file processing - is_site_dir = self.check_pth_processing() - else: - # make sure we can write to target dir - testfile = self.pseudo_tempname() + '.write-test' - test_exists = os.path.exists(testfile) - try: - if test_exists: - os.unlink(testfile) - open(testfile, 'w').close() - os.unlink(testfile) - except (OSError, IOError): - self.cant_write_to_target() - - if not is_site_dir and not self.multi_version: - # Can't install non-multi to non-site dir with easy_install - pythonpath = os.environ.get('PYTHONPATH', '') - log.warn(self.__no_default_msg, self.install_dir, pythonpath) - - if is_site_dir: - if self.pth_file is None: - self.pth_file = PthDistributions(pth_file, self.all_site_dirs) - else: - self.pth_file = None - - if self.multi_version and not os.path.exists(pth_file): - self.pth_file = None # don't create a .pth file - self.install_dir = instdir - - __cant_write_msg = textwrap.dedent(""" - can't create or remove files in install directory - - The following error occurred while trying to add or remove files in the - installation directory: - - %s - - The installation directory you specified (via --install-dir, --prefix, or - the distutils default setting) was: - - %s - """).lstrip() # noqa - - __not_exists_id = textwrap.dedent(""" - This directory does not currently exist. Please create it and try again, or - choose a different installation directory (using the -d or --install-dir - option). - """).lstrip() # noqa - - __access_msg = textwrap.dedent(""" - Perhaps your account does not have write access to this directory? If the - installation directory is a system-owned directory, you may need to sign in - as the administrator or "root" account. If you do not have administrative - access to this machine, you may wish to choose a different installation - directory, preferably one that is listed in your PYTHONPATH environment - variable. - - For information on other options, you may wish to consult the - documentation at: - - https://setuptools.pypa.io/en/latest/deprecated/easy_install.html - - Please make the appropriate changes for your system and try again. - """).lstrip() # noqa - - def cant_write_to_target(self): - msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,) - - if not os.path.exists(self.install_dir): - msg += '\n' + self.__not_exists_id - else: - msg += '\n' + self.__access_msg - raise DistutilsError(msg) - - def check_pth_processing(self): - """Empirically verify whether .pth files are supported in inst. dir""" - instdir = self.install_dir - log.info("Checking .pth file support in %s", instdir) - pth_file = self.pseudo_tempname() + ".pth" - ok_file = pth_file + '.ok' - ok_exists = os.path.exists(ok_file) - tmpl = _one_liner(""" - import os - f = open({ok_file!r}, 'w') - f.write('OK') - f.close() - """) + '\n' - try: - if ok_exists: - os.unlink(ok_file) - dirname = os.path.dirname(ok_file) - os.makedirs(dirname, exist_ok=True) - f = open(pth_file, 'w') - except (OSError, IOError): - self.cant_write_to_target() - else: - try: - f.write(tmpl.format(**locals())) - f.close() - f = None - executable = sys.executable - if os.name == 'nt': - dirname, basename = os.path.split(executable) - alt = os.path.join(dirname, 'pythonw.exe') - use_alt = ( - basename.lower() == 'python.exe' and - os.path.exists(alt) - ) - if use_alt: - # use pythonw.exe to avoid opening a console window - executable = alt - - from distutils.spawn import spawn - - spawn([executable, '-E', '-c', 'pass'], 0) - - if os.path.exists(ok_file): - log.info( - "TEST PASSED: %s appears to support .pth files", - instdir - ) - return True - finally: - if f: - f.close() - if os.path.exists(ok_file): - os.unlink(ok_file) - if os.path.exists(pth_file): - os.unlink(pth_file) - if not self.multi_version: - log.warn("TEST FAILED: %s does NOT support .pth files", instdir) - return False - - def install_egg_scripts(self, dist): - """Write all the scripts for `dist`, unless scripts are excluded""" - if not self.exclude_scripts and dist.metadata_isdir('scripts'): - for script_name in dist.metadata_listdir('scripts'): - if dist.metadata_isdir('scripts/' + script_name): - # The "script" is a directory, likely a Python 3 - # __pycache__ directory, so skip it. - continue - self.install_script( - dist, script_name, - dist.get_metadata('scripts/' + script_name) - ) - self.install_wrapper_scripts(dist) - - def add_output(self, path): - if os.path.isdir(path): - for base, dirs, files in os.walk(path): - for filename in files: - self.outputs.append(os.path.join(base, filename)) - else: - self.outputs.append(path) - - def not_editable(self, spec): - if self.editable: - raise DistutilsArgError( - "Invalid argument %r: you can't use filenames or URLs " - "with --editable (except via the --find-links option)." - % (spec,) - ) - - def check_editable(self, spec): - if not self.editable: - return - - if os.path.exists(os.path.join(self.build_directory, spec.key)): - raise DistutilsArgError( - "%r already exists in %s; can't do a checkout there" % - (spec.key, self.build_directory) - ) - - @contextlib.contextmanager - def _tmpdir(self): - tmpdir = tempfile.mkdtemp(prefix=u"easy_install-") - try: - # cast to str as workaround for #709 and #710 and #712 - yield str(tmpdir) - finally: - os.path.exists(tmpdir) and rmtree(tmpdir) - - def easy_install(self, spec, deps=False): - with self._tmpdir() as tmpdir: - if not isinstance(spec, Requirement): - if URL_SCHEME(spec): - # It's a url, download it to tmpdir and process - self.not_editable(spec) - dl = self.package_index.download(spec, tmpdir) - return self.install_item(None, dl, tmpdir, deps, True) - - elif os.path.exists(spec): - # Existing file or directory, just process it directly - self.not_editable(spec) - return self.install_item(None, spec, tmpdir, deps, True) - else: - spec = parse_requirement_arg(spec) - - self.check_editable(spec) - dist = self.package_index.fetch_distribution( - spec, tmpdir, self.upgrade, self.editable, - not self.always_copy, self.local_index - ) - if dist is None: - msg = "Could not find suitable distribution for %r" % spec - if self.always_copy: - msg += " (--always-copy skips system and development eggs)" - raise DistutilsError(msg) - elif dist.precedence == DEVELOP_DIST: - # .egg-info dists don't need installing, just process deps - self.process_distribution(spec, dist, deps, "Using") - return dist - else: - return self.install_item(spec, dist.location, tmpdir, deps) - - def install_item(self, spec, download, tmpdir, deps, install_needed=False): - - # Installation is also needed if file in tmpdir or is not an egg - install_needed = install_needed or self.always_copy - install_needed = install_needed or os.path.dirname(download) == tmpdir - install_needed = install_needed or not download.endswith('.egg') - install_needed = install_needed or ( - self.always_copy_from is not None and - os.path.dirname(normalize_path(download)) == - normalize_path(self.always_copy_from) - ) - - if spec and not install_needed: - # at this point, we know it's a local .egg, we just don't know if - # it's already installed. - for dist in self.local_index[spec.project_name]: - if dist.location == download: - break - else: - install_needed = True # it's not in the local index - - log.info("Processing %s", os.path.basename(download)) - - if install_needed: - dists = self.install_eggs(spec, download, tmpdir) - for dist in dists: - self.process_distribution(spec, dist, deps) - else: - dists = [self.egg_distribution(download)] - self.process_distribution(spec, dists[0], deps, "Using") - - if spec is not None: - for dist in dists: - if dist in spec: - return dist - - def select_scheme(self, name): - try: - install._select_scheme(self, name) - except AttributeError: - # stdlib distutils - install.install.select_scheme(self, name.replace('posix', 'unix')) - - # FIXME: 'easy_install.process_distribution' is too complex (12) - def process_distribution( # noqa: C901 - self, requirement, dist, deps=True, *info, - ): - self.update_pth(dist) - self.package_index.add(dist) - if dist in self.local_index[dist.key]: - self.local_index.remove(dist) - self.local_index.add(dist) - self.install_egg_scripts(dist) - self.installed_projects[dist.key] = dist - log.info(self.installation_report(requirement, dist, *info)) - if (dist.has_metadata('dependency_links.txt') and - not self.no_find_links): - self.package_index.add_find_links( - dist.get_metadata_lines('dependency_links.txt') - ) - if not deps and not self.always_copy: - return - elif requirement is not None and dist.key != requirement.key: - log.warn("Skipping dependencies for %s", dist) - return # XXX this is not the distribution we were looking for - elif requirement is None or dist not in requirement: - # if we wound up with a different version, resolve what we've got - distreq = dist.as_requirement() - requirement = Requirement(str(distreq)) - log.info("Processing dependencies for %s", requirement) - try: - distros = WorkingSet([]).resolve( - [requirement], self.local_index, self.easy_install - ) - except DistributionNotFound as e: - raise DistutilsError(str(e)) from e - except VersionConflict as e: - raise DistutilsError(e.report()) from e - if self.always_copy or self.always_copy_from: - # Force all the relevant distros to be copied or activated - for dist in distros: - if dist.key not in self.installed_projects: - self.easy_install(dist.as_requirement()) - log.info("Finished processing dependencies for %s", requirement) - - def should_unzip(self, dist): - if self.zip_ok is not None: - return not self.zip_ok - if dist.has_metadata('not-zip-safe'): - return True - if not dist.has_metadata('zip-safe'): - return True - return False - - def maybe_move(self, spec, dist_filename, setup_base): - dst = os.path.join(self.build_directory, spec.key) - if os.path.exists(dst): - msg = ( - "%r already exists in %s; build directory %s will not be kept" - ) - log.warn(msg, spec.key, self.build_directory, setup_base) - return setup_base - if os.path.isdir(dist_filename): - setup_base = dist_filename - else: - if os.path.dirname(dist_filename) == setup_base: - os.unlink(dist_filename) # get it out of the tmp dir - contents = os.listdir(setup_base) - if len(contents) == 1: - dist_filename = os.path.join(setup_base, contents[0]) - if os.path.isdir(dist_filename): - # if the only thing there is a directory, move it instead - setup_base = dist_filename - ensure_directory(dst) - shutil.move(setup_base, dst) - return dst - - def install_wrapper_scripts(self, dist): - if self.exclude_scripts: - return - for args in ScriptWriter.best().get_args(dist): - self.write_script(*args) - - def install_script(self, dist, script_name, script_text, dev_path=None): - """Generate a legacy script wrapper and install it""" - spec = str(dist.as_requirement()) - is_script = is_python_script(script_text, script_name) - - if is_script: - body = self._load_template(dev_path) % locals() - script_text = ScriptWriter.get_header(script_text) + body - self.write_script(script_name, _to_bytes(script_text), 'b') - - @staticmethod - def _load_template(dev_path): - """ - There are a couple of template scripts in the package. This - function loads one of them and prepares it for use. - """ - # See https://github.com/pypa/setuptools/issues/134 for info - # on script file naming and downstream issues with SVR4 - name = 'script.tmpl' - if dev_path: - name = name.replace('.tmpl', ' (dev).tmpl') - - raw_bytes = resource_string('setuptools', name) - return raw_bytes.decode('utf-8') - - def write_script(self, script_name, contents, mode="t", blockers=()): - """Write an executable file to the scripts directory""" - self.delete_blockers( # clean up old .py/.pyw w/o a script - [os.path.join(self.script_dir, x) for x in blockers] - ) - log.info("Installing %s script to %s", script_name, self.script_dir) - target = os.path.join(self.script_dir, script_name) - self.add_output(target) - - if self.dry_run: - return - - mask = current_umask() - ensure_directory(target) - if os.path.exists(target): - os.unlink(target) - with open(target, "w" + mode) as f: - f.write(contents) - chmod(target, 0o777 - mask) - - def install_eggs(self, spec, dist_filename, tmpdir): - # .egg dirs or files are already built, so just return them - installer_map = { - '.egg': self.install_egg, - '.exe': self.install_exe, - '.whl': self.install_wheel, - } - try: - install_dist = installer_map[ - dist_filename.lower()[-4:] - ] - except KeyError: - pass - else: - return [install_dist(dist_filename, tmpdir)] - - # Anything else, try to extract and build - setup_base = tmpdir - if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'): - unpack_archive(dist_filename, tmpdir, self.unpack_progress) - elif os.path.isdir(dist_filename): - setup_base = os.path.abspath(dist_filename) - - if (setup_base.startswith(tmpdir) # something we downloaded - and self.build_directory and spec is not None): - setup_base = self.maybe_move(spec, dist_filename, setup_base) - - # Find the setup.py file - setup_script = os.path.join(setup_base, 'setup.py') - - if not os.path.exists(setup_script): - setups = glob(os.path.join(setup_base, '*', 'setup.py')) - if not setups: - raise DistutilsError( - "Couldn't find a setup script in %s" % - os.path.abspath(dist_filename) - ) - if len(setups) > 1: - raise DistutilsError( - "Multiple setup scripts in %s" % - os.path.abspath(dist_filename) - ) - setup_script = setups[0] - - # Now run it, and return the result - if self.editable: - log.info(self.report_editable(spec, setup_script)) - return [] - else: - return self.build_and_install(setup_script, setup_base) - - def egg_distribution(self, egg_path): - if os.path.isdir(egg_path): - metadata = PathMetadata(egg_path, os.path.join(egg_path, - 'EGG-INFO')) - else: - metadata = EggMetadata(zipimport.zipimporter(egg_path)) - return Distribution.from_filename(egg_path, metadata=metadata) - - # FIXME: 'easy_install.install_egg' is too complex (11) - def install_egg(self, egg_path, tmpdir): # noqa: C901 - destination = os.path.join( - self.install_dir, - os.path.basename(egg_path), - ) - destination = os.path.abspath(destination) - if not self.dry_run: - ensure_directory(destination) - - dist = self.egg_distribution(egg_path) - if not ( - os.path.exists(destination) and os.path.samefile(egg_path, destination) - ): - if os.path.isdir(destination) and not os.path.islink(destination): - dir_util.remove_tree(destination, dry_run=self.dry_run) - elif os.path.exists(destination): - self.execute( - os.unlink, - (destination,), - "Removing " + destination, - ) - try: - new_dist_is_zipped = False - if os.path.isdir(egg_path): - if egg_path.startswith(tmpdir): - f, m = shutil.move, "Moving" - else: - f, m = shutil.copytree, "Copying" - elif self.should_unzip(dist): - self.mkpath(destination) - f, m = self.unpack_and_compile, "Extracting" - else: - new_dist_is_zipped = True - if egg_path.startswith(tmpdir): - f, m = shutil.move, "Moving" - else: - f, m = shutil.copy2, "Copying" - self.execute( - f, - (egg_path, destination), - (m + " %s to %s") % ( - os.path.basename(egg_path), - os.path.dirname(destination) - ), - ) - update_dist_caches( - destination, - fix_zipimporter_caches=new_dist_is_zipped, - ) - except Exception: - update_dist_caches(destination, fix_zipimporter_caches=False) - raise - - self.add_output(destination) - return self.egg_distribution(destination) - - def install_exe(self, dist_filename, tmpdir): - # See if it's valid, get data - cfg = extract_wininst_cfg(dist_filename) - if cfg is None: - raise DistutilsError( - "%s is not a valid distutils Windows .exe" % dist_filename - ) - # Create a dummy distribution object until we build the real distro - dist = Distribution( - None, - project_name=cfg.get('metadata', 'name'), - version=cfg.get('metadata', 'version'), platform=get_platform(), - ) - - # Convert the .exe to an unpacked egg - egg_path = os.path.join(tmpdir, dist.egg_name() + '.egg') - dist.location = egg_path - egg_tmp = egg_path + '.tmp' - _egg_info = os.path.join(egg_tmp, 'EGG-INFO') - pkg_inf = os.path.join(_egg_info, 'PKG-INFO') - ensure_directory(pkg_inf) # make sure EGG-INFO dir exists - dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX - self.exe_to_egg(dist_filename, egg_tmp) - - # Write EGG-INFO/PKG-INFO - if not os.path.exists(pkg_inf): - f = open(pkg_inf, 'w') - f.write('Metadata-Version: 1.0\n') - for k, v in cfg.items('metadata'): - if k != 'target_version': - f.write('%s: %s\n' % (k.replace('_', '-').title(), v)) - f.close() - script_dir = os.path.join(_egg_info, 'scripts') - # delete entry-point scripts to avoid duping - self.delete_blockers([ - os.path.join(script_dir, args[0]) - for args in ScriptWriter.get_args(dist) - ]) - # Build .egg file from tmpdir - bdist_egg.make_zipfile( - egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run, - ) - # install the .egg - return self.install_egg(egg_path, tmpdir) - - # FIXME: 'easy_install.exe_to_egg' is too complex (12) - def exe_to_egg(self, dist_filename, egg_tmp): # noqa: C901 - """Extract a bdist_wininst to the directories an egg would use""" - # Check for .pth file and set up prefix translations - prefixes = get_exe_prefixes(dist_filename) - to_compile = [] - native_libs = [] - top_level = {} - - def process(src, dst): - s = src.lower() - for old, new in prefixes: - if s.startswith(old): - src = new + src[len(old):] - parts = src.split('/') - dst = os.path.join(egg_tmp, *parts) - dl = dst.lower() - if dl.endswith('.pyd') or dl.endswith('.dll'): - parts[-1] = bdist_egg.strip_module(parts[-1]) - top_level[os.path.splitext(parts[0])[0]] = 1 - native_libs.append(src) - elif dl.endswith('.py') and old != 'SCRIPTS/': - top_level[os.path.splitext(parts[0])[0]] = 1 - to_compile.append(dst) - return dst - if not src.endswith('.pth'): - log.warn("WARNING: can't process %s", src) - return None - - # extract, tracking .pyd/.dll->native_libs and .py -> to_compile - unpack_archive(dist_filename, egg_tmp, process) - stubs = [] - for res in native_libs: - if res.lower().endswith('.pyd'): # create stubs for .pyd's - parts = res.split('/') - resource = parts[-1] - parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py' - pyfile = os.path.join(egg_tmp, *parts) - to_compile.append(pyfile) - stubs.append(pyfile) - bdist_egg.write_stub(resource, pyfile) - self.byte_compile(to_compile) # compile .py's - bdist_egg.write_safety_flag( - os.path.join(egg_tmp, 'EGG-INFO'), - bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag - - for name in 'top_level', 'native_libs': - if locals()[name]: - txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt') - if not os.path.exists(txt): - f = open(txt, 'w') - f.write('\n'.join(locals()[name]) + '\n') - f.close() - - def install_wheel(self, wheel_path, tmpdir): - wheel = Wheel(wheel_path) - assert wheel.is_compatible() - destination = os.path.join(self.install_dir, wheel.egg_name()) - destination = os.path.abspath(destination) - if not self.dry_run: - ensure_directory(destination) - if os.path.isdir(destination) and not os.path.islink(destination): - dir_util.remove_tree(destination, dry_run=self.dry_run) - elif os.path.exists(destination): - self.execute( - os.unlink, - (destination,), - "Removing " + destination, - ) - try: - self.execute( - wheel.install_as_egg, - (destination,), - ("Installing %s to %s") % ( - os.path.basename(wheel_path), - os.path.dirname(destination) - ), - ) - finally: - update_dist_caches(destination, fix_zipimporter_caches=False) - self.add_output(destination) - return self.egg_distribution(destination) - - __mv_warning = textwrap.dedent(""" - Because this distribution was installed --multi-version, before you can - import modules from this package in an application, you will need to - 'import pkg_resources' and then use a 'require()' call similar to one of - these examples, in order to select the desired version: - - pkg_resources.require("%(name)s") # latest installed version - pkg_resources.require("%(name)s==%(version)s") # this exact version - pkg_resources.require("%(name)s>=%(version)s") # this version or higher - """).lstrip() # noqa - - __id_warning = textwrap.dedent(""" - Note also that the installation directory must be on sys.path at runtime for - this to work. (e.g. by being the application's script directory, by being on - PYTHONPATH, or by being added to sys.path by your code.) - """) # noqa - - def installation_report(self, req, dist, what="Installed"): - """Helpful installation message for display to package users""" - msg = "\n%(what)s %(eggloc)s%(extras)s" - if self.multi_version and not self.no_report: - msg += '\n' + self.__mv_warning - if self.install_dir not in map(normalize_path, sys.path): - msg += '\n' + self.__id_warning - - eggloc = dist.location - name = dist.project_name - version = dist.version - extras = '' # TODO: self.report_extras(req, dist) - return msg % locals() - - __editable_msg = textwrap.dedent(""" - Extracted editable version of %(spec)s to %(dirname)s - - If it uses setuptools in its setup script, you can activate it in - "development" mode by going to that directory and running:: - - %(python)s setup.py develop - - See the setuptools documentation for the "develop" command for more info. - """).lstrip() # noqa - - def report_editable(self, spec, setup_script): - dirname = os.path.dirname(setup_script) - python = sys.executable - return '\n' + self.__editable_msg % locals() - - def run_setup(self, setup_script, setup_base, args): - sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg) - sys.modules.setdefault('distutils.command.egg_info', egg_info) - - args = list(args) - if self.verbose > 2: - v = 'v' * (self.verbose - 1) - args.insert(0, '-' + v) - elif self.verbose < 2: - args.insert(0, '-q') - if self.dry_run: - args.insert(0, '-n') - log.info( - "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args) - ) - try: - run_setup(setup_script, args) - except SystemExit as v: - raise DistutilsError( - "Setup script exited with %s" % (v.args[0],) - ) from v - - def build_and_install(self, setup_script, setup_base): - args = ['bdist_egg', '--dist-dir'] - - dist_dir = tempfile.mkdtemp( - prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script) - ) - try: - self._set_fetcher_options(os.path.dirname(setup_script)) - args.append(dist_dir) - - self.run_setup(setup_script, setup_base, args) - all_eggs = Environment([dist_dir]) - eggs = [] - for key in all_eggs: - for dist in all_eggs[key]: - eggs.append(self.install_egg(dist.location, setup_base)) - if not eggs and not self.dry_run: - log.warn("No eggs found in %s (setup script problem?)", - dist_dir) - return eggs - finally: - rmtree(dist_dir) - log.set_verbosity(self.verbose) # restore our log verbosity - - def _set_fetcher_options(self, base): - """ - When easy_install is about to run bdist_egg on a source dist, that - source dist might have 'setup_requires' directives, requiring - additional fetching. Ensure the fetcher options given to easy_install - are available to that command as well. - """ - # find the fetch options from easy_install and write them out - # to the setup.cfg file. - ei_opts = self.distribution.get_option_dict('easy_install').copy() - fetch_directives = ( - 'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts', - ) - fetch_options = {} - for key, val in ei_opts.items(): - if key not in fetch_directives: - continue - fetch_options[key] = val[1] - # create a settings dictionary suitable for `edit_config` - settings = dict(easy_install=fetch_options) - cfg_filename = os.path.join(base, 'setup.cfg') - setopt.edit_config(cfg_filename, settings) - - def update_pth(self, dist): # noqa: C901 # is too complex (11) # FIXME - if self.pth_file is None: - return - - for d in self.pth_file[dist.key]: # drop old entries - if not self.multi_version and d.location == dist.location: - continue - - log.info("Removing %s from easy-install.pth file", d) - self.pth_file.remove(d) - if d.location in self.shadow_path: - self.shadow_path.remove(d.location) - - if not self.multi_version: - if dist.location in self.pth_file.paths: - log.info( - "%s is already the active version in easy-install.pth", - dist, - ) - else: - log.info("Adding %s to easy-install.pth file", dist) - self.pth_file.add(dist) # add new entry - if dist.location not in self.shadow_path: - self.shadow_path.append(dist.location) - - if self.dry_run: - return - - self.pth_file.save() - - if dist.key != 'setuptools': - return - - # Ensure that setuptools itself never becomes unavailable! - # XXX should this check for latest version? - filename = os.path.join(self.install_dir, 'setuptools.pth') - if os.path.islink(filename): - os.unlink(filename) - with open(filename, 'wt') as f: - f.write(self.pth_file.make_relative(dist.location) + '\n') - - def unpack_progress(self, src, dst): - # Progress filter for unpacking - log.debug("Unpacking %s to %s", src, dst) - return dst # only unpack-and-compile skips files for dry run - - def unpack_and_compile(self, egg_path, destination): - to_compile = [] - to_chmod = [] - - def pf(src, dst): - if dst.endswith('.py') and not src.startswith('EGG-INFO/'): - to_compile.append(dst) - elif dst.endswith('.dll') or dst.endswith('.so'): - to_chmod.append(dst) - self.unpack_progress(src, dst) - return not self.dry_run and dst or None - - unpack_archive(egg_path, destination, pf) - self.byte_compile(to_compile) - if not self.dry_run: - for f in to_chmod: - mode = ((os.stat(f)[stat.ST_MODE]) | 0o555) & 0o7755 - chmod(f, mode) - - def byte_compile(self, to_compile): - if sys.dont_write_bytecode: - return - - from distutils.util import byte_compile - - try: - # try to make the byte compile messages quieter - log.set_verbosity(self.verbose - 1) - - byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run) - if self.optimize: - byte_compile( - to_compile, optimize=self.optimize, force=1, - dry_run=self.dry_run, - ) - finally: - log.set_verbosity(self.verbose) # restore original verbosity - - __no_default_msg = textwrap.dedent(""" - bad install directory or PYTHONPATH - - You are attempting to install a package to a directory that is not - on PYTHONPATH and which Python does not read ".pth" files from. The - installation directory you specified (via --install-dir, --prefix, or - the distutils default setting) was: - - %s - - and your PYTHONPATH environment variable currently contains: - - %r - - Here are some of your options for correcting the problem: - - * You can choose a different installation directory, i.e., one that is - on PYTHONPATH or supports .pth files - - * You can add the installation directory to the PYTHONPATH environment - variable. (It must then also be on PYTHONPATH whenever you run - Python and want to use the package(s) you are installing.) - - * You can set up the installation directory to support ".pth" files by - using one of the approaches described here: - - https://setuptools.pypa.io/en/latest/deprecated/easy_install.html#custom-installation-locations - - - Please make the appropriate changes for your system and try again. - """).strip() - - def create_home_path(self): - """Create directories under ~.""" - if not self.user: - return - home = convert_path(os.path.expanduser("~")) - for path in only_strs(self.config_vars.values()): - if path.startswith(home) and not os.path.isdir(path): - self.debug_print("os.makedirs('%s', 0o700)" % path) - os.makedirs(path, 0o700) - - if sys.version[:3] in ('2.3', '2.4', '2.5') or 'real_prefix' in sys.__dict__: - sitedir_name = 'site-packages' - else: - sitedir_name = 'dist-packages' - - INSTALL_SCHEMES = dict( - posix=dict( - install_dir='$base/lib/python$py_version_short/site-packages', - script_dir='$base/bin', - ), - unix_local = dict( - install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, - script_dir = '$base/local/bin', - ), - posix_local = dict( - install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, - script_dir = '$base/local/bin', - ), - deb_system = dict( - install_dir = '$base/lib/python3/%s' % sitedir_name, - script_dir = '$base/bin', - ), - ) - - DEFAULT_SCHEME = dict( - install_dir='$base/Lib/site-packages', - script_dir='$base/Scripts', - ) - - def _expand(self, *attrs): - config_vars = self.get_finalized_command('install').config_vars - - if self.prefix or self.install_layout: - if self.install_layout and self.install_layout in ['deb']: - scheme_name = "deb_system" - self.prefix = '/usr' - elif self.prefix or 'real_prefix' in sys.__dict__: - scheme_name = os.name - else: - scheme_name = "posix_local" - # Set default install_dir/scripts from --prefix - config_vars = dict(config_vars) - config_vars['base'] = self.prefix - scheme = self.INSTALL_SCHEMES.get(scheme_name,self.DEFAULT_SCHEME) - for attr, val in scheme.items(): - if getattr(self, attr, None) is None: - setattr(self, attr, val) - - from distutils.util import subst_vars - - for attr in attrs: - val = getattr(self, attr) - if val is not None: - val = subst_vars(val, config_vars) - if os.name == 'posix': - val = os.path.expanduser(val) - setattr(self, attr, val) - - -def _pythonpath(): - items = os.environ.get('PYTHONPATH', '').split(os.pathsep) - return filter(None, items) - - -def get_site_dirs(): - """ - Return a list of 'site' dirs - """ - - sitedirs = [] - - # start with PYTHONPATH - sitedirs.extend(_pythonpath()) - - prefixes = [sys.prefix] - if sys.exec_prefix != sys.prefix: - prefixes.append(sys.exec_prefix) - for prefix in prefixes: - if not prefix: - continue - - if sys.platform in ('os2emx', 'riscos'): - sitedirs.append(os.path.join(prefix, "Lib", "site-packages")) - elif os.sep == '/': - sitedirs.extend([ - os.path.join( - prefix, - "local/lib", - "python" + sys.version[:3], - "dist-packages", - ), - os.path.join( - prefix, - "lib", - "python{}.{}".format(*sys.version_info), - "dist-packages", - ), - os.path.join(prefix, "lib", "site-python"), - ]) - else: - sitedirs.extend([ - prefix, - os.path.join(prefix, "lib", "site-packages"), - ]) - if sys.platform != 'darwin': - continue - - # for framework builds *only* we add the standard Apple - # locations. Currently only per-user, but /Library and - # /Network/Library could be added too - if 'Python.framework' not in prefix: - continue - - home = os.environ.get('HOME') - if not home: - continue - - home_sp = os.path.join( - home, - 'Library', - 'Python', - '{}.{}'.format(*sys.version_info), - 'site-packages', - ) - sitedirs.append(home_sp) - lib_paths = get_path('purelib'), get_path('platlib') - - sitedirs.extend(s for s in lib_paths if s not in sitedirs) - - if site.ENABLE_USER_SITE: - sitedirs.append(site.USER_SITE) - - with contextlib.suppress(AttributeError): - sitedirs.extend(site.getsitepackages()) - - sitedirs = list(map(normalize_path, sitedirs)) - - return sitedirs - - -def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME - """Yield sys.path directories that might contain "old-style" packages""" - - seen = {} - - for dirname in inputs: - dirname = normalize_path(dirname) - if dirname in seen: - continue - - seen[dirname] = 1 - if not os.path.isdir(dirname): - continue - - files = os.listdir(dirname) - yield dirname, files - - for name in files: - if not name.endswith('.pth'): - # We only care about the .pth files - continue - if name in ('easy-install.pth', 'setuptools.pth'): - # Ignore .pth files that we control - continue - - # Read the .pth file - f = open(os.path.join(dirname, name)) - lines = list(yield_lines(f)) - f.close() - - # Yield existing non-dupe, non-import directory lines from it - for line in lines: - if line.startswith("import"): - continue - - line = normalize_path(line.rstrip()) - if line in seen: - continue - - seen[line] = 1 - if not os.path.isdir(line): - continue - - yield line, os.listdir(line) - - -def extract_wininst_cfg(dist_filename): - """Extract configuration data from a bdist_wininst .exe - - Returns a configparser.RawConfigParser, or None - """ - f = open(dist_filename, 'rb') - try: - endrec = zipfile._EndRecData(f) - if endrec is None: - return None - - prepended = (endrec[9] - endrec[5]) - endrec[6] - if prepended < 12: # no wininst data here - return None - f.seek(prepended - 12) - - tag, cfglen, bmlen = struct.unpack("egg path translations for a given .exe file""" - - prefixes = [ - ('PURELIB/', ''), - ('PLATLIB/pywin32_system32', ''), - ('PLATLIB/', ''), - ('SCRIPTS/', 'EGG-INFO/scripts/'), - ('DATA/lib/site-packages', ''), - ] - z = zipfile.ZipFile(exe_filename) - try: - for info in z.infolist(): - name = info.filename - parts = name.split('/') - if len(parts) == 3 and parts[2] == 'PKG-INFO': - if parts[1].endswith('.egg-info'): - prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/')) - break - if len(parts) != 2 or not name.endswith('.pth'): - continue - if name.endswith('-nspkg.pth'): - continue - if parts[0].upper() in ('PURELIB', 'PLATLIB'): - contents = z.read(name).decode() - for pth in yield_lines(contents): - pth = pth.strip().replace('\\', '/') - if not pth.startswith('import'): - prefixes.append((('%s/%s/' % (parts[0], pth)), '')) - finally: - z.close() - prefixes = [(x.lower(), y) for x, y in prefixes] - prefixes.sort() - prefixes.reverse() - return prefixes - - -class PthDistributions(Environment): - """A .pth file with Distribution paths in it""" - - dirty = False - - def __init__(self, filename, sitedirs=()): - self.filename = filename - self.sitedirs = list(map(normalize_path, sitedirs)) - self.basedir = normalize_path(os.path.dirname(self.filename)) - self._load() - super().__init__([], None, None) - for path in yield_lines(self.paths): - list(map(self.add, find_distributions(path, True))) - - def _load(self): - self.paths = [] - saw_import = False - seen = dict.fromkeys(self.sitedirs) - if os.path.isfile(self.filename): - f = open(self.filename, 'rt') - for line in f: - if line.startswith('import'): - saw_import = True - continue - path = line.rstrip() - self.paths.append(path) - if not path.strip() or path.strip().startswith('#'): - continue - # skip non-existent paths, in case somebody deleted a package - # manually, and duplicate paths as well - path = self.paths[-1] = normalize_path( - os.path.join(self.basedir, path) - ) - if not os.path.exists(path) or path in seen: - self.paths.pop() # skip it - self.dirty = True # we cleaned up, so we're dirty now :) - continue - seen[path] = 1 - f.close() - - if self.paths and not saw_import: - self.dirty = True # ensure anything we touch has import wrappers - while self.paths and not self.paths[-1].strip(): - self.paths.pop() - - def save(self): - """Write changed .pth file back to disk""" - if not self.dirty: - return - - rel_paths = list(map(self.make_relative, self.paths)) - if rel_paths: - log.debug("Saving %s", self.filename) - lines = self._wrap_lines(rel_paths) - data = '\n'.join(lines) + '\n' - - if os.path.islink(self.filename): - os.unlink(self.filename) - with open(self.filename, 'wt') as f: - f.write(data) - - elif os.path.exists(self.filename): - log.debug("Deleting empty %s", self.filename) - os.unlink(self.filename) - - self.dirty = False - - @staticmethod - def _wrap_lines(lines): - return lines - - def add(self, dist): - """Add `dist` to the distribution map""" - new_path = ( - dist.location not in self.paths and ( - dist.location not in self.sitedirs or - # account for '.' being in PYTHONPATH - dist.location == os.getcwd() - ) - ) - if new_path: - self.paths.append(dist.location) - self.dirty = True - super().add(dist) - - def remove(self, dist): - """Remove `dist` from the distribution map""" - while dist.location in self.paths: - self.paths.remove(dist.location) - self.dirty = True - super().remove(dist) - - def make_relative(self, path): - npath, last = os.path.split(normalize_path(path)) - baselen = len(self.basedir) - parts = [last] - sep = os.altsep == '/' and '/' or os.sep - while len(npath) >= baselen: - if npath == self.basedir: - parts.append(os.curdir) - parts.reverse() - return sep.join(parts) - npath, last = os.path.split(npath) - parts.append(last) - else: - return path - - -class RewritePthDistributions(PthDistributions): - @classmethod - def _wrap_lines(cls, lines): - yield cls.prelude - for line in lines: - yield line - yield cls.postlude - - prelude = _one_liner(""" - import sys - sys.__plen = len(sys.path) - """) - postlude = _one_liner(""" - import sys - new = sys.path[sys.__plen:] - del sys.path[sys.__plen:] - p = getattr(sys, '__egginsert', 0) - sys.path[p:p] = new - sys.__egginsert = p + len(new) - """) - - -if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite': - PthDistributions = RewritePthDistributions - - -def _first_line_re(): - """ - Return a regular expression based on first_line_re suitable for matching - strings. - """ - if isinstance(first_line_re.pattern, str): - return first_line_re - - # first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern. - return re.compile(first_line_re.pattern.decode()) - - -def auto_chmod(func, arg, exc): - if func in [os.unlink, os.remove] and os.name == 'nt': - chmod(arg, stat.S_IWRITE) - return func(arg) - et, ev, _ = sys.exc_info() - # TODO: This code doesn't make sense. What is it trying to do? - raise (ev[0], ev[1] + (" %s %s" % (func, arg))) - - -def update_dist_caches(dist_path, fix_zipimporter_caches): - """ - Fix any globally cached `dist_path` related data - - `dist_path` should be a path of a newly installed egg distribution (zipped - or unzipped). - - sys.path_importer_cache contains finder objects that have been cached when - importing data from the original distribution. Any such finders need to be - cleared since the replacement distribution might be packaged differently, - e.g. a zipped egg distribution might get replaced with an unzipped egg - folder or vice versa. Having the old finders cached may then cause Python - to attempt loading modules from the replacement distribution using an - incorrect loader. - - zipimport.zipimporter objects are Python loaders charged with importing - data packaged inside zip archives. If stale loaders referencing the - original distribution, are left behind, they can fail to load modules from - the replacement distribution. E.g. if an old zipimport.zipimporter instance - is used to load data from a new zipped egg archive, it may cause the - operation to attempt to locate the requested data in the wrong location - - one indicated by the original distribution's zip archive directory - information. Such an operation may then fail outright, e.g. report having - read a 'bad local file header', or even worse, it may fail silently & - return invalid data. - - zipimport._zip_directory_cache contains cached zip archive directory - information for all existing zipimport.zipimporter instances and all such - instances connected to the same archive share the same cached directory - information. - - If asked, and the underlying Python implementation allows it, we can fix - all existing zipimport.zipimporter instances instead of having to track - them down and remove them one by one, by updating their shared cached zip - archive directory information. This, of course, assumes that the - replacement distribution is packaged as a zipped egg. - - If not asked to fix existing zipimport.zipimporter instances, we still do - our best to clear any remaining zipimport.zipimporter related cached data - that might somehow later get used when attempting to load data from the new - distribution and thus cause such load operations to fail. Note that when - tracking down such remaining stale data, we can not catch every conceivable - usage from here, and we clear only those that we know of and have found to - cause problems if left alive. Any remaining caches should be updated by - whomever is in charge of maintaining them, i.e. they should be ready to - handle us replacing their zip archives with new distributions at runtime. - - """ - # There are several other known sources of stale zipimport.zipimporter - # instances that we do not clear here, but might if ever given a reason to - # do so: - # * Global setuptools pkg_resources.working_set (a.k.a. 'master working - # set') may contain distributions which may in turn contain their - # zipimport.zipimporter loaders. - # * Several zipimport.zipimporter loaders held by local variables further - # up the function call stack when running the setuptools installation. - # * Already loaded modules may have their __loader__ attribute set to the - # exact loader instance used when importing them. Python 3.4 docs state - # that this information is intended mostly for introspection and so is - # not expected to cause us problems. - normalized_path = normalize_path(dist_path) - _uncache(normalized_path, sys.path_importer_cache) - if fix_zipimporter_caches: - _replace_zip_directory_cache_data(normalized_path) - else: - # Here, even though we do not want to fix existing and now stale - # zipimporter cache information, we still want to remove it. Related to - # Python's zip archive directory information cache, we clear each of - # its stale entries in two phases: - # 1. Clear the entry so attempting to access zip archive information - # via any existing stale zipimport.zipimporter instances fails. - # 2. Remove the entry from the cache so any newly constructed - # zipimport.zipimporter instances do not end up using old stale - # zip archive directory information. - # This whole stale data removal step does not seem strictly necessary, - # but has been left in because it was done before we started replacing - # the zip archive directory information cache content if possible, and - # there are no relevant unit tests that we can depend on to tell us if - # this is really needed. - _remove_and_clear_zip_directory_cache_data(normalized_path) - - -def _collect_zipimporter_cache_entries(normalized_path, cache): - """ - Return zipimporter cache entry keys related to a given normalized path. - - Alternative path spellings (e.g. those using different character case or - those using alternative path separators) related to the same path are - included. Any sub-path entries are included as well, i.e. those - corresponding to zip archives embedded in other zip archives. - - """ - result = [] - prefix_len = len(normalized_path) - for p in cache: - np = normalize_path(p) - if (np.startswith(normalized_path) and - np[prefix_len:prefix_len + 1] in (os.sep, '')): - result.append(p) - return result - - -def _update_zipimporter_cache(normalized_path, cache, updater=None): - """ - Update zipimporter cache data for a given normalized path. - - Any sub-path entries are processed as well, i.e. those corresponding to zip - archives embedded in other zip archives. - - Given updater is a callable taking a cache entry key and the original entry - (after already removing the entry from the cache), and expected to update - the entry and possibly return a new one to be inserted in its place. - Returning None indicates that the entry should not be replaced with a new - one. If no updater is given, the cache entries are simply removed without - any additional processing, the same as if the updater simply returned None. - - """ - for p in _collect_zipimporter_cache_entries(normalized_path, cache): - # N.B. pypy's custom zipimport._zip_directory_cache implementation does - # not support the complete dict interface: - # * Does not support item assignment, thus not allowing this function - # to be used only for removing existing cache entries. - # * Does not support the dict.pop() method, forcing us to use the - # get/del patterns instead. For more detailed information see the - # following links: - # https://github.com/pypa/setuptools/issues/202#issuecomment-202913420 - # http://bit.ly/2h9itJX - old_entry = cache[p] - del cache[p] - new_entry = updater and updater(p, old_entry) - if new_entry is not None: - cache[p] = new_entry - - -def _uncache(normalized_path, cache): - _update_zipimporter_cache(normalized_path, cache) - - -def _remove_and_clear_zip_directory_cache_data(normalized_path): - def clear_and_remove_cached_zip_archive_directory_data(path, old_entry): - old_entry.clear() - - _update_zipimporter_cache( - normalized_path, zipimport._zip_directory_cache, - updater=clear_and_remove_cached_zip_archive_directory_data) - - -# PyPy Python implementation does not allow directly writing to the -# zipimport._zip_directory_cache and so prevents us from attempting to correct -# its content. The best we can do there is clear the problematic cache content -# and have PyPy repopulate it as needed. The downside is that if there are any -# stale zipimport.zipimporter instances laying around, attempting to use them -# will fail due to not having its zip archive directory information available -# instead of being automatically corrected to use the new correct zip archive -# directory information. -if '__pypy__' in sys.builtin_module_names: - _replace_zip_directory_cache_data = \ - _remove_and_clear_zip_directory_cache_data -else: - - def _replace_zip_directory_cache_data(normalized_path): - def replace_cached_zip_archive_directory_data(path, old_entry): - # N.B. In theory, we could load the zip directory information just - # once for all updated path spellings, and then copy it locally and - # update its contained path strings to contain the correct - # spelling, but that seems like a way too invasive move (this cache - # structure is not officially documented anywhere and could in - # theory change with new Python releases) for no significant - # benefit. - old_entry.clear() - zipimport.zipimporter(path) - old_entry.update(zipimport._zip_directory_cache[path]) - return old_entry - - _update_zipimporter_cache( - normalized_path, zipimport._zip_directory_cache, - updater=replace_cached_zip_archive_directory_data) - - -def is_python(text, filename=''): - "Is this string a valid Python script?" - try: - compile(text, filename, 'exec') - except (SyntaxError, TypeError): - return False - else: - return True - - -def is_sh(executable): - """Determine if the specified executable is a .sh (contains a #! line)""" - try: - with io.open(executable, encoding='latin-1') as fp: - magic = fp.read(2) - except (OSError, IOError): - return executable - return magic == '#!' - - -def nt_quote_arg(arg): - """Quote a command line argument according to Windows parsing rules""" - return subprocess.list2cmdline([arg]) - - -def is_python_script(script_text, filename): - """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc. - """ - if filename.endswith('.py') or filename.endswith('.pyw'): - return True # extension says it's Python - if is_python(script_text, filename): - return True # it's syntactically valid Python - if script_text.startswith('#!'): - # It begins with a '#!' line, so check if 'python' is in it somewhere - return 'python' in script_text.splitlines()[0].lower() - - return False # Not any Python I can recognize - - -try: - from os import chmod as _chmod -except ImportError: - # Jython compatibility - def _chmod(*args): - pass - - -def chmod(path, mode): - log.debug("changing mode of %s to %o", path, mode) - try: - _chmod(path, mode) - except os.error as e: - log.debug("chmod failed: %s", e) - - -class CommandSpec(list): - """ - A command spec for a #! header, specified as a list of arguments akin to - those passed to Popen. - """ - - options = [] - split_args = dict() - - @classmethod - def best(cls): - """ - Choose the best CommandSpec class based on environmental conditions. - """ - return cls - - @classmethod - def _sys_executable(cls): - _default = os.path.normpath(sys.executable) - return os.environ.get('__PYVENV_LAUNCHER__', _default) - - @classmethod - def from_param(cls, param): - """ - Construct a CommandSpec from a parameter to build_scripts, which may - be None. - """ - if isinstance(param, cls): - return param - if isinstance(param, list): - return cls(param) - if param is None: - return cls.from_environment() - # otherwise, assume it's a string. - return cls.from_string(param) - - @classmethod - def from_environment(cls): - return cls([cls._sys_executable()]) - - @classmethod - def from_string(cls, string): - """ - Construct a command spec from a simple string representing a command - line parseable by shlex.split. - """ - items = shlex.split(string, **cls.split_args) - return cls(items) - - def install_options(self, script_text): - self.options = shlex.split(self._extract_options(script_text)) - cmdline = subprocess.list2cmdline(self) - if not isascii(cmdline): - self.options[:0] = ['-x'] - - @staticmethod - def _extract_options(orig_script): - """ - Extract any options from the first line of the script. - """ - first = (orig_script + '\n').splitlines()[0] - match = _first_line_re().match(first) - options = match.group(1) or '' if match else '' - return options.strip() - - def as_header(self): - return self._render(self + list(self.options)) - - @staticmethod - def _strip_quotes(item): - _QUOTES = '"\'' - for q in _QUOTES: - if item.startswith(q) and item.endswith(q): - return item[1:-1] - return item - - @staticmethod - def _render(items): - cmdline = subprocess.list2cmdline( - CommandSpec._strip_quotes(item.strip()) for item in items) - return '#!' + cmdline + '\n' - - -# For pbr compat; will be removed in a future version. -sys_executable = CommandSpec._sys_executable() - - -class WindowsCommandSpec(CommandSpec): - split_args = dict(posix=False) - - -class ScriptWriter: - """ - Encapsulates behavior around writing entry point scripts for console and - gui apps. - """ - - template = textwrap.dedent(r""" - # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r - import re - import sys - - # for compatibility with easy_install; see #2198 - __requires__ = %(spec)r - - try: - from importlib.metadata import distribution - except ImportError: - try: - from importlib_metadata import distribution - except ImportError: - from pkg_resources import load_entry_point - - - def importlib_load_entry_point(spec, group, name): - dist_name, _, _ = spec.partition('==') - matches = ( - entry_point - for entry_point in distribution(dist_name).entry_points - if entry_point.group == group and entry_point.name == name - ) - return next(matches).load() - - - globals().setdefault('load_entry_point', importlib_load_entry_point) - - - if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) - sys.exit(load_entry_point(%(spec)r, %(group)r, %(name)r)()) - """).lstrip() - - command_spec_class = CommandSpec - - @classmethod - def get_script_args(cls, dist, executable=None, wininst=False): - # for backward compatibility - warnings.warn("Use get_args", EasyInstallDeprecationWarning) - writer = (WindowsScriptWriter if wininst else ScriptWriter).best() - header = cls.get_script_header("", executable, wininst) - return writer.get_args(dist, header) - - @classmethod - def get_script_header(cls, script_text, executable=None, wininst=False): - # for backward compatibility - warnings.warn( - "Use get_header", EasyInstallDeprecationWarning, stacklevel=2) - if wininst: - executable = "python.exe" - return cls.get_header(script_text, executable) - - @classmethod - def get_args(cls, dist, header=None): - """ - Yield write_script() argument tuples for a distribution's - console_scripts and gui_scripts entry points. - """ - if header is None: - header = cls.get_header() - spec = str(dist.as_requirement()) - for type_ in 'console', 'gui': - group = type_ + '_scripts' - for name, ep in dist.get_entry_map(group).items(): - cls._ensure_safe_name(name) - script_text = cls.template % locals() - args = cls._get_script_args(type_, name, header, script_text) - for res in args: - yield res - - @staticmethod - def _ensure_safe_name(name): - """ - Prevent paths in *_scripts entry point names. - """ - has_path_sep = re.search(r'[\\/]', name) - if has_path_sep: - raise ValueError("Path separators not allowed in script names") - - @classmethod - def get_writer(cls, force_windows): - # for backward compatibility - warnings.warn("Use best", EasyInstallDeprecationWarning) - return WindowsScriptWriter.best() if force_windows else cls.best() - - @classmethod - def best(cls): - """ - Select the best ScriptWriter for this environment. - """ - if sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt'): - return WindowsScriptWriter.best() - else: - return cls - - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - # Simply write the stub with no extension. - yield (name, header + script_text) - - @classmethod - def get_header(cls, script_text="", executable=None): - """Create a #! line, getting options (if any) from script_text""" - cmd = cls.command_spec_class.best().from_param(executable) - cmd.install_options(script_text) - return cmd.as_header() - - -class WindowsScriptWriter(ScriptWriter): - command_spec_class = WindowsCommandSpec - - @classmethod - def get_writer(cls): - # for backward compatibility - warnings.warn("Use best", EasyInstallDeprecationWarning) - return cls.best() - - @classmethod - def best(cls): - """ - Select the best ScriptWriter suitable for Windows - """ - writer_lookup = dict( - executable=WindowsExecutableLauncherWriter, - natural=cls, - ) - # for compatibility, use the executable launcher by default - launcher = os.environ.get('SETUPTOOLS_LAUNCHER', 'executable') - return writer_lookup[launcher] - - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - "For Windows, add a .py extension" - ext = dict(console='.pya', gui='.pyw')[type_] - if ext not in os.environ['PATHEXT'].lower().split(';'): - msg = ( - "{ext} not listed in PATHEXT; scripts will not be " - "recognized as executables." - ).format(**locals()) - warnings.warn(msg, UserWarning) - old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe'] - old.remove(ext) - header = cls._adjust_header(type_, header) - blockers = [name + x for x in old] - yield name + ext, header + script_text, 't', blockers - - @classmethod - def _adjust_header(cls, type_, orig_header): - """ - Make sure 'pythonw' is used for gui and 'python' is used for - console (regardless of what sys.executable is). - """ - pattern = 'pythonw.exe' - repl = 'python.exe' - if type_ == 'gui': - pattern, repl = repl, pattern - pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE) - new_header = pattern_ob.sub(string=orig_header, repl=repl) - return new_header if cls._use_header(new_header) else orig_header - - @staticmethod - def _use_header(new_header): - """ - Should _adjust_header use the replaced header? - - On non-windows systems, always use. On - Windows systems, only use the replaced header if it resolves - to an executable on the system. - """ - clean_header = new_header[2:-1].strip('"') - return sys.platform != 'win32' or find_executable(clean_header) - - -class WindowsExecutableLauncherWriter(WindowsScriptWriter): - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - """ - For Windows, add a .py extension and an .exe launcher - """ - if type_ == 'gui': - launcher_type = 'gui' - ext = '-script.pyw' - old = ['.pyw'] - else: - launcher_type = 'cli' - ext = '-script.py' - old = ['.py', '.pyc', '.pyo'] - hdr = cls._adjust_header(type_, header) - blockers = [name + x for x in old] - yield (name + ext, hdr + script_text, 't', blockers) - yield ( - name + '.exe', get_win_launcher(launcher_type), - 'b' # write in binary mode - ) - if not is_64bit(): - # install a manifest for the launcher to prevent Windows - # from detecting it as an installer (which it will for - # launchers like easy_install.exe). Consider only - # adding a manifest for launchers detected as installers. - # See Distribute #143 for details. - m_name = name + '.exe.manifest' - yield (m_name, load_launcher_manifest(name), 't') - - -# for backward-compatibility -get_script_args = ScriptWriter.get_script_args -get_script_header = ScriptWriter.get_script_header - - -def get_win_launcher(type): - """ - Load the Windows launcher (executable) suitable for launching a script. - - `type` should be either 'cli' or 'gui' - - Returns the executable as a byte string. - """ - launcher_fn = '%s.exe' % type - if is_64bit(): - if get_platform() == "win-arm64": - launcher_fn = launcher_fn.replace(".", "-arm64.") - else: - launcher_fn = launcher_fn.replace(".", "-64.") - else: - launcher_fn = launcher_fn.replace(".", "-32.") - return resource_string('setuptools', launcher_fn) - - -def load_launcher_manifest(name): - manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml') - return manifest.decode('utf-8') % vars() - - -def rmtree(path, ignore_errors=False, onerror=auto_chmod): - return shutil.rmtree(path, ignore_errors, onerror) - - -def current_umask(): - tmp = os.umask(0o022) - os.umask(tmp) - return tmp - - -def only_strs(values): - """ - Exclude non-str values. Ref #3063. - """ - return filter(lambda val: isinstance(val, str), values) - - -class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning): - """ - Warning for EasyInstall deprecations, bypassing suppression. - """ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/editable_wheel.py b/venv/lib/python3.11/site-packages/setuptools/command/editable_wheel.py deleted file mode 100755 index d60cfbe..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/editable_wheel.py +++ /dev/null @@ -1,844 +0,0 @@ -""" -Create a wheel that, when installed, will make the source package 'editable' -(add it to the interpreter's path, including metadata) per PEP 660. Replaces -'setup.py develop'. - -.. note:: - One of the mechanisms briefly mentioned in PEP 660 to implement editable installs is - to create a separated directory inside ``build`` and use a .pth file to point to that - directory. In the context of this file such directory is referred as - *auxiliary build directory* or ``auxiliary_dir``. -""" - -import logging -import os -import re -import shutil -import sys -import traceback -import warnings -from contextlib import suppress -from enum import Enum -from inspect import cleandoc -from itertools import chain -from pathlib import Path -from tempfile import TemporaryDirectory -from typing import ( - TYPE_CHECKING, - Dict, - Iterable, - Iterator, - List, - Mapping, - Optional, - Tuple, - TypeVar, - Union, -) - -from setuptools import Command, SetuptoolsDeprecationWarning, errors, namespaces -from setuptools.command.build_py import build_py as build_py_cls -from setuptools.discovery import find_package_path -from setuptools.dist import Distribution - -if TYPE_CHECKING: - from wheel.wheelfile import WheelFile # noqa - -if sys.version_info >= (3, 8): - from typing import Protocol -elif TYPE_CHECKING: - from typing_extensions import Protocol -else: - from abc import ABC as Protocol - -_Path = Union[str, Path] -_P = TypeVar("_P", bound=_Path) -_logger = logging.getLogger(__name__) - - -class _EditableMode(Enum): - """ - Possible editable installation modes: - `lenient` (new files automatically added to the package - DEFAULT); - `strict` (requires a new installation when files are added/removed); or - `compat` (attempts to emulate `python setup.py develop` - DEPRECATED). - """ - - STRICT = "strict" - LENIENT = "lenient" - COMPAT = "compat" # TODO: Remove `compat` after Dec/2022. - - @classmethod - def convert(cls, mode: Optional[str]) -> "_EditableMode": - if not mode: - return _EditableMode.LENIENT # default - - _mode = mode.upper() - if _mode not in _EditableMode.__members__: - raise errors.OptionError(f"Invalid editable mode: {mode!r}. Try: 'strict'.") - - if _mode == "COMPAT": - msg = """ - The 'compat' editable mode is transitional and will be removed - in future versions of `setuptools`. - Please adapt your code accordingly to use either the 'strict' or the - 'lenient' modes. - - For more information, please check: - https://setuptools.pypa.io/en/latest/userguide/development_mode.html - """ - warnings.warn(msg, SetuptoolsDeprecationWarning) - - return _EditableMode[_mode] - - -_STRICT_WARNING = """ -New or renamed files may not be automatically picked up without a new installation. -""" - -_LENIENT_WARNING = """ -Options like `package-data`, `include/exclude-package-data` or -`packages.find.exclude/include` may have no effect. -""" - - -class editable_wheel(Command): - """Build 'editable' wheel for development. - (This command is reserved for internal use of setuptools). - """ - - description = "create a PEP 660 'editable' wheel" - - user_options = [ - ("dist-dir=", "d", "directory to put final built distributions in"), - ("dist-info-dir=", "I", "path to a pre-build .dist-info directory"), - ("mode=", None, cleandoc(_EditableMode.__doc__ or "")), - ] - - def initialize_options(self): - self.dist_dir = None - self.dist_info_dir = None - self.project_dir = None - self.mode = None - - def finalize_options(self): - dist = self.distribution - self.project_dir = dist.src_root or os.curdir - self.package_dir = dist.package_dir or {} - self.dist_dir = Path(self.dist_dir or os.path.join(self.project_dir, "dist")) - - def run(self): - try: - self.dist_dir.mkdir(exist_ok=True) - self._ensure_dist_info() - - # Add missing dist_info files - self.reinitialize_command("bdist_wheel") - bdist_wheel = self.get_finalized_command("bdist_wheel") - bdist_wheel.write_wheelfile(self.dist_info_dir) - - self._create_wheel_file(bdist_wheel) - except Exception as ex: - traceback.print_exc() - msg = """ - Support for editable installs via PEP 660 was recently introduced - in `setuptools`. If you are seeing this error, please report to: - - https://github.com/pypa/setuptools/issues - - Meanwhile you can try the legacy behavior by setting an - environment variable and trying to install again: - - SETUPTOOLS_ENABLE_FEATURES="legacy-editable" - """ - raise errors.InternalError(cleandoc(msg)) from ex - - def _ensure_dist_info(self): - if self.dist_info_dir is None: - dist_info = self.reinitialize_command("dist_info") - dist_info.output_dir = self.dist_dir - dist_info.ensure_finalized() - dist_info.run() - self.dist_info_dir = dist_info.dist_info_dir - else: - assert str(self.dist_info_dir).endswith(".dist-info") - assert Path(self.dist_info_dir, "METADATA").exists() - - def _install_namespaces(self, installation_dir, pth_prefix): - # XXX: Only required to support the deprecated namespace practice - dist = self.distribution - if not dist.namespace_packages: - return - - src_root = Path(self.project_dir, self.package_dir.get("", ".")).resolve() - installer = _NamespaceInstaller(dist, installation_dir, pth_prefix, src_root) - installer.install_namespaces() - - def _find_egg_info_dir(self) -> Optional[str]: - parent_dir = Path(self.dist_info_dir).parent if self.dist_info_dir else Path() - candidates = map(str, parent_dir.glob("*.egg-info")) - return next(candidates, None) - - def _configure_build( - self, name: str, unpacked_wheel: _Path, build_lib: _Path, tmp_dir: _Path - ): - """Configure commands to behave in the following ways: - - - Build commands can write to ``build_lib`` if they really want to... - (but this folder is expected to be ignored and modules are expected to live - in the project directory...) - - Binary extensions should be built in-place (editable_mode = True) - - Data/header/script files are not part of the "editable" specification - so they are written directly to the unpacked_wheel directory. - """ - # Non-editable files (data, headers, scripts) are written directly to the - # unpacked_wheel - - dist = self.distribution - wheel = str(unpacked_wheel) - build_lib = str(build_lib) - data = str(Path(unpacked_wheel, f"{name}.data", "data")) - headers = str(Path(unpacked_wheel, f"{name}.data", "headers")) - scripts = str(Path(unpacked_wheel, f"{name}.data", "scripts")) - - # egg-info may be generated again to create a manifest (used for package data) - egg_info = dist.reinitialize_command("egg_info", reinit_subcommands=True) - egg_info.egg_base = str(tmp_dir) - egg_info.ignore_egg_info_in_manifest = True - - build = dist.reinitialize_command("build", reinit_subcommands=True) - install = dist.reinitialize_command("install", reinit_subcommands=True) - - build.build_platlib = build.build_purelib = build.build_lib = build_lib - install.install_purelib = install.install_platlib = install.install_lib = wheel - install.install_scripts = build.build_scripts = scripts - install.install_headers = headers - install.install_data = data - - install_scripts = dist.get_command_obj("install_scripts") - install_scripts.no_ep = True - - build.build_temp = str(tmp_dir) - - build_py = dist.get_command_obj("build_py") - build_py.compile = False - build_py.existing_egg_info_dir = self._find_egg_info_dir() - - self._set_editable_mode() - - build.ensure_finalized() - install.ensure_finalized() - - def _set_editable_mode(self): - """Set the ``editable_mode`` flag in the build sub-commands""" - dist = self.distribution - build = dist.get_command_obj("build") - for cmd_name in build.get_sub_commands(): - cmd = dist.get_command_obj(cmd_name) - if hasattr(cmd, "editable_mode"): - cmd.editable_mode = True - elif hasattr(cmd, "inplace"): - cmd.inplace = True # backward compatibility with distutils - - def _collect_build_outputs(self) -> Tuple[List[str], Dict[str, str]]: - files: List[str] = [] - mapping: Dict[str, str] = {} - build = self.get_finalized_command("build") - - for cmd_name in build.get_sub_commands(): - cmd = self.get_finalized_command(cmd_name) - if hasattr(cmd, "get_outputs"): - files.extend(cmd.get_outputs() or []) - if hasattr(cmd, "get_output_mapping"): - mapping.update(cmd.get_output_mapping() or {}) - - return files, mapping - - def _run_build_commands( - self, dist_name: str, unpacked_wheel: _Path, build_lib: _Path, tmp_dir: _Path - ) -> Tuple[List[str], Dict[str, str]]: - self._configure_build(dist_name, unpacked_wheel, build_lib, tmp_dir) - self._run_build_subcommands() - files, mapping = self._collect_build_outputs() - self._run_install("headers") - self._run_install("scripts") - self._run_install("data") - return files, mapping - - def _run_build_subcommands(self): - """ - Issue #3501 indicates that some plugins/customizations might rely on: - - 1. ``build_py`` not running - 2. ``build_py`` always copying files to ``build_lib`` - - However both these assumptions may be false in editable_wheel. - This method implements a temporary workaround to support the ecosystem - while the implementations catch up. - """ - # TODO: Once plugins/customisations had the chance to catch up, replace - # `self._run_build_subcommands()` with `self.run_command("build")`. - # Also remove _safely_run, TestCustomBuildPy. Suggested date: Aug/2023. - build: Command = self.get_finalized_command("build") - for name in build.get_sub_commands(): - cmd = self.get_finalized_command(name) - if name == "build_py" and type(cmd) != build_py_cls: - self._safely_run(name) - else: - self.run_command(name) - - def _safely_run(self, cmd_name: str): - try: - return self.run_command(cmd_name) - except Exception: - msg = f"""{traceback.format_exc()}\n - If you are seeing this warning it is very likely that a setuptools - plugin or customization overrides the `{cmd_name}` command, without - taking into consideration how editable installs run build steps - starting from v64.0.0. - - Plugin authors and developers relying on custom build steps are encouraged - to update their `{cmd_name}` implementation considering the information in - https://setuptools.pypa.io/en/latest/userguide/extension.html - about editable installs. - - For the time being `setuptools` will silence this error and ignore - the faulty command, but this behaviour will change in future versions.\n - """ - warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2) - - def _create_wheel_file(self, bdist_wheel): - from wheel.wheelfile import WheelFile - - dist_info = self.get_finalized_command("dist_info") - dist_name = dist_info.name - tag = "-".join(bdist_wheel.get_tag()) - build_tag = "0.editable" # According to PEP 427 needs to start with digit - archive_name = f"{dist_name}-{build_tag}-{tag}.whl" - wheel_path = Path(self.dist_dir, archive_name) - if wheel_path.exists(): - wheel_path.unlink() - - unpacked_wheel = TemporaryDirectory(suffix=archive_name) - build_lib = TemporaryDirectory(suffix=".build-lib") - build_tmp = TemporaryDirectory(suffix=".build-temp") - - with unpacked_wheel as unpacked, build_lib as lib, build_tmp as tmp: - unpacked_dist_info = Path(unpacked, Path(self.dist_info_dir).name) - shutil.copytree(self.dist_info_dir, unpacked_dist_info) - self._install_namespaces(unpacked, dist_info.name) - files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp) - strategy = self._select_strategy(dist_name, tag, lib) - with strategy, WheelFile(wheel_path, "w") as wheel_obj: - strategy(wheel_obj, files, mapping) - wheel_obj.write_files(unpacked) - - return wheel_path - - def _run_install(self, category: str): - has_category = getattr(self.distribution, f"has_{category}", None) - if has_category and has_category(): - _logger.info(f"Installing {category} as non editable") - self.run_command(f"install_{category}") - - def _select_strategy( - self, - name: str, - tag: str, - build_lib: _Path, - ) -> "EditableStrategy": - """Decides which strategy to use to implement an editable installation.""" - build_name = f"__editable__.{name}-{tag}" - project_dir = Path(self.project_dir) - mode = _EditableMode.convert(self.mode) - - if mode is _EditableMode.STRICT: - auxiliary_dir = _empty_dir(Path(self.project_dir, "build", build_name)) - return _LinkTree(self.distribution, name, auxiliary_dir, build_lib) - - packages = _find_packages(self.distribution) - has_simple_layout = _simple_layout(packages, self.package_dir, project_dir) - is_compat_mode = mode is _EditableMode.COMPAT - if set(self.package_dir) == {""} and has_simple_layout or is_compat_mode: - # src-layout(ish) is relatively safe for a simple pth file - src_dir = self.package_dir.get("", ".") - return _StaticPth(self.distribution, name, [Path(project_dir, src_dir)]) - - # Use a MetaPathFinder to avoid adding accidental top-level packages/modules - return _TopLevelFinder(self.distribution, name) - - -class EditableStrategy(Protocol): - def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - ... - - def __enter__(self): - ... - - def __exit__(self, _exc_type, _exc_value, _traceback): - ... - - -class _StaticPth: - def __init__(self, dist: Distribution, name: str, path_entries: List[Path]): - self.dist = dist - self.name = name - self.path_entries = path_entries - - def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - entries = "\n".join((str(p.resolve()) for p in self.path_entries)) - contents = bytes(f"{entries}\n", "utf-8") - wheel.writestr(f"__editable__.{self.name}.pth", contents) - - def __enter__(self): - msg = f""" - Editable install will be performed using .pth file to extend `sys.path` with: - {list(map(os.fspath, self.path_entries))!r} - """ - _logger.warning(msg + _LENIENT_WARNING) - return self - - def __exit__(self, _exc_type, _exc_value, _traceback): - ... - - -class _LinkTree(_StaticPth): - """ - Creates a ``.pth`` file that points to a link tree in the ``auxiliary_dir``. - - This strategy will only link files (not dirs), so it can be implemented in - any OS, even if that means using hardlinks instead of symlinks. - - By collocating ``auxiliary_dir`` and the original source code, limitations - with hardlinks should be avoided. - """ - def __init__( - self, dist: Distribution, - name: str, - auxiliary_dir: _Path, - build_lib: _Path, - ): - self.auxiliary_dir = Path(auxiliary_dir) - self.build_lib = Path(build_lib).resolve() - self._file = dist.get_command_obj("build_py").copy_file - super().__init__(dist, name, [self.auxiliary_dir]) - - def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - self._create_links(files, mapping) - super().__call__(wheel, files, mapping) - - def _normalize_output(self, file: str) -> Optional[str]: - # Files relative to build_lib will be normalized to None - with suppress(ValueError): - path = Path(file).resolve().relative_to(self.build_lib) - return str(path).replace(os.sep, '/') - return None - - def _create_file(self, relative_output: str, src_file: str, link=None): - dest = self.auxiliary_dir / relative_output - if not dest.parent.is_dir(): - dest.parent.mkdir(parents=True) - self._file(src_file, dest, link=link) - - def _create_links(self, outputs, output_mapping): - self.auxiliary_dir.mkdir(parents=True, exist_ok=True) - link_type = "sym" if _can_symlink_files(self.auxiliary_dir) else "hard" - mappings = { - self._normalize_output(k): v - for k, v in output_mapping.items() - } - mappings.pop(None, None) # remove files that are not relative to build_lib - - for output in outputs: - relative = self._normalize_output(output) - if relative and relative not in mappings: - self._create_file(relative, output) - - for relative, src in mappings.items(): - self._create_file(relative, src, link=link_type) - - def __enter__(self): - msg = "Strict editable install will be performed using a link tree.\n" - _logger.warning(msg + _STRICT_WARNING) - return self - - def __exit__(self, _exc_type, _exc_value, _traceback): - msg = f"""\n - Strict editable installation performed using the auxiliary directory: - {self.auxiliary_dir} - - Please be careful to not remove this directory, otherwise you might not be able - to import/use your package. - """ - warnings.warn(msg, InformationOnly) - - -class _TopLevelFinder: - def __init__(self, dist: Distribution, name: str): - self.dist = dist - self.name = name - - def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - src_root = self.dist.src_root or os.curdir - top_level = chain(_find_packages(self.dist), _find_top_level_modules(self.dist)) - package_dir = self.dist.package_dir or {} - roots = _find_package_roots(top_level, package_dir, src_root) - - namespaces_: Dict[str, List[str]] = dict(chain( - _find_namespaces(self.dist.packages or [], roots), - ((ns, []) for ns in _find_virtual_namespaces(roots)), - )) - - name = f"__editable__.{self.name}.finder" - finder = _make_identifier(name) - content = bytes(_finder_template(name, roots, namespaces_), "utf-8") - wheel.writestr(f"{finder}.py", content) - - content = bytes(f"import {finder}; {finder}.install()", "utf-8") - wheel.writestr(f"__editable__.{self.name}.pth", content) - - def __enter__(self): - msg = "Editable install will be performed using a meta path finder.\n" - _logger.warning(msg + _LENIENT_WARNING) - return self - - def __exit__(self, _exc_type, _exc_value, _traceback): - msg = """\n - Please be careful with folders in your working directory with the same - name as your package as they may take precedence during imports. - """ - warnings.warn(msg, InformationOnly) - - -def _can_symlink_files(base_dir: Path) -> bool: - with TemporaryDirectory(dir=str(base_dir.resolve())) as tmp: - path1, path2 = Path(tmp, "file1.txt"), Path(tmp, "file2.txt") - path1.write_text("file1", encoding="utf-8") - with suppress(AttributeError, NotImplementedError, OSError): - os.symlink(path1, path2) - if path2.is_symlink() and path2.read_text(encoding="utf-8") == "file1": - return True - - try: - os.link(path1, path2) # Ensure hard links can be created - except Exception as ex: - msg = ( - "File system does not seem to support either symlinks or hard links. " - "Strict editable installs require one of them to be supported." - ) - raise LinksNotSupported(msg) from ex - return False - - -def _simple_layout( - packages: Iterable[str], package_dir: Dict[str, str], project_dir: Path -) -> bool: - """Return ``True`` if: - - all packages are contained by the same parent directory, **and** - - all packages become importable if the parent directory is added to ``sys.path``. - - >>> _simple_layout(['a'], {"": "src"}, "/tmp/myproj") - True - >>> _simple_layout(['a', 'a.b'], {"": "src"}, "/tmp/myproj") - True - >>> _simple_layout(['a', 'a.b'], {}, "/tmp/myproj") - True - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"": "src"}, "/tmp/myproj") - True - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "a", "b": "b"}, ".") - True - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a", "b": "_b"}, ".") - False - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a"}, "/tmp/myproj") - False - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a.a1.a2": "_a2"}, ".") - False - >>> _simple_layout(['a', 'a.b'], {"": "src", "a.b": "_ab"}, "/tmp/myproj") - False - >>> # Special cases, no packages yet: - >>> _simple_layout([], {"": "src"}, "/tmp/myproj") - True - >>> _simple_layout([], {"a": "_a", "": "src"}, "/tmp/myproj") - False - """ - layout = { - pkg: find_package_path(pkg, package_dir, project_dir) - for pkg in packages - } - if not layout: - return set(package_dir) in ({}, {""}) - parent = os.path.commonpath([_parent_path(k, v) for k, v in layout.items()]) - return all( - _normalize_path(Path(parent, *key.split('.'))) == _normalize_path(value) - for key, value in layout.items() - ) - - -def _parent_path(pkg, pkg_path): - """Infer the parent path containing a package, that if added to ``sys.path`` would - allow importing that package. - When ``pkg`` is directly mapped into a directory with a different name, return its - own path. - >>> _parent_path("a", "src/a") - 'src' - >>> _parent_path("b", "src/c") - 'src/c' - """ - parent = pkg_path[:-len(pkg)] if pkg_path.endswith(pkg) else pkg_path - return parent.rstrip("/" + os.sep) - - -def _find_packages(dist: Distribution) -> Iterator[str]: - yield from iter(dist.packages or []) - - py_modules = dist.py_modules or [] - nested_modules = [mod for mod in py_modules if "." in mod] - if dist.ext_package: - yield dist.ext_package - else: - ext_modules = dist.ext_modules or [] - nested_modules += [x.name for x in ext_modules if "." in x.name] - - for module in nested_modules: - package, _, _ = module.rpartition(".") - yield package - - -def _find_top_level_modules(dist: Distribution) -> Iterator[str]: - py_modules = dist.py_modules or [] - yield from (mod for mod in py_modules if "." not in mod) - - if not dist.ext_package: - ext_modules = dist.ext_modules or [] - yield from (x.name for x in ext_modules if "." not in x.name) - - -def _find_package_roots( - packages: Iterable[str], - package_dir: Mapping[str, str], - src_root: _Path, -) -> Dict[str, str]: - pkg_roots: Dict[str, str] = { - pkg: _absolute_root(find_package_path(pkg, package_dir, src_root)) - for pkg in sorted(packages) - } - - return _remove_nested(pkg_roots) - - -def _absolute_root(path: _Path) -> str: - """Works for packages and top-level modules""" - path_ = Path(path) - parent = path_.parent - - if path_.exists(): - return str(path_.resolve()) - else: - return str(parent.resolve() / path_.name) - - -def _find_virtual_namespaces(pkg_roots: Dict[str, str]) -> Iterator[str]: - """By carefully designing ``package_dir``, it is possible to implement the logical - structure of PEP 420 in a package without the corresponding directories. - - Moreover a parent package can be purposefully/accidentally skipped in the discovery - phase (e.g. ``find_packages(include=["mypkg.*"])``, when ``mypkg.foo`` is included - by ``mypkg`` itself is not). - We consider this case to also be a virtual namespace (ignoring the original - directory) to emulate a non-editable installation. - - This function will try to find these kinds of namespaces. - """ - for pkg in pkg_roots: - if "." not in pkg: - continue - parts = pkg.split(".") - for i in range(len(parts) - 1, 0, -1): - partial_name = ".".join(parts[:i]) - path = Path(find_package_path(partial_name, pkg_roots, "")) - if not path.exists() or partial_name not in pkg_roots: - # partial_name not in pkg_roots ==> purposefully/accidentally skipped - yield partial_name - - -def _find_namespaces( - packages: List[str], pkg_roots: Dict[str, str] -) -> Iterator[Tuple[str, List[str]]]: - for pkg in packages: - path = find_package_path(pkg, pkg_roots, "") - if Path(path).exists() and not Path(path, "__init__.py").exists(): - yield (pkg, [path]) - - -def _remove_nested(pkg_roots: Dict[str, str]) -> Dict[str, str]: - output = dict(pkg_roots.copy()) - - for pkg, path in reversed(list(pkg_roots.items())): - if any( - pkg != other and _is_nested(pkg, path, other, other_path) - for other, other_path in pkg_roots.items() - ): - output.pop(pkg) - - return output - - -def _is_nested(pkg: str, pkg_path: str, parent: str, parent_path: str) -> bool: - """ - Return ``True`` if ``pkg`` is nested inside ``parent`` both logically and in the - file system. - >>> _is_nested("a.b", "path/a/b", "a", "path/a") - True - >>> _is_nested("a.b", "path/a/b", "a", "otherpath/a") - False - >>> _is_nested("a.b", "path/a/b", "c", "path/c") - False - >>> _is_nested("a.a", "path/a/a", "a", "path/a") - True - >>> _is_nested("b.a", "path/b/a", "a", "path/a") - False - """ - norm_pkg_path = _normalize_path(pkg_path) - rest = pkg.replace(parent, "", 1).strip(".").split(".") - return ( - pkg.startswith(parent) - and norm_pkg_path == _normalize_path(Path(parent_path, *rest)) - ) - - -def _normalize_path(filename: _Path) -> str: - """Normalize a file/dir name for comparison purposes""" - # See pkg_resources.normalize_path - file = os.path.abspath(filename) if sys.platform == 'cygwin' else filename - return os.path.normcase(os.path.realpath(os.path.normpath(file))) - - -def _empty_dir(dir_: _P) -> _P: - """Create a directory ensured to be empty. Existing files may be removed.""" - shutil.rmtree(dir_, ignore_errors=True) - os.makedirs(dir_) - return dir_ - - -def _make_identifier(name: str) -> str: - """Make a string safe to be used as Python identifier. - >>> _make_identifier("12abc") - '_12abc' - >>> _make_identifier("__editable__.myns.pkg-78.9.3_local") - '__editable___myns_pkg_78_9_3_local' - """ - safe = re.sub(r'\W|^(?=\d)', '_', name) - assert safe.isidentifier() - return safe - - -class _NamespaceInstaller(namespaces.Installer): - def __init__(self, distribution, installation_dir, editable_name, src_root): - self.distribution = distribution - self.src_root = src_root - self.installation_dir = installation_dir - self.editable_name = editable_name - self.outputs = [] - self.dry_run = False - - def _get_target(self): - """Installation target.""" - return os.path.join(self.installation_dir, self.editable_name) - - def _get_root(self): - """Where the modules/packages should be loaded from.""" - return repr(str(self.src_root)) - - -_FINDER_TEMPLATE = """\ -import sys -from importlib.machinery import ModuleSpec -from importlib.machinery import all_suffixes as module_suffixes -from importlib.util import spec_from_file_location -from itertools import chain -from pathlib import Path - -MAPPING = {mapping!r} -NAMESPACES = {namespaces!r} -PATH_PLACEHOLDER = {name!r} + ".__path_hook__" - - -class _EditableFinder: # MetaPathFinder - @classmethod - def find_spec(cls, fullname, path=None, target=None): - for pkg, pkg_path in reversed(list(MAPPING.items())): - if fullname == pkg or fullname.startswith(f"{{pkg}}."): - rest = fullname.replace(pkg, "", 1).strip(".").split(".") - return cls._find_spec(fullname, Path(pkg_path, *rest)) - - return None - - @classmethod - def _find_spec(cls, fullname, candidate_path): - init = candidate_path / "__init__.py" - candidates = (candidate_path.with_suffix(x) for x in module_suffixes()) - for candidate in chain([init], candidates): - if candidate.exists(): - return spec_from_file_location(fullname, candidate) - - -class _EditableNamespaceFinder: # PathEntryFinder - @classmethod - def _path_hook(cls, path): - if path == PATH_PLACEHOLDER: - return cls - raise ImportError - - @classmethod - def _paths(cls, fullname): - # Ensure __path__ is not empty for the spec to be considered a namespace. - return NAMESPACES[fullname] or MAPPING.get(fullname) or [PATH_PLACEHOLDER] - - @classmethod - def find_spec(cls, fullname, target=None): - if fullname in NAMESPACES: - spec = ModuleSpec(fullname, None, is_package=True) - spec.submodule_search_locations = cls._paths(fullname) - return spec - return None - - @classmethod - def find_module(cls, fullname): - return None - - -def install(): - if not any(finder == _EditableFinder for finder in sys.meta_path): - sys.meta_path.append(_EditableFinder) - - if not NAMESPACES: - return - - if not any(hook == _EditableNamespaceFinder._path_hook for hook in sys.path_hooks): - # PathEntryFinder is needed to create NamespaceSpec without private APIS - sys.path_hooks.append(_EditableNamespaceFinder._path_hook) - if PATH_PLACEHOLDER not in sys.path: - sys.path.append(PATH_PLACEHOLDER) # Used just to trigger the path hook -""" - - -def _finder_template( - name: str, mapping: Mapping[str, str], namespaces: Dict[str, List[str]] -) -> str: - """Create a string containing the code for the``MetaPathFinder`` and - ``PathEntryFinder``. - """ - mapping = dict(sorted(mapping.items(), key=lambda p: p[0])) - return _FINDER_TEMPLATE.format(name=name, mapping=mapping, namespaces=namespaces) - - -class InformationOnly(UserWarning): - """Currently there is no clear way of displaying messages to the users - that use the setuptools backend directly via ``pip``. - The only thing that might work is a warning, although it is not the - most appropriate tool for the job... - """ - - -class LinksNotSupported(errors.FileError): - """File system does not seem to support either symlinks or hard links.""" diff --git a/venv/lib/python3.11/site-packages/setuptools/command/egg_info.py b/venv/lib/python3.11/site-packages/setuptools/command/egg_info.py deleted file mode 100755 index 257afc3..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/egg_info.py +++ /dev/null @@ -1,775 +0,0 @@ -"""setuptools.command.egg_info - -Create a distribution's .egg-info directory and contents""" - -from distutils.filelist import FileList as _FileList -from distutils.errors import DistutilsInternalError -from distutils.util import convert_path -from distutils import log -import distutils.errors -import distutils.filelist -import functools -import os -import re -import sys -import io -import warnings -import time -import collections - -from .._importlib import metadata -from .. import _entry_points - -from setuptools import Command -from setuptools.command.sdist import sdist -from setuptools.command.sdist import walk_revctrl -from setuptools.command.setopt import edit_config -from setuptools.command import bdist_egg -from pkg_resources import ( - Requirement, safe_name, parse_version, - safe_version, to_filename) -import setuptools.unicode_utils as unicode_utils -from setuptools.glob import glob - -from setuptools.extern import packaging -from setuptools.extern.jaraco.text import yield_lines -from setuptools import SetuptoolsDeprecationWarning - - -def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME - """ - Translate a file path glob like '*.txt' in to a regular expression. - This differs from fnmatch.translate which allows wildcards to match - directory separators. It also knows about '**/' which matches any number of - directories. - """ - pat = '' - - # This will split on '/' within [character classes]. This is deliberate. - chunks = glob.split(os.path.sep) - - sep = re.escape(os.sep) - valid_char = '[^%s]' % (sep,) - - for c, chunk in enumerate(chunks): - last_chunk = c == len(chunks) - 1 - - # Chunks that are a literal ** are globstars. They match anything. - if chunk == '**': - if last_chunk: - # Match anything if this is the last component - pat += '.*' - else: - # Match '(name/)*' - pat += '(?:%s+%s)*' % (valid_char, sep) - continue # Break here as the whole path component has been handled - - # Find any special characters in the remainder - i = 0 - chunk_len = len(chunk) - while i < chunk_len: - char = chunk[i] - if char == '*': - # Match any number of name characters - pat += valid_char + '*' - elif char == '?': - # Match a name character - pat += valid_char - elif char == '[': - # Character class - inner_i = i + 1 - # Skip initial !/] chars - if inner_i < chunk_len and chunk[inner_i] == '!': - inner_i = inner_i + 1 - if inner_i < chunk_len and chunk[inner_i] == ']': - inner_i = inner_i + 1 - - # Loop till the closing ] is found - while inner_i < chunk_len and chunk[inner_i] != ']': - inner_i = inner_i + 1 - - if inner_i >= chunk_len: - # Got to the end of the string without finding a closing ] - # Do not treat this as a matching group, but as a literal [ - pat += re.escape(char) - else: - # Grab the insides of the [brackets] - inner = chunk[i + 1:inner_i] - char_class = '' - - # Class negation - if inner[0] == '!': - char_class = '^' - inner = inner[1:] - - char_class += re.escape(inner) - pat += '[%s]' % (char_class,) - - # Skip to the end ] - i = inner_i - else: - pat += re.escape(char) - i += 1 - - # Join each chunk with the dir separator - if not last_chunk: - pat += sep - - pat += r'\Z' - return re.compile(pat, flags=re.MULTILINE | re.DOTALL) - - -class InfoCommon: - tag_build = None - tag_date = None - - @property - def name(self): - return safe_name(self.distribution.get_name()) - - def tagged_version(self): - return safe_version(self._maybe_tag(self.distribution.get_version())) - - def _maybe_tag(self, version): - """ - egg_info may be called more than once for a distribution, - in which case the version string already contains all tags. - """ - return ( - version if self.vtags and self._already_tagged(version) - else version + self.vtags - ) - - def _already_tagged(self, version: str) -> bool: - # Depending on their format, tags may change with version normalization. - # So in addition the regular tags, we have to search for the normalized ones. - return version.endswith(self.vtags) or version.endswith(self._safe_tags()) - - def _safe_tags(self) -> str: - # To implement this we can rely on `safe_version` pretending to be version 0 - # followed by tags. Then we simply discard the starting 0 (fake version number) - return safe_version(f"0{self.vtags}")[1:] - - def tags(self) -> str: - version = '' - if self.tag_build: - version += self.tag_build - if self.tag_date: - version += time.strftime("%Y%m%d") - return version - vtags = property(tags) - - -class egg_info(InfoCommon, Command): - description = "create a distribution's .egg-info directory" - - user_options = [ - ('egg-base=', 'e', "directory containing .egg-info directories" - " (default: top of the source tree)"), - ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), - ('tag-build=', 'b', "Specify explicit tag to add to version number"), - ('no-date', 'D', "Don't include date stamp [default]"), - ] - - boolean_options = ['tag-date'] - negative_opt = { - 'no-date': 'tag-date', - } - - def initialize_options(self): - self.egg_base = None - self.egg_name = None - self.egg_info = None - self.egg_version = None - self.broken_egg_info = False - self.ignore_egg_info_in_manifest = False - - #################################### - # allow the 'tag_svn_revision' to be detected and - # set, supporting sdists built on older Setuptools. - @property - def tag_svn_revision(self): - pass - - @tag_svn_revision.setter - def tag_svn_revision(self, value): - pass - #################################### - - def save_version_info(self, filename): - """ - Materialize the value of date into the - build tag. Install build keys in a deterministic order - to avoid arbitrary reordering on subsequent builds. - """ - egg_info = collections.OrderedDict() - # follow the order these keys would have been added - # when PYTHONHASHSEED=0 - egg_info['tag_build'] = self.tags() - egg_info['tag_date'] = 0 - edit_config(filename, dict(egg_info=egg_info)) - - def finalize_options(self): - # Note: we need to capture the current value returned - # by `self.tagged_version()`, so we can later update - # `self.distribution.metadata.version` without - # repercussions. - self.egg_name = self.name - self.egg_version = self.tagged_version() - parsed_version = parse_version(self.egg_version) - - try: - is_version = isinstance(parsed_version, packaging.version.Version) - spec = "%s==%s" if is_version else "%s===%s" - Requirement(spec % (self.egg_name, self.egg_version)) - except ValueError as e: - raise distutils.errors.DistutilsOptionError( - "Invalid distribution name or version syntax: %s-%s" % - (self.egg_name, self.egg_version) - ) from e - - if self.egg_base is None: - dirs = self.distribution.package_dir - self.egg_base = (dirs or {}).get('', os.curdir) - - self.ensure_dirname('egg_base') - self.egg_info = to_filename(self.egg_name) + '.egg-info' - if self.egg_base != os.curdir: - self.egg_info = os.path.join(self.egg_base, self.egg_info) - if '-' in self.egg_name: - self.check_broken_egg_info() - - # Set package version for the benefit of dumber commands - # (e.g. sdist, bdist_wininst, etc.) - # - self.distribution.metadata.version = self.egg_version - - # If we bootstrapped around the lack of a PKG-INFO, as might be the - # case in a fresh checkout, make sure that any special tags get added - # to the version info - # - pd = self.distribution._patched_dist - if pd is not None and pd.key == self.egg_name.lower(): - pd._version = self.egg_version - pd._parsed_version = parse_version(self.egg_version) - self.distribution._patched_dist = None - - def write_or_delete_file(self, what, filename, data, force=False): - """Write `data` to `filename` or delete if empty - - If `data` is non-empty, this routine is the same as ``write_file()``. - If `data` is empty but not ``None``, this is the same as calling - ``delete_file(filename)`. If `data` is ``None``, then this is a no-op - unless `filename` exists, in which case a warning is issued about the - orphaned file (if `force` is false), or deleted (if `force` is true). - """ - if data: - self.write_file(what, filename, data) - elif os.path.exists(filename): - if data is None and not force: - log.warn( - "%s not set in setup(), but %s exists", what, filename - ) - return - else: - self.delete_file(filename) - - def write_file(self, what, filename, data): - """Write `data` to `filename` (if not a dry run) after announcing it - - `what` is used in a log message to identify what is being written - to the file. - """ - log.info("writing %s to %s", what, filename) - data = data.encode("utf-8") - if not self.dry_run: - f = open(filename, 'wb') - f.write(data) - f.close() - - def delete_file(self, filename): - """Delete `filename` (if not a dry run) after announcing it""" - log.info("deleting %s", filename) - if not self.dry_run: - os.unlink(filename) - - def run(self): - self.mkpath(self.egg_info) - try: - os.utime(self.egg_info, None) - except OSError as e: - msg = f"Cannot update time stamp of directory '{self.egg_info}'" - raise distutils.errors.DistutilsFileError(msg) from e - for ep in metadata.entry_points(group='egg_info.writers'): - writer = ep.load() - writer(self, ep.name, os.path.join(self.egg_info, ep.name)) - - # Get rid of native_libs.txt if it was put there by older bdist_egg - nl = os.path.join(self.egg_info, "native_libs.txt") - if os.path.exists(nl): - self.delete_file(nl) - - self.find_sources() - - def find_sources(self): - """Generate SOURCES.txt manifest file""" - manifest_filename = os.path.join(self.egg_info, "SOURCES.txt") - mm = manifest_maker(self.distribution) - mm.ignore_egg_info_dir = self.ignore_egg_info_in_manifest - mm.manifest = manifest_filename - mm.run() - self.filelist = mm.filelist - - def check_broken_egg_info(self): - bei = self.egg_name + '.egg-info' - if self.egg_base != os.curdir: - bei = os.path.join(self.egg_base, bei) - if os.path.exists(bei): - log.warn( - "-" * 78 + '\n' - "Note: Your current .egg-info directory has a '-' in its name;" - '\nthis will not work correctly with "setup.py develop".\n\n' - 'Please rename %s to %s to correct this problem.\n' + '-' * 78, - bei, self.egg_info - ) - self.broken_egg_info = self.egg_info - self.egg_info = bei # make it work for now - - -class FileList(_FileList): - # Implementations of the various MANIFEST.in commands - - def __init__(self, warn=None, debug_print=None, ignore_egg_info_dir=False): - super().__init__(warn, debug_print) - self.ignore_egg_info_dir = ignore_egg_info_dir - - def process_template_line(self, line): - # Parse the line: split it up, make sure the right number of words - # is there, and return the relevant words. 'action' is always - # defined: it's the first word of the line. Which of the other - # three are defined depends on the action; it'll be either - # patterns, (dir and patterns), or (dir_pattern). - (action, patterns, dir, dir_pattern) = self._parse_template_line(line) - - action_map = { - 'include': self.include, - 'exclude': self.exclude, - 'global-include': self.global_include, - 'global-exclude': self.global_exclude, - 'recursive-include': functools.partial( - self.recursive_include, dir, - ), - 'recursive-exclude': functools.partial( - self.recursive_exclude, dir, - ), - 'graft': self.graft, - 'prune': self.prune, - } - log_map = { - 'include': "warning: no files found matching '%s'", - 'exclude': ( - "warning: no previously-included files found " - "matching '%s'" - ), - 'global-include': ( - "warning: no files found matching '%s' " - "anywhere in distribution" - ), - 'global-exclude': ( - "warning: no previously-included files matching " - "'%s' found anywhere in distribution" - ), - 'recursive-include': ( - "warning: no files found matching '%s' " - "under directory '%s'" - ), - 'recursive-exclude': ( - "warning: no previously-included files matching " - "'%s' found under directory '%s'" - ), - 'graft': "warning: no directories found matching '%s'", - 'prune': "no previously-included directories found matching '%s'", - } - - try: - process_action = action_map[action] - except KeyError: - raise DistutilsInternalError( - "this cannot happen: invalid action '{action!s}'". - format(action=action), - ) - - # OK, now we know that the action is valid and we have the - # right number of words on the line for that action -- so we - # can proceed with minimal error-checking. - - action_is_recursive = action.startswith('recursive-') - if action in {'graft', 'prune'}: - patterns = [dir_pattern] - extra_log_args = (dir, ) if action_is_recursive else () - log_tmpl = log_map[action] - - self.debug_print( - ' '.join( - [action] + - ([dir] if action_is_recursive else []) + - patterns, - ) - ) - for pattern in patterns: - if not process_action(pattern): - log.warn(log_tmpl, pattern, *extra_log_args) - - def _remove_files(self, predicate): - """ - Remove all files from the file list that match the predicate. - Return True if any matching files were removed - """ - found = False - for i in range(len(self.files) - 1, -1, -1): - if predicate(self.files[i]): - self.debug_print(" removing " + self.files[i]) - del self.files[i] - found = True - return found - - def include(self, pattern): - """Include files that match 'pattern'.""" - found = [f for f in glob(pattern) if not os.path.isdir(f)] - self.extend(found) - return bool(found) - - def exclude(self, pattern): - """Exclude files that match 'pattern'.""" - match = translate_pattern(pattern) - return self._remove_files(match.match) - - def recursive_include(self, dir, pattern): - """ - Include all files anywhere in 'dir/' that match the pattern. - """ - full_pattern = os.path.join(dir, '**', pattern) - found = [f for f in glob(full_pattern, recursive=True) - if not os.path.isdir(f)] - self.extend(found) - return bool(found) - - def recursive_exclude(self, dir, pattern): - """ - Exclude any file anywhere in 'dir/' that match the pattern. - """ - match = translate_pattern(os.path.join(dir, '**', pattern)) - return self._remove_files(match.match) - - def graft(self, dir): - """Include all files from 'dir/'.""" - found = [ - item - for match_dir in glob(dir) - for item in distutils.filelist.findall(match_dir) - ] - self.extend(found) - return bool(found) - - def prune(self, dir): - """Filter out files from 'dir/'.""" - match = translate_pattern(os.path.join(dir, '**')) - return self._remove_files(match.match) - - def global_include(self, pattern): - """ - Include all files anywhere in the current directory that match the - pattern. This is very inefficient on large file trees. - """ - if self.allfiles is None: - self.findall() - match = translate_pattern(os.path.join('**', pattern)) - found = [f for f in self.allfiles if match.match(f)] - self.extend(found) - return bool(found) - - def global_exclude(self, pattern): - """ - Exclude all files anywhere that match the pattern. - """ - match = translate_pattern(os.path.join('**', pattern)) - return self._remove_files(match.match) - - def append(self, item): - if item.endswith('\r'): # Fix older sdists built on Windows - item = item[:-1] - path = convert_path(item) - - if self._safe_path(path): - self.files.append(path) - - def extend(self, paths): - self.files.extend(filter(self._safe_path, paths)) - - def _repair(self): - """ - Replace self.files with only safe paths - - Because some owners of FileList manipulate the underlying - ``files`` attribute directly, this method must be called to - repair those paths. - """ - self.files = list(filter(self._safe_path, self.files)) - - def _safe_path(self, path): - enc_warn = "'%s' not %s encodable -- skipping" - - # To avoid accidental trans-codings errors, first to unicode - u_path = unicode_utils.filesys_decode(path) - if u_path is None: - log.warn("'%s' in unexpected encoding -- skipping" % path) - return False - - # Must ensure utf-8 encodability - utf8_path = unicode_utils.try_encode(u_path, "utf-8") - if utf8_path is None: - log.warn(enc_warn, path, 'utf-8') - return False - - try: - # ignore egg-info paths - is_egg_info = ".egg-info" in u_path or b".egg-info" in utf8_path - if self.ignore_egg_info_dir and is_egg_info: - return False - # accept is either way checks out - if os.path.exists(u_path) or os.path.exists(utf8_path): - return True - # this will catch any encode errors decoding u_path - except UnicodeEncodeError: - log.warn(enc_warn, path, sys.getfilesystemencoding()) - - -class manifest_maker(sdist): - template = "MANIFEST.in" - - def initialize_options(self): - self.use_defaults = 1 - self.prune = 1 - self.manifest_only = 1 - self.force_manifest = 1 - self.ignore_egg_info_dir = False - - def finalize_options(self): - pass - - def run(self): - self.filelist = FileList(ignore_egg_info_dir=self.ignore_egg_info_dir) - if not os.path.exists(self.manifest): - self.write_manifest() # it must exist so it'll get in the list - self.add_defaults() - if os.path.exists(self.template): - self.read_template() - self.add_license_files() - self._add_referenced_files() - self.prune_file_list() - self.filelist.sort() - self.filelist.remove_duplicates() - self.write_manifest() - - def _manifest_normalize(self, path): - path = unicode_utils.filesys_decode(path) - return path.replace(os.sep, '/') - - def write_manifest(self): - """ - Write the file list in 'self.filelist' to the manifest file - named by 'self.manifest'. - """ - self.filelist._repair() - - # Now _repairs should encodability, but not unicode - files = [self._manifest_normalize(f) for f in self.filelist.files] - msg = "writing manifest file '%s'" % self.manifest - self.execute(write_file, (self.manifest, files), msg) - - def warn(self, msg): - if not self._should_suppress_warning(msg): - sdist.warn(self, msg) - - @staticmethod - def _should_suppress_warning(msg): - """ - suppress missing-file warnings from sdist - """ - return re.match(r"standard file .*not found", msg) - - def add_defaults(self): - sdist.add_defaults(self) - self.filelist.append(self.template) - self.filelist.append(self.manifest) - rcfiles = list(walk_revctrl()) - if rcfiles: - self.filelist.extend(rcfiles) - elif os.path.exists(self.manifest): - self.read_manifest() - - if os.path.exists("setup.py"): - # setup.py should be included by default, even if it's not - # the script called to create the sdist - self.filelist.append("setup.py") - - ei_cmd = self.get_finalized_command('egg_info') - self.filelist.graft(ei_cmd.egg_info) - - def add_license_files(self): - license_files = self.distribution.metadata.license_files or [] - for lf in license_files: - log.info("adding license file '%s'", lf) - self.filelist.extend(license_files) - - def _add_referenced_files(self): - """Add files referenced by the config (e.g. `file:` directive) to filelist""" - referenced = getattr(self.distribution, '_referenced_files', []) - # ^-- fallback if dist comes from distutils or is a custom class - for rf in referenced: - log.debug("adding file referenced by config '%s'", rf) - self.filelist.extend(referenced) - - def prune_file_list(self): - build = self.get_finalized_command('build') - base_dir = self.distribution.get_fullname() - self.filelist.prune(build.build_base) - self.filelist.prune(base_dir) - sep = re.escape(os.sep) - self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, - is_regex=1) - - def _safe_data_files(self, build_py): - """ - The parent class implementation of this method - (``sdist``) will try to include data files, which - might cause recursion problems when - ``include_package_data=True``. - - Therefore, avoid triggering any attempt of - analyzing/building the manifest again. - """ - if hasattr(build_py, 'get_data_files_without_manifest'): - return build_py.get_data_files_without_manifest() - - warnings.warn( - "Custom 'build_py' does not implement " - "'get_data_files_without_manifest'.\nPlease extend command classes" - " from setuptools instead of distutils.", - SetuptoolsDeprecationWarning - ) - return build_py.get_data_files() - - -def write_file(filename, contents): - """Create a file with the specified name and write 'contents' (a - sequence of strings without line terminators) to it. - """ - contents = "\n".join(contents) - - # assuming the contents has been vetted for utf-8 encoding - contents = contents.encode("utf-8") - - with open(filename, "wb") as f: # always write POSIX-style manifest - f.write(contents) - - -def write_pkg_info(cmd, basename, filename): - log.info("writing %s", filename) - if not cmd.dry_run: - metadata = cmd.distribution.metadata - metadata.version, oldver = cmd.egg_version, metadata.version - metadata.name, oldname = cmd.egg_name, metadata.name - - try: - # write unescaped data to PKG-INFO, so older pkg_resources - # can still parse it - metadata.write_pkg_info(cmd.egg_info) - finally: - metadata.name, metadata.version = oldname, oldver - - safe = getattr(cmd.distribution, 'zip_safe', None) - - bdist_egg.write_safety_flag(cmd.egg_info, safe) - - -def warn_depends_obsolete(cmd, basename, filename): - if os.path.exists(filename): - log.warn( - "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" - "Use the install_requires/extras_require setup() args instead." - ) - - -def _write_requirements(stream, reqs): - lines = yield_lines(reqs or ()) - - def append_cr(line): - return line + '\n' - lines = map(append_cr, sorted(lines)) - stream.writelines(lines) - - -def write_requirements(cmd, basename, filename): - dist = cmd.distribution - data = io.StringIO() - _write_requirements(data, dist.install_requires) - extras_require = dist.extras_require or {} - for extra in sorted(extras_require): - data.write('\n[{extra}]\n'.format(**vars())) - _write_requirements(data, extras_require[extra]) - cmd.write_or_delete_file("requirements", filename, data.getvalue()) - - -def write_setup_requirements(cmd, basename, filename): - data = io.StringIO() - _write_requirements(data, cmd.distribution.setup_requires) - cmd.write_or_delete_file("setup-requirements", filename, data.getvalue()) - - -def write_toplevel_names(cmd, basename, filename): - pkgs = dict.fromkeys( - [ - k.split('.', 1)[0] - for k in cmd.distribution.iter_distribution_names() - ] - ) - cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n') - - -def overwrite_arg(cmd, basename, filename): - write_arg(cmd, basename, filename, True) - - -def write_arg(cmd, basename, filename, force=False): - argname = os.path.splitext(basename)[0] - value = getattr(cmd.distribution, argname, None) - if value is not None: - value = '\n'.join(value) + '\n' - cmd.write_or_delete_file(argname, filename, value, force) - - -def write_entries(cmd, basename, filename): - eps = _entry_points.load(cmd.distribution.entry_points) - defn = _entry_points.render(eps) - cmd.write_or_delete_file('entry points', filename, defn, True) - - -def get_pkg_info_revision(): - """ - Get a -r### off of PKG-INFO Version in case this is an sdist of - a subversion revision. - """ - warnings.warn( - "get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning) - if os.path.exists('PKG-INFO'): - with io.open('PKG-INFO') as f: - for line in f: - match = re.match(r"Version:.*-r(\d+)\s*$", line) - if match: - return int(match.group(1)) - return 0 - - -class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning): - """Deprecated behavior warning for EggInfo, bypassing suppression.""" diff --git a/venv/lib/python3.11/site-packages/setuptools/command/install.py b/venv/lib/python3.11/site-packages/setuptools/command/install.py deleted file mode 100755 index 55fdb12..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/install.py +++ /dev/null @@ -1,139 +0,0 @@ -from distutils.errors import DistutilsArgError -import inspect -import glob -import warnings -import platform -import distutils.command.install as orig - -import setuptools - -# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for -# now. See https://github.com/pypa/setuptools/issues/199/ -_install = orig.install - - -class install(orig.install): - """Use easy_install to install the package, w/dependencies""" - - user_options = orig.install.user_options + [ - ('old-and-unmanageable', None, "Try not to use this!"), - ('single-version-externally-managed', None, - "used by system package builders to create 'flat' eggs"), - ] - boolean_options = orig.install.boolean_options + [ - 'old-and-unmanageable', 'single-version-externally-managed', - ] - new_commands = [ - ('install_egg_info', lambda self: True), - ('install_scripts', lambda self: True), - ] - _nc = dict(new_commands) - - def initialize_options(self): - - warnings.warn( - "setup.py install is deprecated. " - "Use build and pip and other standards-based tools.", - setuptools.SetuptoolsDeprecationWarning, - ) - - orig.install.initialize_options(self) - self.old_and_unmanageable = None - self.single_version_externally_managed = None - - def finalize_options(self): - orig.install.finalize_options(self) - if self.root: - self.single_version_externally_managed = True - elif self.single_version_externally_managed: - if not self.root and not self.record: - raise DistutilsArgError( - "You must specify --record or --root when building system" - " packages" - ) - - def handle_extra_path(self): - if self.root or self.single_version_externally_managed: - # explicit backward-compatibility mode, allow extra_path to work - return orig.install.handle_extra_path(self) - - # Ignore extra_path when installing an egg (or being run by another - # command without --root or --single-version-externally-managed - self.path_file = None - self.extra_dirs = '' - - def run(self): - # Explicit request for old-style install? Just do it - if self.old_and_unmanageable or self.single_version_externally_managed: - return orig.install.run(self) - - if not self._called_from_setup(inspect.currentframe()): - # Run in backward-compatibility mode to support bdist_* commands. - orig.install.run(self) - else: - self.do_egg_install() - - @staticmethod - def _called_from_setup(run_frame): - """ - Attempt to detect whether run() was called from setup() or by another - command. If called by setup(), the parent caller will be the - 'run_command' method in 'distutils.dist', and *its* caller will be - the 'run_commands' method. If called any other way, the - immediate caller *might* be 'run_command', but it won't have been - called by 'run_commands'. Return True in that case or if a call stack - is unavailable. Return False otherwise. - """ - if run_frame is None: - msg = "Call stack not available. bdist_* commands may fail." - warnings.warn(msg) - if platform.python_implementation() == 'IronPython': - msg = "For best results, pass -X:Frames to enable call stack." - warnings.warn(msg) - return True - - frames = inspect.getouterframes(run_frame) - for frame in frames[2:4]: - caller, = frame[:1] - info = inspect.getframeinfo(caller) - caller_module = caller.f_globals.get('__name__', '') - - if caller_module == "setuptools.dist" and info.function == "run_command": - # Starting from v61.0.0 setuptools overwrites dist.run_command - continue - - return ( - caller_module == 'distutils.dist' - and info.function == 'run_commands' - ) - - def do_egg_install(self): - - easy_install = self.distribution.get_command_class('easy_install') - - cmd = easy_install( - self.distribution, args="x", root=self.root, record=self.record, - ) - cmd.ensure_finalized() # finalize before bdist_egg munges install cmd - cmd.always_copy_from = '.' # make sure local-dir eggs get installed - - # pick up setup-dir .egg files only: no .egg-info - cmd.package_index.scan(glob.glob('*.egg')) - - self.run_command('bdist_egg') - args = [self.distribution.get_command_obj('bdist_egg').egg_output] - - if setuptools.bootstrap_install_from: - # Bootstrap self-installation of setuptools - args.insert(0, setuptools.bootstrap_install_from) - - cmd.args = args - cmd.run(show_deprecation=False) - setuptools.bootstrap_install_from = None - - -# XXX Python 3.1 doesn't see _nc if this is inside the class -install.sub_commands = ( - [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] + - install.new_commands -) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/install_egg_info.py b/venv/lib/python3.11/site-packages/setuptools/command/install_egg_info.py deleted file mode 100755 index 025f5b2..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/install_egg_info.py +++ /dev/null @@ -1,83 +0,0 @@ -from distutils import log, dir_util -import os, sys - -from setuptools import Command -from setuptools import namespaces -from setuptools.archive_util import unpack_archive -from .._path import ensure_directory -import pkg_resources - - -class install_egg_info(namespaces.Installer, Command): - """Install an .egg-info directory for the package""" - - description = "Install an .egg-info directory for the package" - - user_options = [ - ('install-dir=', 'd', "directory to install to"), - ] - - def initialize_options(self): - self.install_dir = None - self.install_layout = None - self.prefix_option = None - - def finalize_options(self): - self.set_undefined_options('install_lib', - ('install_dir', 'install_dir')) - self.set_undefined_options('install',('install_layout','install_layout')) - if sys.hexversion > 0x2060000: - self.set_undefined_options('install',('prefix_option','prefix_option')) - ei_cmd = self.get_finalized_command("egg_info") - basename = pkg_resources.Distribution( - None, None, ei_cmd.egg_name, ei_cmd.egg_version - ).egg_name() + '.egg-info' - - if self.install_layout: - if not self.install_layout.lower() in ['deb']: - raise DistutilsOptionError("unknown value for --install-layout") - self.install_layout = self.install_layout.lower() - basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') - elif self.prefix_option or 'real_prefix' in sys.__dict__: - # don't modify for virtualenv - pass - else: - basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') - - self.source = ei_cmd.egg_info - self.target = os.path.join(self.install_dir, basename) - self.outputs = [] - - def run(self): - self.run_command('egg_info') - if os.path.isdir(self.target) and not os.path.islink(self.target): - dir_util.remove_tree(self.target, dry_run=self.dry_run) - elif os.path.exists(self.target): - self.execute(os.unlink, (self.target,), "Removing " + self.target) - if not self.dry_run: - ensure_directory(self.target) - self.execute( - self.copytree, (), "Copying %s to %s" % (self.source, self.target) - ) - self.install_namespaces() - - def get_outputs(self): - return self.outputs - - def copytree(self): - # Copy the .egg-info tree to site-packages - def skimmer(src, dst): - # filter out source-control directories; note that 'src' is always - # a '/'-separated path, regardless of platform. 'dst' is a - # platform-specific path. - for skip in '.svn/', 'CVS/': - if src.startswith(skip) or '/' + skip in src: - return None - if self.install_layout and self.install_layout in ['deb'] and src.startswith('SOURCES.txt'): - log.info("Skipping SOURCES.txt") - return None - self.outputs.append(dst) - log.debug("Copying %s to %s", src, dst) - return dst - - unpack_archive(self.source, self.target, skimmer) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/install_lib.py b/venv/lib/python3.11/site-packages/setuptools/command/install_lib.py deleted file mode 100755 index 65e318e..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/install_lib.py +++ /dev/null @@ -1,148 +0,0 @@ -import os -import sys -from itertools import product, starmap -import distutils.command.install_lib as orig - - -class install_lib(orig.install_lib): - """Don't add compiled flags to filenames of non-Python files""" - - def initialize_options(self): - orig.install_lib.initialize_options(self) - self.multiarch = None - self.install_layout = None - - def finalize_options(self): - orig.install_lib.finalize_options(self) - self.set_undefined_options('install',('install_layout','install_layout')) - if self.install_layout == 'deb' and sys.version_info[:2] >= (3, 3): - import sysconfig - self.multiarch = sysconfig.get_config_var('MULTIARCH') - - def run(self): - self.build() - outfiles = self.install() - if outfiles is not None: - # always compile, in case we have any extension stubs to deal with - self.byte_compile(outfiles) - - def get_exclusions(self): - """ - Return a collections.Sized collections.Container of paths to be - excluded for single_version_externally_managed installations. - """ - all_packages = ( - pkg - for ns_pkg in self._get_SVEM_NSPs() - for pkg in self._all_packages(ns_pkg) - ) - - excl_specs = product(all_packages, self._gen_exclusion_paths()) - return set(starmap(self._exclude_pkg_path, excl_specs)) - - def _exclude_pkg_path(self, pkg, exclusion_path): - """ - Given a package name and exclusion path within that package, - compute the full exclusion path. - """ - parts = pkg.split('.') + [exclusion_path] - return os.path.join(self.install_dir, *parts) - - @staticmethod - def _all_packages(pkg_name): - """ - >>> list(install_lib._all_packages('foo.bar.baz')) - ['foo.bar.baz', 'foo.bar', 'foo'] - """ - while pkg_name: - yield pkg_name - pkg_name, sep, child = pkg_name.rpartition('.') - - def _get_SVEM_NSPs(self): - """ - Get namespace packages (list) but only for - single_version_externally_managed installations and empty otherwise. - """ - # TODO: is it necessary to short-circuit here? i.e. what's the cost - # if get_finalized_command is called even when namespace_packages is - # False? - if not self.distribution.namespace_packages: - return [] - - install_cmd = self.get_finalized_command('install') - svem = install_cmd.single_version_externally_managed - - return self.distribution.namespace_packages if svem else [] - - @staticmethod - def _gen_exclusion_paths(): - """ - Generate file paths to be excluded for namespace packages (bytecode - cache files). - """ - # always exclude the package module itself - yield '__init__.py' - - yield '__init__.pyc' - yield '__init__.pyo' - - if not hasattr(sys, 'implementation'): - return - - base = os.path.join( - '__pycache__', '__init__.' + sys.implementation.cache_tag) - yield base + '.pyc' - yield base + '.pyo' - yield base + '.opt-1.pyc' - yield base + '.opt-2.pyc' - - def copy_tree( - self, infile, outfile, - preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 - ): - assert preserve_mode and preserve_times and not preserve_symlinks - exclude = self.get_exclusions() - - if not exclude: - import distutils.dir_util - distutils.dir_util._multiarch = self.multiarch - return orig.install_lib.copy_tree(self, infile, outfile) - - # Exclude namespace package __init__.py* files from the output - - from setuptools.archive_util import unpack_directory - from distutils import log - - outfiles = [] - - if self.multiarch: - import sysconfig - ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX') - if ext_suffix.endswith(self.multiarch + ext_suffix[-3:]): - new_suffix = None - else: - new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:]) - - def pf(src, dst): - if dst in exclude: - log.warn("Skipping installation of %s (namespace package)", - dst) - return False - - if self.multiarch and new_suffix and dst.endswith(ext_suffix) and not dst.endswith(new_suffix): - dst = dst.replace(ext_suffix, new_suffix) - log.info("renaming extension to %s", os.path.basename(dst)) - - log.info("copying %s -> %s", src, os.path.dirname(dst)) - outfiles.append(dst) - return dst - - unpack_directory(infile, outfile, pf) - return outfiles - - def get_outputs(self): - outputs = orig.install_lib.get_outputs(self) - exclude = self.get_exclusions() - if exclude: - return [f for f in outputs if f not in exclude] - return outputs diff --git a/venv/lib/python3.11/site-packages/setuptools/command/install_scripts.py b/venv/lib/python3.11/site-packages/setuptools/command/install_scripts.py deleted file mode 100755 index aeb0e42..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/install_scripts.py +++ /dev/null @@ -1,70 +0,0 @@ -from distutils import log -import distutils.command.install_scripts as orig -from distutils.errors import DistutilsModuleError -import os -import sys - -from pkg_resources import Distribution, PathMetadata -from .._path import ensure_directory - - -class install_scripts(orig.install_scripts): - """Do normal script install, plus any egg_info wrapper scripts""" - - def initialize_options(self): - orig.install_scripts.initialize_options(self) - self.no_ep = False - - def run(self): - import setuptools.command.easy_install as ei - - self.run_command("egg_info") - if self.distribution.scripts: - orig.install_scripts.run(self) # run first to set up self.outfiles - else: - self.outfiles = [] - if self.no_ep: - # don't install entry point scripts into .egg file! - return - - ei_cmd = self.get_finalized_command("egg_info") - dist = Distribution( - ei_cmd.egg_base, PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), - ei_cmd.egg_name, ei_cmd.egg_version, - ) - bs_cmd = self.get_finalized_command('build_scripts') - exec_param = getattr(bs_cmd, 'executable', None) - try: - bw_cmd = self.get_finalized_command("bdist_wininst") - is_wininst = getattr(bw_cmd, '_is_running', False) - except (ImportError, DistutilsModuleError): - is_wininst = False - writer = ei.ScriptWriter - if is_wininst: - exec_param = "python.exe" - writer = ei.WindowsScriptWriter - if exec_param == sys.executable: - # In case the path to the Python executable contains a space, wrap - # it so it's not split up. - exec_param = [exec_param] - # resolve the writer to the environment - writer = writer.best() - cmd = writer.command_spec_class.best().from_param(exec_param) - for args in writer.get_args(dist, cmd.as_header()): - self.write_script(*args) - - def write_script(self, script_name, contents, mode="t", *ignored): - """Write an executable file to the scripts directory""" - from setuptools.command.easy_install import chmod, current_umask - - log.info("Installing %s script to %s", script_name, self.install_dir) - target = os.path.join(self.install_dir, script_name) - self.outfiles.append(target) - - mask = current_umask() - if not self.dry_run: - ensure_directory(target) - f = open(target, "w" + mode) - f.write(contents) - f.close() - chmod(target, 0o777 - mask) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/launcher manifest.xml b/venv/lib/python3.11/site-packages/setuptools/command/launcher manifest.xml deleted file mode 100755 index 5972a96..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/launcher manifest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - diff --git a/venv/lib/python3.11/site-packages/setuptools/command/py36compat.py b/venv/lib/python3.11/site-packages/setuptools/command/py36compat.py deleted file mode 100755 index 343547a..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/py36compat.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -from glob import glob -from distutils.util import convert_path -from distutils.command import sdist - - -class sdist_add_defaults: - """ - Mix-in providing forward-compatibility for functionality as found in - distutils on Python 3.7. - - Do not edit the code in this class except to update functionality - as implemented in distutils. Instead, override in the subclass. - """ - - def add_defaults(self): - """Add all the default files to self.filelist: - - README or README.txt - - setup.py - - test/test*.py - - all pure Python modules mentioned in setup script - - all files pointed by package_data (build_py) - - all files defined in data_files. - - all files defined as scripts. - - all C sources listed as part of extensions or C libraries - in the setup script (doesn't catch C headers!) - Warns if (README or README.txt) or setup.py are missing; everything - else is optional. - """ - self._add_defaults_standards() - self._add_defaults_optional() - self._add_defaults_python() - self._add_defaults_data_files() - self._add_defaults_ext() - self._add_defaults_c_libs() - self._add_defaults_scripts() - - @staticmethod - def _cs_path_exists(fspath): - """ - Case-sensitive path existence check - - >>> sdist_add_defaults._cs_path_exists(__file__) - True - >>> sdist_add_defaults._cs_path_exists(__file__.upper()) - False - """ - if not os.path.exists(fspath): - return False - # make absolute so we always have a directory - abspath = os.path.abspath(fspath) - directory, filename = os.path.split(abspath) - return filename in os.listdir(directory) - - def _add_defaults_standards(self): - standards = [self.READMES, self.distribution.script_name] - for fn in standards: - if isinstance(fn, tuple): - alts = fn - got_it = False - for fn in alts: - if self._cs_path_exists(fn): - got_it = True - self.filelist.append(fn) - break - - if not got_it: - self.warn("standard file not found: should have one of " + - ', '.join(alts)) - else: - if self._cs_path_exists(fn): - self.filelist.append(fn) - else: - self.warn("standard file '%s' not found" % fn) - - def _add_defaults_optional(self): - optional = ['test/test*.py', 'setup.cfg'] - for pattern in optional: - files = filter(os.path.isfile, glob(pattern)) - self.filelist.extend(files) - - def _add_defaults_python(self): - # build_py is used to get: - # - python modules - # - files defined in package_data - build_py = self.get_finalized_command('build_py') - - # getting python files - if self.distribution.has_pure_modules(): - self.filelist.extend(build_py.get_source_files()) - - # getting package_data files - # (computed in build_py.data_files by build_py.finalize_options) - for pkg, src_dir, build_dir, filenames in build_py.data_files: - for filename in filenames: - self.filelist.append(os.path.join(src_dir, filename)) - - def _add_defaults_data_files(self): - # getting distribution.data_files - if self.distribution.has_data_files(): - for item in self.distribution.data_files: - if isinstance(item, str): - # plain file - item = convert_path(item) - if os.path.isfile(item): - self.filelist.append(item) - else: - # a (dirname, filenames) tuple - dirname, filenames = item - for f in filenames: - f = convert_path(f) - if os.path.isfile(f): - self.filelist.append(f) - - def _add_defaults_ext(self): - if self.distribution.has_ext_modules(): - build_ext = self.get_finalized_command('build_ext') - self.filelist.extend(build_ext.get_source_files()) - - def _add_defaults_c_libs(self): - if self.distribution.has_c_libraries(): - build_clib = self.get_finalized_command('build_clib') - self.filelist.extend(build_clib.get_source_files()) - - def _add_defaults_scripts(self): - if self.distribution.has_scripts(): - build_scripts = self.get_finalized_command('build_scripts') - self.filelist.extend(build_scripts.get_source_files()) - - -if hasattr(sdist.sdist, '_add_defaults_standards'): - # disable the functionality already available upstream - class sdist_add_defaults: # noqa - pass diff --git a/venv/lib/python3.11/site-packages/setuptools/command/register.py b/venv/lib/python3.11/site-packages/setuptools/command/register.py deleted file mode 100755 index b8266b9..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/register.py +++ /dev/null @@ -1,18 +0,0 @@ -from distutils import log -import distutils.command.register as orig - -from setuptools.errors import RemovedCommandError - - -class register(orig.register): - """Formerly used to register packages on PyPI.""" - - def run(self): - msg = ( - "The register command has been removed, use twine to upload " - + "instead (https://pypi.org/p/twine)" - ) - - self.announce("ERROR: " + msg, log.ERROR) - - raise RemovedCommandError(msg) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/rotate.py b/venv/lib/python3.11/site-packages/setuptools/command/rotate.py deleted file mode 100755 index 74795ba..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/rotate.py +++ /dev/null @@ -1,64 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsOptionError -import os -import shutil - -from setuptools import Command - - -class rotate(Command): - """Delete older distributions""" - - description = "delete older distributions, keeping N newest files" - user_options = [ - ('match=', 'm', "patterns to match (required)"), - ('dist-dir=', 'd', "directory where the distributions are"), - ('keep=', 'k', "number of matching distributions to keep"), - ] - - boolean_options = [] - - def initialize_options(self): - self.match = None - self.dist_dir = None - self.keep = None - - def finalize_options(self): - if self.match is None: - raise DistutilsOptionError( - "Must specify one or more (comma-separated) match patterns " - "(e.g. '.zip' or '.egg')" - ) - if self.keep is None: - raise DistutilsOptionError("Must specify number of files to keep") - try: - self.keep = int(self.keep) - except ValueError as e: - raise DistutilsOptionError("--keep must be an integer") from e - if isinstance(self.match, str): - self.match = [ - convert_path(p.strip()) for p in self.match.split(',') - ] - self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) - - def run(self): - self.run_command("egg_info") - from glob import glob - - for pattern in self.match: - pattern = self.distribution.get_name() + '*' + pattern - files = glob(os.path.join(self.dist_dir, pattern)) - files = [(os.path.getmtime(f), f) for f in files] - files.sort() - files.reverse() - - log.info("%d file(s) matching %s", len(files), pattern) - files = files[self.keep:] - for (t, f) in files: - log.info("Deleting %s", f) - if not self.dry_run: - if os.path.isdir(f): - shutil.rmtree(f) - else: - os.unlink(f) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/saveopts.py b/venv/lib/python3.11/site-packages/setuptools/command/saveopts.py deleted file mode 100755 index 611cec5..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/saveopts.py +++ /dev/null @@ -1,22 +0,0 @@ -from setuptools.command.setopt import edit_config, option_base - - -class saveopts(option_base): - """Save command-line options to a file""" - - description = "save supplied options to setup.cfg or other config file" - - def run(self): - dist = self.distribution - settings = {} - - for cmd in dist.command_options: - - if cmd == 'saveopts': - continue # don't save our own options! - - for opt, (src, val) in dist.get_option_dict(cmd).items(): - if src == "command line": - settings.setdefault(cmd, {})[opt] = val - - edit_config(self.filename, settings, self.dry_run) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/sdist.py b/venv/lib/python3.11/site-packages/setuptools/command/sdist.py deleted file mode 100755 index 4a8cde7..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/sdist.py +++ /dev/null @@ -1,210 +0,0 @@ -from distutils import log -import distutils.command.sdist as orig -import os -import sys -import io -import contextlib -from itertools import chain - -from .py36compat import sdist_add_defaults - -from .._importlib import metadata -from .build import _ORIGINAL_SUBCOMMANDS - -_default_revctrl = list - - -def walk_revctrl(dirname=''): - """Find all files under revision control""" - for ep in metadata.entry_points(group='setuptools.file_finders'): - for item in ep.load()(dirname): - yield item - - -class sdist(sdist_add_defaults, orig.sdist): - """Smart sdist that finds anything supported by revision control""" - - user_options = [ - ('formats=', None, - "formats for source distribution (comma-separated list)"), - ('keep-temp', 'k', - "keep the distribution tree around after creating " + - "archive file(s)"), - ('dist-dir=', 'd', - "directory to put the source distribution archive(s) in " - "[default: dist]"), - ('owner=', 'u', - "Owner name used when creating a tar file [default: current user]"), - ('group=', 'g', - "Group name used when creating a tar file [default: current group]"), - ] - - negative_opt = {} - - README_EXTENSIONS = ['', '.rst', '.txt', '.md'] - READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS) - - def run(self): - self.run_command('egg_info') - ei_cmd = self.get_finalized_command('egg_info') - self.filelist = ei_cmd.filelist - self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt')) - self.check_readme() - - # Run sub commands - for cmd_name in self.get_sub_commands(): - self.run_command(cmd_name) - - self.make_distribution() - - dist_files = getattr(self.distribution, 'dist_files', []) - for file in self.archive_files: - data = ('sdist', '', file) - if data not in dist_files: - dist_files.append(data) - - def initialize_options(self): - orig.sdist.initialize_options(self) - - self._default_to_gztar() - - def _default_to_gztar(self): - # only needed on Python prior to 3.6. - if sys.version_info >= (3, 6, 0, 'beta', 1): - return - self.formats = ['gztar'] - - def make_distribution(self): - """ - Workaround for #516 - """ - with self._remove_os_link(): - orig.sdist.make_distribution(self) - - @staticmethod - @contextlib.contextmanager - def _remove_os_link(): - """ - In a context, remove and restore os.link if it exists - """ - - class NoValue: - pass - - orig_val = getattr(os, 'link', NoValue) - try: - del os.link - except Exception: - pass - try: - yield - finally: - if orig_val is not NoValue: - setattr(os, 'link', orig_val) - - def add_defaults(self): - super().add_defaults() - self._add_defaults_build_sub_commands() - - def _add_defaults_optional(self): - super()._add_defaults_optional() - if os.path.isfile('pyproject.toml'): - self.filelist.append('pyproject.toml') - - def _add_defaults_python(self): - """getting python files""" - if self.distribution.has_pure_modules(): - build_py = self.get_finalized_command('build_py') - self.filelist.extend(build_py.get_source_files()) - self._add_data_files(self._safe_data_files(build_py)) - - def _add_defaults_build_sub_commands(self): - build = self.get_finalized_command("build") - missing_cmds = set(build.get_sub_commands()) - _ORIGINAL_SUBCOMMANDS - # ^-- the original built-in sub-commands are already handled by default. - cmds = (self.get_finalized_command(c) for c in missing_cmds) - files = (c.get_source_files() for c in cmds if hasattr(c, "get_source_files")) - self.filelist.extend(chain.from_iterable(files)) - - def _safe_data_files(self, build_py): - """ - Since the ``sdist`` class is also used to compute the MANIFEST - (via :obj:`setuptools.command.egg_info.manifest_maker`), - there might be recursion problems when trying to obtain the list of - data_files and ``include_package_data=True`` (which in turn depends on - the files included in the MANIFEST). - - To avoid that, ``manifest_maker`` should be able to overwrite this - method and avoid recursive attempts to build/analyze the MANIFEST. - """ - return build_py.data_files - - def _add_data_files(self, data_files): - """ - Add data files as found in build_py.data_files. - """ - self.filelist.extend( - os.path.join(src_dir, name) - for _, src_dir, _, filenames in data_files - for name in filenames - ) - - def _add_defaults_data_files(self): - try: - super()._add_defaults_data_files() - except TypeError: - log.warn("data_files contains unexpected objects") - - def check_readme(self): - for f in self.READMES: - if os.path.exists(f): - return - else: - self.warn( - "standard file not found: should have one of " + - ', '.join(self.READMES) - ) - - def make_release_tree(self, base_dir, files): - orig.sdist.make_release_tree(self, base_dir, files) - - # Save any egg_info command line options used to create this sdist - dest = os.path.join(base_dir, 'setup.cfg') - if hasattr(os, 'link') and os.path.exists(dest): - # unlink and re-copy, since it might be hard-linked, and - # we don't want to change the source version - os.unlink(dest) - self.copy_file('setup.cfg', dest) - - self.get_finalized_command('egg_info').save_version_info(dest) - - def _manifest_is_not_generated(self): - # check for special comment used in 2.7.1 and higher - if not os.path.isfile(self.manifest): - return False - - with io.open(self.manifest, 'rb') as fp: - first_line = fp.readline() - return (first_line != - '# file GENERATED by distutils, do NOT edit\n'.encode()) - - def read_manifest(self): - """Read the manifest file (named by 'self.manifest') and use it to - fill in 'self.filelist', the list of files to include in the source - distribution. - """ - log.info("reading manifest file '%s'", self.manifest) - manifest = open(self.manifest, 'rb') - for line in manifest: - # The manifest must contain UTF-8. See #303. - try: - line = line.decode('UTF-8') - except UnicodeDecodeError: - log.warn("%r not UTF-8 decodable -- skipping" % line) - continue - # ignore comments and blank lines - line = line.strip() - if line.startswith('#') or not line: - continue - self.filelist.append(line) - manifest.close() diff --git a/venv/lib/python3.11/site-packages/setuptools/command/setopt.py b/venv/lib/python3.11/site-packages/setuptools/command/setopt.py deleted file mode 100755 index 6358c04..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/setopt.py +++ /dev/null @@ -1,149 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsOptionError -import distutils -import os -import configparser - -from setuptools import Command - -__all__ = ['config_file', 'edit_config', 'option_base', 'setopt'] - - -def config_file(kind="local"): - """Get the filename of the distutils, local, global, or per-user config - - `kind` must be one of "local", "global", or "user" - """ - if kind == 'local': - return 'setup.cfg' - if kind == 'global': - return os.path.join( - os.path.dirname(distutils.__file__), 'distutils.cfg' - ) - if kind == 'user': - dot = os.name == 'posix' and '.' or '' - return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot)) - raise ValueError( - "config_file() type must be 'local', 'global', or 'user'", kind - ) - - -def edit_config(filename, settings, dry_run=False): - """Edit a configuration file to include `settings` - - `settings` is a dictionary of dictionaries or ``None`` values, keyed by - command/section name. A ``None`` value means to delete the entire section, - while a dictionary lists settings to be changed or deleted in that section. - A setting of ``None`` means to delete that setting. - """ - log.debug("Reading configuration from %s", filename) - opts = configparser.RawConfigParser() - opts.optionxform = lambda x: x - opts.read([filename]) - for section, options in settings.items(): - if options is None: - log.info("Deleting section [%s] from %s", section, filename) - opts.remove_section(section) - else: - if not opts.has_section(section): - log.debug("Adding new section [%s] to %s", section, filename) - opts.add_section(section) - for option, value in options.items(): - if value is None: - log.debug( - "Deleting %s.%s from %s", - section, option, filename - ) - opts.remove_option(section, option) - if not opts.options(section): - log.info("Deleting empty [%s] section from %s", - section, filename) - opts.remove_section(section) - else: - log.debug( - "Setting %s.%s to %r in %s", - section, option, value, filename - ) - opts.set(section, option, value) - - log.info("Writing %s", filename) - if not dry_run: - with open(filename, 'w') as f: - opts.write(f) - - -class option_base(Command): - """Abstract base class for commands that mess with config files""" - - user_options = [ - ('global-config', 'g', - "save options to the site-wide distutils.cfg file"), - ('user-config', 'u', - "save options to the current user's pydistutils.cfg file"), - ('filename=', 'f', - "configuration file to use (default=setup.cfg)"), - ] - - boolean_options = [ - 'global-config', 'user-config', - ] - - def initialize_options(self): - self.global_config = None - self.user_config = None - self.filename = None - - def finalize_options(self): - filenames = [] - if self.global_config: - filenames.append(config_file('global')) - if self.user_config: - filenames.append(config_file('user')) - if self.filename is not None: - filenames.append(self.filename) - if not filenames: - filenames.append(config_file('local')) - if len(filenames) > 1: - raise DistutilsOptionError( - "Must specify only one configuration file option", - filenames - ) - self.filename, = filenames - - -class setopt(option_base): - """Save command-line options to a file""" - - description = "set an option in setup.cfg or another config file" - - user_options = [ - ('command=', 'c', 'command to set an option for'), - ('option=', 'o', 'option to set'), - ('set-value=', 's', 'value of the option'), - ('remove', 'r', 'remove (unset) the value'), - ] + option_base.user_options - - boolean_options = option_base.boolean_options + ['remove'] - - def initialize_options(self): - option_base.initialize_options(self) - self.command = None - self.option = None - self.set_value = None - self.remove = None - - def finalize_options(self): - option_base.finalize_options(self) - if self.command is None or self.option is None: - raise DistutilsOptionError("Must specify --command *and* --option") - if self.set_value is None and not self.remove: - raise DistutilsOptionError("Must specify --set-value or --remove") - - def run(self): - edit_config( - self.filename, { - self.command: {self.option.replace('-', '_'): self.set_value} - }, - self.dry_run - ) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/test.py b/venv/lib/python3.11/site-packages/setuptools/command/test.py deleted file mode 100755 index 8dde513..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/test.py +++ /dev/null @@ -1,251 +0,0 @@ -import os -import operator -import sys -import contextlib -import itertools -import unittest -from distutils.errors import DistutilsError, DistutilsOptionError -from distutils import log -from unittest import TestLoader - -from pkg_resources import ( - resource_listdir, - resource_exists, - normalize_path, - working_set, - evaluate_marker, - add_activation_listener, - require, -) -from .._importlib import metadata -from setuptools import Command -from setuptools.extern.more_itertools import unique_everseen -from setuptools.extern.jaraco.functools import pass_none - - -class ScanningLoader(TestLoader): - def __init__(self): - TestLoader.__init__(self) - self._visited = set() - - def loadTestsFromModule(self, module, pattern=None): - """Return a suite of all tests cases contained in the given module - - If the module is a package, load tests from all the modules in it. - If the module has an ``additional_tests`` function, call it and add - the return value to the tests. - """ - if module in self._visited: - return None - self._visited.add(module) - - tests = [] - tests.append(TestLoader.loadTestsFromModule(self, module)) - - if hasattr(module, "additional_tests"): - tests.append(module.additional_tests()) - - if hasattr(module, '__path__'): - for file in resource_listdir(module.__name__, ''): - if file.endswith('.py') and file != '__init__.py': - submodule = module.__name__ + '.' + file[:-3] - else: - if resource_exists(module.__name__, file + '/__init__.py'): - submodule = module.__name__ + '.' + file - else: - continue - tests.append(self.loadTestsFromName(submodule)) - - if len(tests) != 1: - return self.suiteClass(tests) - else: - return tests[0] # don't create a nested suite for only one return - - -# adapted from jaraco.classes.properties:NonDataProperty -class NonDataProperty: - def __init__(self, fget): - self.fget = fget - - def __get__(self, obj, objtype=None): - if obj is None: - return self - return self.fget(obj) - - -class test(Command): - """Command to run unit tests after in-place build""" - - description = "run unit tests after in-place build (deprecated)" - - user_options = [ - ('test-module=', 'm', "Run 'test_suite' in specified module"), - ( - 'test-suite=', - 's', - "Run single test, case or suite (e.g. 'module.test_suite')", - ), - ('test-runner=', 'r', "Test runner to use"), - ] - - def initialize_options(self): - self.test_suite = None - self.test_module = None - self.test_loader = None - self.test_runner = None - - def finalize_options(self): - - if self.test_suite and self.test_module: - msg = "You may specify a module or a suite, but not both" - raise DistutilsOptionError(msg) - - if self.test_suite is None: - if self.test_module is None: - self.test_suite = self.distribution.test_suite - else: - self.test_suite = self.test_module + ".test_suite" - - if self.test_loader is None: - self.test_loader = getattr(self.distribution, 'test_loader', None) - if self.test_loader is None: - self.test_loader = "setuptools.command.test:ScanningLoader" - if self.test_runner is None: - self.test_runner = getattr(self.distribution, 'test_runner', None) - - @NonDataProperty - def test_args(self): - return list(self._test_args()) - - def _test_args(self): - if not self.test_suite: - yield 'discover' - if self.verbose: - yield '--verbose' - if self.test_suite: - yield self.test_suite - - def with_project_on_sys_path(self, func): - """ - Backward compatibility for project_on_sys_path context. - """ - with self.project_on_sys_path(): - func() - - @contextlib.contextmanager - def project_on_sys_path(self, include_dists=[]): - self.run_command('egg_info') - - # Build extensions in-place - self.reinitialize_command('build_ext', inplace=1) - self.run_command('build_ext') - - ei_cmd = self.get_finalized_command("egg_info") - - old_path = sys.path[:] - old_modules = sys.modules.copy() - - try: - project_path = normalize_path(ei_cmd.egg_base) - sys.path.insert(0, project_path) - working_set.__init__() - add_activation_listener(lambda dist: dist.activate()) - require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) - with self.paths_on_pythonpath([project_path]): - yield - finally: - sys.path[:] = old_path - sys.modules.clear() - sys.modules.update(old_modules) - working_set.__init__() - - @staticmethod - @contextlib.contextmanager - def paths_on_pythonpath(paths): - """ - Add the indicated paths to the head of the PYTHONPATH environment - variable so that subprocesses will also see the packages at - these paths. - - Do this in a context that restores the value on exit. - """ - nothing = object() - orig_pythonpath = os.environ.get('PYTHONPATH', nothing) - current_pythonpath = os.environ.get('PYTHONPATH', '') - try: - prefix = os.pathsep.join(unique_everseen(paths)) - to_join = filter(None, [prefix, current_pythonpath]) - new_path = os.pathsep.join(to_join) - if new_path: - os.environ['PYTHONPATH'] = new_path - yield - finally: - if orig_pythonpath is nothing: - os.environ.pop('PYTHONPATH', None) - else: - os.environ['PYTHONPATH'] = orig_pythonpath - - @staticmethod - def install_dists(dist): - """ - Install the requirements indicated by self.distribution and - return an iterable of the dists that were built. - """ - ir_d = dist.fetch_build_eggs(dist.install_requires) - tr_d = dist.fetch_build_eggs(dist.tests_require or []) - er_d = dist.fetch_build_eggs( - v - for k, v in dist.extras_require.items() - if k.startswith(':') and evaluate_marker(k[1:]) - ) - return itertools.chain(ir_d, tr_d, er_d) - - def run(self): - self.announce( - "WARNING: Testing via this command is deprecated and will be " - "removed in a future version. Users looking for a generic test " - "entry point independent of test runner are encouraged to use " - "tox.", - log.WARN, - ) - - installed_dists = self.install_dists(self.distribution) - - cmd = ' '.join(self._argv) - if self.dry_run: - self.announce('skipping "%s" (dry run)' % cmd) - return - - self.announce('running "%s"' % cmd) - - paths = map(operator.attrgetter('location'), installed_dists) - with self.paths_on_pythonpath(paths): - with self.project_on_sys_path(): - self.run_tests() - - def run_tests(self): - test = unittest.main( - None, - None, - self._argv, - testLoader=self._resolve_as_ep(self.test_loader), - testRunner=self._resolve_as_ep(self.test_runner), - exit=False, - ) - if not test.result.wasSuccessful(): - msg = 'Test failed: %s' % test.result - self.announce(msg, log.ERROR) - raise DistutilsError(msg) - - @property - def _argv(self): - return ['unittest'] + self.test_args - - @staticmethod - @pass_none - def _resolve_as_ep(val): - """ - Load the indicated attribute value, called, as a as if it were - specified as an entry point. - """ - return metadata.EntryPoint(value=val, name=None, group=None).load()() diff --git a/venv/lib/python3.11/site-packages/setuptools/command/upload.py b/venv/lib/python3.11/site-packages/setuptools/command/upload.py deleted file mode 100755 index ec7f81e..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/upload.py +++ /dev/null @@ -1,17 +0,0 @@ -from distutils import log -from distutils.command import upload as orig - -from setuptools.errors import RemovedCommandError - - -class upload(orig.upload): - """Formerly used to upload packages to PyPI.""" - - def run(self): - msg = ( - "The upload command has been removed, use twine to upload " - + "instead (https://pypi.org/p/twine)" - ) - - self.announce("ERROR: " + msg, log.ERROR) - raise RemovedCommandError(msg) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/upload_docs.py b/venv/lib/python3.11/site-packages/setuptools/command/upload_docs.py deleted file mode 100755 index 63eb28c..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/upload_docs.py +++ /dev/null @@ -1,212 +0,0 @@ -"""upload_docs - -Implements a Distutils 'upload_docs' subcommand (upload documentation to -sites other than PyPi such as devpi). -""" - -from base64 import standard_b64encode -from distutils import log -from distutils.errors import DistutilsOptionError -import os -import socket -import zipfile -import tempfile -import shutil -import itertools -import functools -import http.client -import urllib.parse -import warnings - -from .._importlib import metadata -from .. import SetuptoolsDeprecationWarning - -from .upload import upload - - -def _encode(s): - return s.encode('utf-8', 'surrogateescape') - - -class upload_docs(upload): - # override the default repository as upload_docs isn't - # supported by Warehouse (and won't be). - DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi/' - - description = 'Upload documentation to sites other than PyPi such as devpi' - - user_options = [ - ('repository=', 'r', - "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), - ('show-response', None, - 'display full response text from server'), - ('upload-dir=', None, 'directory to upload'), - ] - boolean_options = upload.boolean_options - - def has_sphinx(self): - return bool( - self.upload_dir is None - and metadata.entry_points(group='distutils.commands', name='build_sphinx') - ) - - sub_commands = [('build_sphinx', has_sphinx)] - - def initialize_options(self): - upload.initialize_options(self) - self.upload_dir = None - self.target_dir = None - - def finalize_options(self): - log.warn( - "Upload_docs command is deprecated. Use Read the Docs " - "(https://readthedocs.org) instead.") - upload.finalize_options(self) - if self.upload_dir is None: - if self.has_sphinx(): - build_sphinx = self.get_finalized_command('build_sphinx') - self.target_dir = dict(build_sphinx.builder_target_dirs)['html'] - else: - build = self.get_finalized_command('build') - self.target_dir = os.path.join(build.build_base, 'docs') - else: - self.ensure_dirname('upload_dir') - self.target_dir = self.upload_dir - self.announce('Using upload directory %s' % self.target_dir) - - def create_zipfile(self, filename): - zip_file = zipfile.ZipFile(filename, "w") - try: - self.mkpath(self.target_dir) # just in case - for root, dirs, files in os.walk(self.target_dir): - if root == self.target_dir and not files: - tmpl = "no files found in upload directory '%s'" - raise DistutilsOptionError(tmpl % self.target_dir) - for name in files: - full = os.path.join(root, name) - relative = root[len(self.target_dir):].lstrip(os.path.sep) - dest = os.path.join(relative, name) - zip_file.write(full, dest) - finally: - zip_file.close() - - def run(self): - warnings.warn( - "upload_docs is deprecated and will be removed in a future " - "version. Use tools like httpie or curl instead.", - SetuptoolsDeprecationWarning, - ) - - # Run sub commands - for cmd_name in self.get_sub_commands(): - self.run_command(cmd_name) - - tmp_dir = tempfile.mkdtemp() - name = self.distribution.metadata.get_name() - zip_file = os.path.join(tmp_dir, "%s.zip" % name) - try: - self.create_zipfile(zip_file) - self.upload_file(zip_file) - finally: - shutil.rmtree(tmp_dir) - - @staticmethod - def _build_part(item, sep_boundary): - key, values = item - title = '\nContent-Disposition: form-data; name="%s"' % key - # handle multiple entries for the same name - if not isinstance(values, list): - values = [values] - for value in values: - if isinstance(value, tuple): - title += '; filename="%s"' % value[0] - value = value[1] - else: - value = _encode(value) - yield sep_boundary - yield _encode(title) - yield b"\n\n" - yield value - if value and value[-1:] == b'\r': - yield b'\n' # write an extra newline (lurve Macs) - - @classmethod - def _build_multipart(cls, data): - """ - Build up the MIME payload for the POST data - """ - boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' - sep_boundary = b'\n--' + boundary.encode('ascii') - end_boundary = sep_boundary + b'--' - end_items = end_boundary, b"\n", - builder = functools.partial( - cls._build_part, - sep_boundary=sep_boundary, - ) - part_groups = map(builder, data.items()) - parts = itertools.chain.from_iterable(part_groups) - body_items = itertools.chain(parts, end_items) - content_type = 'multipart/form-data; boundary=%s' % boundary - return b''.join(body_items), content_type - - def upload_file(self, filename): - with open(filename, 'rb') as f: - content = f.read() - meta = self.distribution.metadata - data = { - ':action': 'doc_upload', - 'name': meta.get_name(), - 'content': (os.path.basename(filename), content), - } - # set up the authentication - credentials = _encode(self.username + ':' + self.password) - credentials = standard_b64encode(credentials).decode('ascii') - auth = "Basic " + credentials - - body, ct = self._build_multipart(data) - - msg = "Submitting documentation to %s" % (self.repository) - self.announce(msg, log.INFO) - - # build the Request - # We can't use urllib2 since we need to send the Basic - # auth right with the first request - schema, netloc, url, params, query, fragments = \ - urllib.parse.urlparse(self.repository) - assert not params and not query and not fragments - if schema == 'http': - conn = http.client.HTTPConnection(netloc) - elif schema == 'https': - conn = http.client.HTTPSConnection(netloc) - else: - raise AssertionError("unsupported schema " + schema) - - data = '' - try: - conn.connect() - conn.putrequest("POST", url) - content_type = ct - conn.putheader('Content-type', content_type) - conn.putheader('Content-length', str(len(body))) - conn.putheader('Authorization', auth) - conn.endheaders() - conn.send(body) - except socket.error as e: - self.announce(str(e), log.ERROR) - return - - r = conn.getresponse() - if r.status == 200: - msg = 'Server response (%s): %s' % (r.status, r.reason) - self.announce(msg, log.INFO) - elif r.status == 301: - location = r.getheader('Location') - if location is None: - location = 'https://pythonhosted.org/%s/' % meta.get_name() - msg = 'Upload successful. Visit %s' % location - self.announce(msg, log.INFO) - else: - msg = 'Upload failed (%s): %s' % (r.status, r.reason) - self.announce(msg, log.ERROR) - if self.show_response: - print('-' * 75, r.read(), '-' * 75) diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__init__.py b/venv/lib/python3.11/site-packages/setuptools/config/__init__.py deleted file mode 100755 index 1a5153a..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -"""For backward compatibility, expose main functions from -``setuptools.config.setupcfg`` -""" -import warnings -from functools import wraps -from textwrap import dedent -from typing import Callable, TypeVar, cast - -from .._deprecation_warning import SetuptoolsDeprecationWarning -from . import setupcfg - -Fn = TypeVar("Fn", bound=Callable) - -__all__ = ('parse_configuration', 'read_configuration') - - -def _deprecation_notice(fn: Fn) -> Fn: - @wraps(fn) - def _wrapper(*args, **kwargs): - msg = f"""\ - As setuptools moves its configuration towards `pyproject.toml`, - `{__name__}.{fn.__name__}` became deprecated. - - For the time being, you can use the `{setupcfg.__name__}` module - to access a backward compatible API, but this module is provisional - and might be removed in the future. - """ - warnings.warn(dedent(msg), SetuptoolsDeprecationWarning, stacklevel=2) - return fn(*args, **kwargs) - - return cast(Fn, _wrapper) - - -read_configuration = _deprecation_notice(setupcfg.read_configuration) -parse_configuration = _deprecation_notice(setupcfg.parse_configuration) diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index ecced6e2bd921f211dfe59894231daa860e33d91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2031 zcmZ`(&1)M+6rcT)R(dmV=y$0*J9sUBtH^@dMWJ|W}N+k(K#g#p!q)39Nx~iv@w0N$$ z2`^bndU{FsQl%8|5_Zx}dqbrmnCo`R9riM%jD%!FbURIwFNU^dgm$2JT4}@{E@kZu z8L>ymNL977Pt;Nlv~wi0INHiu32$Ol)T#r$vu-ss%0{MAUp=mGxPnEZ;_A^ z3oHu!`zG}rzjh#81SP$9StQT;;+{%S_wBqKjfW;>#ORn*r}5rsj1tp6!IP_gl%Q}G z^{sx~;Bb*;1^QtH$QO`j{x9hU8jRyQszUCc=-Z&X1HIE8OI)1LZM=sYSg%ThxrH3a zb5>7Nj7jKkK|d5nZb|?%iNmbdzC*UWp)B^62-XVkLj|D$iTZu=vCOr;GFt4L#Z$-J zRe8`U9+yBzZfh?R+pue=zf%BpLs>-*IP;_Ql>{y%=T<(!-FAcFV`N}2SSAcRoB^~1 zM!E^XJP>$exEwY@8Y~iv7kJ>g<(YKvobr)WSh-oo70ACwu-!!hu?y+Gj=(NoAecL# zQ6T`28Qci!*fM=w2jB`>d1a#vX4rL?^!M=qo0dfw!{&dn?-G3D;}2(WrOx31hjlk& zn1QLw4g)ZnZvQOPx3TBc7C0DyDG?6a80tmbU9AJUNTIJwbqFeeHO)9woJ*F8n@>c# zVff&pVbCEEM><4CAe}|3m{EZqDzcSVBh{q9Pl#fLQSn%f=0L)P4g_xP=+ojt;E|$d zQY$Ea6x4#tMKcVG%fw$Ux=y7SHuyr|UoKp{SY!?-?}T87StG1?oU>vlQ$@pYe1{uG zA#8w&qKrdASKc;ynSd}De!v}z6t22~WxDKIp{FKZ9Y%rty@uLqGCTZ7daSL%*hWD1 zCr&;4?0ES~N5w0x!u58lrx0tcE3a}WHTq>{v${3^_0qGYm*=kkdZVe&?do$aeGVpj z+0k|S^xbB5dh0zP;@77S;Z~GasK6@~#YBe%LyiMQr(n)Rxs)+I14A_a8h@y$Kk=}# zYe2w--?a4lrOzKcdC->A+PO9wAb%++k?o3JokqjCP5J2uyF*j0p{b@iMbE+!`SB=e z7o^yh=zsrxbiFzF@1e=&;J>d8uian2yLGy$P48;cEp2*D-cMgyOSTgu(%G%| z+X#jqF2%!1GL0tl&585RPq*^7b|-GPCT=&;*dFjE^Uu$>F3j#u-f2zVX`=DY9|z+f D@(mIn diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-311.pyc deleted file mode 100755 index 6e98474da287e1f770af37889dd147e8d8188ef9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22840 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/expand.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/expand.cpython-311.pyc deleted file mode 100755 index 2d210fdc7bf935f4e1dd2f047aef5d65d1b83e5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28245 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 XG$W@r&s@Cu#%J{Q^Chw{f#rVzT9%K~ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/pyprojecttoml.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/pyprojecttoml.cpython-311.pyc deleted file mode 100755 index 32c58d2dffdfb362de1ea0ad7468506c46eac4ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27876 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/setupcfg.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/setupcfg.cpython-311.pyc deleted file mode 100755 index 13a88b41629207df2c3792cbf1976d9c0969a751..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33285 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 "Distribution": - """Apply configuration dict read with :func:`read_configuration`""" - - if not config: - return dist # short-circuit unrelated pyproject.toml file - - root_dir = os.path.dirname(filename) or "." - - _apply_project_table(dist, config, root_dir) - _apply_tool_table(dist, config, filename) - - current_directory = os.getcwd() - os.chdir(root_dir) - try: - dist._finalize_requires() - dist._finalize_license_files() - finally: - os.chdir(current_directory) - - return dist - - -def _apply_project_table(dist: "Distribution", config: dict, root_dir: _Path): - project_table = config.get("project", {}).copy() - if not project_table: - return # short-circuit - - _handle_missing_dynamic(dist, project_table) - _unify_entry_points(project_table) - - for field, value in project_table.items(): - norm_key = json_compatible_key(field) - corresp = PYPROJECT_CORRESPONDENCE.get(norm_key, norm_key) - if callable(corresp): - corresp(dist, value, root_dir) - else: - _set_config(dist, corresp, value) - - -def _apply_tool_table(dist: "Distribution", config: dict, filename: _Path): - tool_table = config.get("tool", {}).get("setuptools", {}) - if not tool_table: - return # short-circuit - - for field, value in tool_table.items(): - norm_key = json_compatible_key(field) - - if norm_key in TOOL_TABLE_DEPRECATIONS: - suggestion = TOOL_TABLE_DEPRECATIONS[norm_key] - msg = f"The parameter `{norm_key}` is deprecated, {suggestion}" - warnings.warn(msg, SetuptoolsDeprecationWarning) - - norm_key = TOOL_TABLE_RENAMES.get(norm_key, norm_key) - _set_config(dist, norm_key, value) - - _copy_command_options(config, dist, filename) - - -def _handle_missing_dynamic(dist: "Distribution", project_table: dict): - """Be temporarily forgiving with ``dynamic`` fields not listed in ``dynamic``""" - # TODO: Set fields back to `None` once the feature stabilizes - dynamic = set(project_table.get("dynamic", [])) - for field, getter in _PREVIOUSLY_DEFINED.items(): - if not (field in project_table or field in dynamic): - value = getter(dist) - if value: - msg = _WouldIgnoreField.message(field, value) - warnings.warn(msg, _WouldIgnoreField) - - -def json_compatible_key(key: str) -> str: - """As defined in :pep:`566#json-compatible-metadata`""" - return key.lower().replace("-", "_") - - -def _set_config(dist: "Distribution", field: str, value: Any): - setter = getattr(dist.metadata, f"set_{field}", None) - if setter: - setter(value) - elif hasattr(dist.metadata, field) or field in SETUPTOOLS_PATCHES: - setattr(dist.metadata, field, value) - else: - setattr(dist, field, value) - - -_CONTENT_TYPES = { - ".md": "text/markdown", - ".rst": "text/x-rst", - ".txt": "text/plain", -} - - -def _guess_content_type(file: str) -> Optional[str]: - _, ext = os.path.splitext(file.lower()) - if not ext: - return None - - if ext in _CONTENT_TYPES: - return _CONTENT_TYPES[ext] - - valid = ", ".join(f"{k} ({v})" for k, v in _CONTENT_TYPES.items()) - msg = f"only the following file extensions are recognized: {valid}." - raise ValueError(f"Undefined content type for {file}, {msg}") - - -def _long_description(dist: "Distribution", val: _DictOrStr, root_dir: _Path): - from setuptools.config import expand - - if isinstance(val, str): - file: Union[str, list] = val - text = expand.read_files(file, root_dir) - ctype = _guess_content_type(val) - else: - file = val.get("file") or [] - text = val.get("text") or expand.read_files(file, root_dir) - ctype = val["content-type"] - - _set_config(dist, "long_description", text) - - if ctype: - _set_config(dist, "long_description_content_type", ctype) - - if file: - dist._referenced_files.add(cast(str, file)) - - -def _license(dist: "Distribution", val: dict, root_dir: _Path): - from setuptools.config import expand - - if "file" in val: - _set_config(dist, "license", expand.read_files([val["file"]], root_dir)) - dist._referenced_files.add(val["file"]) - else: - _set_config(dist, "license", val["text"]) - - -def _people(dist: "Distribution", val: List[dict], _root_dir: _Path, kind: str): - field = [] - email_field = [] - for person in val: - if "name" not in person: - email_field.append(person["email"]) - elif "email" not in person: - field.append(person["name"]) - else: - addr = Address(display_name=person["name"], addr_spec=person["email"]) - email_field.append(str(addr)) - - if field: - _set_config(dist, kind, ", ".join(field)) - if email_field: - _set_config(dist, f"{kind}_email", ", ".join(email_field)) - - -def _project_urls(dist: "Distribution", val: dict, _root_dir): - _set_config(dist, "project_urls", val) - - -def _python_requires(dist: "Distribution", val: dict, _root_dir): - from setuptools.extern.packaging.specifiers import SpecifierSet - - _set_config(dist, "python_requires", SpecifierSet(val)) - - -def _dependencies(dist: "Distribution", val: list, _root_dir): - if getattr(dist, "install_requires", []): - msg = "`install_requires` overwritten in `pyproject.toml` (dependencies)" - warnings.warn(msg) - _set_config(dist, "install_requires", val) - - -def _optional_dependencies(dist: "Distribution", val: dict, _root_dir): - existing = getattr(dist, "extras_require", {}) - _set_config(dist, "extras_require", {**existing, **val}) - - -def _unify_entry_points(project_table: dict): - project = project_table - entry_points = project.pop("entry-points", project.pop("entry_points", {})) - renaming = {"scripts": "console_scripts", "gui_scripts": "gui_scripts"} - for key, value in list(project.items()): # eager to allow modifications - norm_key = json_compatible_key(key) - if norm_key in renaming and value: - entry_points[renaming[norm_key]] = project.pop(key) - - if entry_points: - project["entry-points"] = { - name: [f"{k} = {v}" for k, v in group.items()] - for name, group in entry_points.items() - } - - -def _copy_command_options(pyproject: dict, dist: "Distribution", filename: _Path): - tool_table = pyproject.get("tool", {}) - cmdclass = tool_table.get("setuptools", {}).get("cmdclass", {}) - valid_options = _valid_command_options(cmdclass) - - cmd_opts = dist.command_options - for cmd, config in pyproject.get("tool", {}).get("distutils", {}).items(): - cmd = json_compatible_key(cmd) - valid = valid_options.get(cmd, set()) - cmd_opts.setdefault(cmd, {}) - for key, value in config.items(): - key = json_compatible_key(key) - cmd_opts[cmd][key] = (str(filename), value) - if key not in valid: - # To avoid removing options that are specified dynamically we - # just log a warn... - _logger.warning(f"Command option {cmd}.{key} is not defined") - - -def _valid_command_options(cmdclass: Mapping = EMPTY) -> Dict[str, Set[str]]: - from .._importlib import metadata - from setuptools.dist import Distribution - - valid_options = {"global": _normalise_cmd_options(Distribution.global_options)} - - unloaded_entry_points = metadata.entry_points(group='distutils.commands') - loaded_entry_points = (_load_ep(ep) for ep in unloaded_entry_points) - entry_points = (ep for ep in loaded_entry_points if ep) - for cmd, cmd_class in chain(entry_points, cmdclass.items()): - opts = valid_options.get(cmd, set()) - opts = opts | _normalise_cmd_options(getattr(cmd_class, "user_options", [])) - valid_options[cmd] = opts - - return valid_options - - -def _load_ep(ep: "metadata.EntryPoint") -> Optional[Tuple[str, Type]]: - # Ignore all the errors - try: - return (ep.name, ep.load()) - except Exception as ex: - msg = f"{ex.__class__.__name__} while trying to load entry-point {ep.name}" - _logger.warning(f"{msg}: {ex}") - return None - - -def _normalise_cmd_option_key(name: str) -> str: - return json_compatible_key(name).strip("_=") - - -def _normalise_cmd_options(desc: List[Tuple[str, Optional[str], str]]) -> Set[str]: - return {_normalise_cmd_option_key(fancy_option[0]) for fancy_option in desc} - - -def _attrgetter(attr): - """ - Similar to ``operator.attrgetter`` but returns None if ``attr`` is not found - >>> from types import SimpleNamespace - >>> obj = SimpleNamespace(a=42, b=SimpleNamespace(c=13)) - >>> _attrgetter("a")(obj) - 42 - >>> _attrgetter("b.c")(obj) - 13 - >>> _attrgetter("d")(obj) is None - True - """ - return partial(reduce, lambda acc, x: getattr(acc, x, None), attr.split(".")) - - -def _some_attrgetter(*items): - """ - Return the first "truth-y" attribute or None - >>> from types import SimpleNamespace - >>> obj = SimpleNamespace(a=42, b=SimpleNamespace(c=13)) - >>> _some_attrgetter("d", "a", "b.c")(obj) - 42 - >>> _some_attrgetter("d", "e", "b.c", "a")(obj) - 13 - >>> _some_attrgetter("d", "e", "f")(obj) is None - True - """ - def _acessor(obj): - values = (_attrgetter(i)(obj) for i in items) - return next((i for i in values if i is not None), None) - return _acessor - - -PYPROJECT_CORRESPONDENCE: Dict[str, _Correspondence] = { - "readme": _long_description, - "license": _license, - "authors": partial(_people, kind="author"), - "maintainers": partial(_people, kind="maintainer"), - "urls": _project_urls, - "dependencies": _dependencies, - "optional_dependencies": _optional_dependencies, - "requires_python": _python_requires, -} - -TOOL_TABLE_RENAMES = {"script_files": "scripts"} -TOOL_TABLE_DEPRECATIONS = { - "namespace_packages": "consider using implicit namespaces instead (PEP 420)." -} - -SETUPTOOLS_PATCHES = {"long_description_content_type", "project_urls", - "provides_extras", "license_file", "license_files"} - -_PREVIOUSLY_DEFINED = { - "name": _attrgetter("metadata.name"), - "version": _attrgetter("metadata.version"), - "description": _attrgetter("metadata.description"), - "readme": _attrgetter("metadata.long_description"), - "requires-python": _some_attrgetter("python_requires", "metadata.python_requires"), - "license": _attrgetter("metadata.license"), - "authors": _some_attrgetter("metadata.author", "metadata.author_email"), - "maintainers": _some_attrgetter("metadata.maintainer", "metadata.maintainer_email"), - "keywords": _attrgetter("metadata.keywords"), - "classifiers": _attrgetter("metadata.classifiers"), - "urls": _attrgetter("metadata.project_urls"), - "entry-points": _attrgetter("entry_points"), - "dependencies": _some_attrgetter("_orig_install_requires", "install_requires"), - "optional-dependencies": _some_attrgetter("_orig_extras_require", "extras_require"), -} - - -class _WouldIgnoreField(UserWarning): - """Inform users that ``pyproject.toml`` would overwrite previous metadata.""" - - MESSAGE = """\ - {field!r} defined outside of `pyproject.toml` would be ignored. - !!\n\n - ########################################################################## - # configuration would be ignored/result in error due to `pyproject.toml` # - ########################################################################## - - The following seems to be defined outside of `pyproject.toml`: - - `{field} = {value!r}` - - According to the spec (see the link below), however, setuptools CANNOT - consider this value unless {field!r} is listed as `dynamic`. - - https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ - - For the time being, `setuptools` will still consider the given value (as a - **transitional** measure), but please note that future releases of setuptools will - follow strictly the standard. - - To prevent this warning, you can list {field!r} under `dynamic` or alternatively - remove the `[project]` table from your file and rely entirely on other means of - configuration. - \n\n!! - """ - - @classmethod - def message(cls, field, value): - from inspect import cleandoc - return cleandoc(cls.MESSAGE.format(field=field, value=value)) diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__init__.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__init__.py deleted file mode 100755 index dbe6cb4..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -from functools import reduce -from typing import Any, Callable, Dict - -from . import formats -from .error_reporting import detailed_errors, ValidationError -from .extra_validations import EXTRA_VALIDATIONS -from .fastjsonschema_exceptions import JsonSchemaException, JsonSchemaValueException -from .fastjsonschema_validations import validate as _validate - -__all__ = [ - "validate", - "FORMAT_FUNCTIONS", - "EXTRA_VALIDATIONS", - "ValidationError", - "JsonSchemaException", - "JsonSchemaValueException", -] - - -FORMAT_FUNCTIONS: Dict[str, Callable[[str], bool]] = { - fn.__name__.replace("_", "-"): fn - for fn in formats.__dict__.values() - if callable(fn) and not fn.__name__.startswith("_") -} - - -def validate(data: Any) -> bool: - """Validate the given ``data`` object using JSON Schema - This function raises ``ValidationError`` if ``data`` is invalid. - """ - with detailed_errors(): - _validate(data, custom_formats=FORMAT_FUNCTIONS) - reduce(lambda acc, fn: fn(acc), EXTRA_VALIDATIONS, data) - return True diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 79c091cc275a2ff006825033fe8681f4389e7ef3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2319 zcmZ`)&1)M+6rcT&b|u-8osT+p)mCYp22o+Xk` zStW5$iwi#VP^h6Tc1sQ>2e-w6hTi&L$Uz}uArL4%4)32SKaRjaY<1e#G5uv}?AZ(FsW#d0kme5sXAcM1z%_$tmbl&1^K@n_G5$%W) zfjPktt*9+2QlLjH*^VhOJFdioanwrK9ZE-_OID|yRFZZ|Nd;rs>ax3)eHKMh6y* zPOuY=tDD?Rv_5vYa0!*r@0@EBL~wGv~`^G|SSaE$oY9rtUrEwydP0OKi=f zS>8_>*wai48!9HmCDcz{(=5}_Jkxc~vKavFKKt3^l~MKD=qDG(Mkg;^9-jcm{THe0 zOz1P%*3RD2ahW;zhju0brh;25fFj@60>;@WNy0h&u5*{Kd^$R*p1V4JCO{<#m?kXJ zq=Si05IQ?@*rK2a@N6uDSVAVMqAx!Fit~2aRJm0ct+i(U=&o|JtuV$CnyQvQ`* zq=xR=3j=O3i=_lMTg z!}auVu+k8t3zr^=JrBg5Wnp<@T|8VD53l5#LL1-)?1D%NgfBwMX)Jxc3UOW?^m|~p zgmwqJy^c;I4tcwRRYe|fMcD4`2^Z8e&wlMe|<(JJh_*4i7eMM#9m?XS0s31_?+oGFnPSD!SzTp_W>QSSbsH}%PCzk>JBZ+7IzhMx0uZRWq+X$(YpdH8 zKd!g(6^_piydR#8Lm-wAkE$GeN?ZNFXK>@cv!oU@T_?6W zTn$W~G2`bgj~(AV+KU%2_RIvsf5dn#@htdlU7HVRlkw|@ef-)NWz9%pI zDV~!4;!a89**-rOM3q%&@QHrZn=3;G5SFWi{h1L)b3P(0!TeM}%PJ6sOFU-A?keC& zzZ>83h!)-&qy!DF%kM2})SCr%rU5&vIHYH~L#uw@9;5Bx1t=_1q@V3BsVXoSuomza zV+qirU|GR*t7--65nr5!kMUDr>Nu_!{BuxMB`oMcgu_I!U87>*5t4@m7E77~3BlmF z21?gn>J9XM?e+Z$I#_G(4fIj%RlR|Z*V=mnP1au3Uq)z(QUVAt6!TK^KuBOuk_YR_ zw;v^sJV+i{Padr&k2WK)_KZ>Hb0%u2Yq5WkE}vh~SFZjxw(@yBJy`1*tnbSMqjHQ^ ZIc5!7QsTN6hhQ77YxzX*daVd9^nYGCJ)Qsn diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-311.pyc deleted file mode 100755 index 28b31fac0031dc3de82b7d8145d38276ac7f5429..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20210 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 diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-311.pyc deleted file mode 100755 index ae6db3dc14e22ac926ebe23ff67cdc24799eb24c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3243 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

wZWUS!?B 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 T>N`gL=9v3*q4Dzq8sPr{9aQqX diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/error_reporting.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/error_reporting.py deleted file mode 100755 index f78e483..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/error_reporting.py +++ /dev/null @@ -1,318 +0,0 @@ -import io -import json -import logging -import os -import re -from contextlib import contextmanager -from textwrap import indent, wrap -from typing import Any, Dict, Iterator, List, Optional, Sequence, Union, cast - -from .fastjsonschema_exceptions import JsonSchemaValueException - -_logger = logging.getLogger(__name__) - -_MESSAGE_REPLACEMENTS = { - "must be named by propertyName definition": "keys must be named by", - "one of contains definition": "at least one item that matches", - " same as const definition:": "", - "only specified items": "only items matching the definition", -} - -_SKIP_DETAILS = ( - "must not be empty", - "is always invalid", - "must not be there", -) - -_NEED_DETAILS = {"anyOf", "oneOf", "anyOf", "contains", "propertyNames", "not", "items"} - -_CAMEL_CASE_SPLITTER = re.compile(r"\W+|([A-Z][^A-Z\W]*)") -_IDENTIFIER = re.compile(r"^[\w_]+$", re.I) - -_TOML_JARGON = { - "object": "table", - "property": "key", - "properties": "keys", - "property names": "keys", -} - - -class ValidationError(JsonSchemaValueException): - """Report violations of a given JSON schema. - - This class extends :exc:`~fastjsonschema.JsonSchemaValueException` - by adding the following properties: - - - ``summary``: an improved version of the ``JsonSchemaValueException`` error message - with only the necessary information) - - - ``details``: more contextual information about the error like the failing schema - itself and the value that violates the schema. - - Depending on the level of the verbosity of the ``logging`` configuration - the exception message will be only ``summary`` (default) or a combination of - ``summary`` and ``details`` (when the logging level is set to :obj:`logging.DEBUG`). - """ - - summary = "" - details = "" - _original_message = "" - - @classmethod - def _from_jsonschema(cls, ex: JsonSchemaValueException): - formatter = _ErrorFormatting(ex) - obj = cls(str(formatter), ex.value, formatter.name, ex.definition, ex.rule) - debug_code = os.getenv("JSONSCHEMA_DEBUG_CODE_GENERATION", "false").lower() - if debug_code != "false": # pragma: no cover - obj.__cause__, obj.__traceback__ = ex.__cause__, ex.__traceback__ - obj._original_message = ex.message - obj.summary = formatter.summary - obj.details = formatter.details - return obj - - -@contextmanager -def detailed_errors(): - try: - yield - except JsonSchemaValueException as ex: - raise ValidationError._from_jsonschema(ex) from None - - -class _ErrorFormatting: - def __init__(self, ex: JsonSchemaValueException): - self.ex = ex - self.name = f"`{self._simplify_name(ex.name)}`" - self._original_message = self.ex.message.replace(ex.name, self.name) - self._summary = "" - self._details = "" - - def __str__(self) -> str: - if _logger.getEffectiveLevel() <= logging.DEBUG and self.details: - return f"{self.summary}\n\n{self.details}" - - return self.summary - - @property - def summary(self) -> str: - if not self._summary: - self._summary = self._expand_summary() - - return self._summary - - @property - def details(self) -> str: - if not self._details: - self._details = self._expand_details() - - return self._details - - def _simplify_name(self, name): - x = len("data.") - return name[x:] if name.startswith("data.") else name - - def _expand_summary(self): - msg = self._original_message - - for bad, repl in _MESSAGE_REPLACEMENTS.items(): - msg = msg.replace(bad, repl) - - if any(substring in msg for substring in _SKIP_DETAILS): - return msg - - schema = self.ex.rule_definition - if self.ex.rule in _NEED_DETAILS and schema: - summary = _SummaryWriter(_TOML_JARGON) - return f"{msg}:\n\n{indent(summary(schema), ' ')}" - - return msg - - def _expand_details(self) -> str: - optional = [] - desc_lines = self.ex.definition.pop("$$description", []) - desc = self.ex.definition.pop("description", None) or " ".join(desc_lines) - if desc: - description = "\n".join( - wrap( - desc, - width=80, - initial_indent=" ", - subsequent_indent=" ", - break_long_words=False, - ) - ) - optional.append(f"DESCRIPTION:\n{description}") - schema = json.dumps(self.ex.definition, indent=4) - value = json.dumps(self.ex.value, indent=4) - defaults = [ - f"GIVEN VALUE:\n{indent(value, ' ')}", - f"OFFENDING RULE: {self.ex.rule!r}", - f"DEFINITION:\n{indent(schema, ' ')}", - ] - return "\n\n".join(optional + defaults) - - -class _SummaryWriter: - _IGNORE = {"description", "default", "title", "examples"} - - def __init__(self, jargon: Optional[Dict[str, str]] = None): - self.jargon: Dict[str, str] = jargon or {} - # Clarify confusing terms - self._terms = { - "anyOf": "at least one of the following", - "oneOf": "exactly one of the following", - "allOf": "all of the following", - "not": "(*NOT* the following)", - "prefixItems": f"{self._jargon('items')} (in order)", - "items": "items", - "contains": "contains at least one of", - "propertyNames": ( - f"non-predefined acceptable {self._jargon('property names')}" - ), - "patternProperties": f"{self._jargon('properties')} named via pattern", - "const": "predefined value", - "enum": "one of", - } - # Attributes that indicate that the definition is easy and can be done - # inline (e.g. string and number) - self._guess_inline_defs = [ - "enum", - "const", - "maxLength", - "minLength", - "pattern", - "format", - "minimum", - "maximum", - "exclusiveMinimum", - "exclusiveMaximum", - "multipleOf", - ] - - def _jargon(self, term: Union[str, List[str]]) -> Union[str, List[str]]: - if isinstance(term, list): - return [self.jargon.get(t, t) for t in term] - return self.jargon.get(term, term) - - def __call__( - self, - schema: Union[dict, List[dict]], - prefix: str = "", - *, - _path: Sequence[str] = (), - ) -> str: - if isinstance(schema, list): - return self._handle_list(schema, prefix, _path) - - filtered = self._filter_unecessary(schema, _path) - simple = self._handle_simple_dict(filtered, _path) - if simple: - return f"{prefix}{simple}" - - child_prefix = self._child_prefix(prefix, " ") - item_prefix = self._child_prefix(prefix, "- ") - indent = len(prefix) * " " - with io.StringIO() as buffer: - for i, (key, value) in enumerate(filtered.items()): - child_path = [*_path, key] - line_prefix = prefix if i == 0 else indent - buffer.write(f"{line_prefix}{self._label(child_path)}:") - # ^ just the first item should receive the complete prefix - if isinstance(value, dict): - filtered = self._filter_unecessary(value, child_path) - simple = self._handle_simple_dict(filtered, child_path) - buffer.write( - f" {simple}" - if simple - else f"\n{self(value, child_prefix, _path=child_path)}" - ) - elif isinstance(value, list) and ( - key != "type" or self._is_property(child_path) - ): - children = self._handle_list(value, item_prefix, child_path) - sep = " " if children.startswith("[") else "\n" - buffer.write(f"{sep}{children}") - else: - buffer.write(f" {self._value(value, child_path)}\n") - return buffer.getvalue() - - def _is_unecessary(self, path: Sequence[str]) -> bool: - if self._is_property(path) or not path: # empty path => instruction @ root - return False - key = path[-1] - return any(key.startswith(k) for k in "$_") or key in self._IGNORE - - def _filter_unecessary(self, schema: dict, path: Sequence[str]): - return { - key: value - for key, value in schema.items() - if not self._is_unecessary([*path, key]) - } - - def _handle_simple_dict(self, value: dict, path: Sequence[str]) -> Optional[str]: - inline = any(p in value for p in self._guess_inline_defs) - simple = not any(isinstance(v, (list, dict)) for v in value.values()) - if inline or simple: - return f"{{{', '.join(self._inline_attrs(value, path))}}}\n" - return None - - def _handle_list( - self, schemas: list, prefix: str = "", path: Sequence[str] = () - ) -> str: - if self._is_unecessary(path): - return "" - - repr_ = repr(schemas) - if all(not isinstance(e, (dict, list)) for e in schemas) and len(repr_) < 60: - return f"{repr_}\n" - - item_prefix = self._child_prefix(prefix, "- ") - return "".join( - self(v, item_prefix, _path=[*path, f"[{i}]"]) for i, v in enumerate(schemas) - ) - - def _is_property(self, path: Sequence[str]): - """Check if the given path can correspond to an arbitrarily named property""" - counter = 0 - for key in path[-2::-1]: - if key not in {"properties", "patternProperties"}: - break - counter += 1 - - # If the counter if even, the path correspond to a JSON Schema keyword - # otherwise it can be any arbitrary string naming a property - return counter % 2 == 1 - - def _label(self, path: Sequence[str]) -> str: - *parents, key = path - if not self._is_property(path): - norm_key = _separate_terms(key) - return self._terms.get(key) or " ".join(self._jargon(norm_key)) - - if parents[-1] == "patternProperties": - return f"(regex {key!r})" - return repr(key) # property name - - def _value(self, value: Any, path: Sequence[str]) -> str: - if path[-1] == "type" and not self._is_property(path): - type_ = self._jargon(value) - return ( - f"[{', '.join(type_)}]" if isinstance(value, list) else cast(str, type_) - ) - return repr(value) - - def _inline_attrs(self, schema: dict, path: Sequence[str]) -> Iterator[str]: - for key, value in schema.items(): - child_path = [*path, key] - yield f"{self._label(child_path)}: {self._value(value, child_path)}" - - def _child_prefix(self, parent_prefix: str, child_prefix: str) -> str: - return len(parent_prefix) * " " + child_prefix - - -def _separate_terms(word: str) -> List[str]: - """ - >>> _separate_terms("FooBar-foo") - ['foo', 'bar', 'foo'] - """ - return [w.lower() for w in _CAMEL_CASE_SPLITTER.split(word) if w] diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/extra_validations.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/extra_validations.py deleted file mode 100755 index 4130a42..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/extra_validations.py +++ /dev/null @@ -1,36 +0,0 @@ -"""The purpose of this module is implement PEP 621 validations that are -difficult to express as a JSON Schema (or that are not supported by the current -JSON Schema library). -""" - -from typing import Mapping, TypeVar - -from .error_reporting import ValidationError - -T = TypeVar("T", bound=Mapping) - - -class RedefiningStaticFieldAsDynamic(ValidationError): - """According to PEP 621: - - Build back-ends MUST raise an error if the metadata specifies a field - statically as well as being listed in dynamic. - """ - - -def validate_project_dynamic(pyproject: T) -> T: - project_table = pyproject.get("project", {}) - dynamic = project_table.get("dynamic", []) - - for field in dynamic: - if field in project_table: - msg = f"You cannot provide a value for `project.{field}` and " - msg += "list it under `project.dynamic` at the same time" - name = f"data.project.{field}" - value = {field: project_table[field], "...": " # ...", "dynamic": dynamic} - raise RedefiningStaticFieldAsDynamic(msg, value, name, rule="PEP 621") - - return pyproject - - -EXTRA_VALIDATIONS = (validate_project_dynamic,) diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py deleted file mode 100755 index d2dddd6..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py +++ /dev/null @@ -1,51 +0,0 @@ -import re - - -SPLIT_RE = re.compile(r'[\.\[\]]+') - - -class JsonSchemaException(ValueError): - """ - Base exception of ``fastjsonschema`` library. - """ - - -class JsonSchemaValueException(JsonSchemaException): - """ - Exception raised by validation function. Available properties: - - * ``message`` containing human-readable information what is wrong (e.g. ``data.property[index] must be smaller than or equal to 42``), - * invalid ``value`` (e.g. ``60``), - * ``name`` of a path in the data structure (e.g. ``data.property[index]``), - * ``path`` as an array in the data structure (e.g. ``['data', 'property', 'index']``), - * the whole ``definition`` which the ``value`` has to fulfil (e.g. ``{'type': 'number', 'maximum': 42}``), - * ``rule`` which the ``value`` is breaking (e.g. ``maximum``) - * and ``rule_definition`` (e.g. ``42``). - - .. versionchanged:: 2.14.0 - Added all extra properties. - """ - - def __init__(self, message, value=None, name=None, definition=None, rule=None): - super().__init__(message) - self.message = message - self.value = value - self.name = name - self.definition = definition - self.rule = rule - - @property - def path(self): - return [item for item in SPLIT_RE.split(self.name) if item != ''] - - @property - def rule_definition(self): - if not self.rule or not self.definition: - return None - return self.definition.get(self.rule) - - -class JsonSchemaDefinitionException(JsonSchemaException): - """ - Exception raised by generator of validation function. - """ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py deleted file mode 100755 index ad5ee31..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py +++ /dev/null @@ -1,1035 +0,0 @@ -# noqa -# type: ignore -# flake8: noqa -# pylint: skip-file -# mypy: ignore-errors -# yapf: disable -# pylama:skip=1 - - -# *** PLEASE DO NOT MODIFY DIRECTLY: Automatically generated code *** - - -VERSION = "2.15.3" -import re -from .fastjsonschema_exceptions import JsonSchemaValueException - - -REGEX_PATTERNS = { - '^.*$': re.compile('^.*$'), - '.+': re.compile('.+'), - '^.+$': re.compile('^.+$'), - 'idn-email_re_pattern': re.compile('^[^@]+@[^@]+\\.[^@]+\\Z') -} - -NoneType = type(None) - -def validate(data, custom_formats={}, name_prefix=None): - validate_https___packaging_python_org_en_latest_specifications_declaring_build_dependencies(data, custom_formats, (name_prefix or "data") + "") - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_build_dependencies(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-build-dependencies/', 'title': 'Data structure for ``pyproject.toml`` files', '$$description': ['File format containing build-time configurations for the Python ecosystem. ', ':pep:`517` initially defined a build-system independent format for source trees', 'which was complemented by :pep:`518` to provide a way of specifying dependencies ', 'for building Python projects.', 'Please notice the ``project`` table (as initially defined in :pep:`621`) is not included', 'in this schema and should be considered separately.'], 'type': 'object', 'additionalProperties': False, 'properties': {'build-system': {'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, 'project': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create command-line wrappers for the given', '`entry points `_.']}, 'gui-scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create GUI wrappers for the given', '`entry points `_.', 'The difference between ``scripts`` and ``gui-scripts`` is only relevant in', 'Windows.']}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$ref': '#/definitions/entry-point-group'}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$ref': '#/definitions/dependency'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$ref': '#/definitions/dependency'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, 'tool': {'type': 'object', 'properties': {'distutils': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://docs.python.org/3/install/', 'title': '``tool.distutils`` table', '$$description': ['Originally, ``distutils`` allowed developers to configure arguments for', '``setup.py`` scripts via `distutils configuration files', '`_.', '``tool.distutils`` subtables could be used with the same purpose', '(NOT CURRENTLY IMPLEMENTED).'], 'type': 'object', 'properties': {'global': {'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}}, 'patternProperties': {'.+': {'type': 'object'}}, '$comment': 'TODO: Is there a practical way of making this schema more specific?'}, 'setuptools': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$ref': '#/definitions/find-directive'}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'$ref': '#/definitions/attr-directive'}, {'$ref': '#/definitions/file-directive'}]}, 'classifiers': {'$ref': '#/definitions/file-directive'}, 'description': {'$ref': '#/definitions/file-directive'}, 'dependencies': {'$ref': '#/definitions/file-directive'}, 'entry-points': {'$ref': '#/definitions/file-directive'}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$ref': '#/definitions/file-directive'}}}, 'readme': {'anyOf': [{'$ref': '#/definitions/file-directive'}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}}}}, 'project': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create command-line wrappers for the given', '`entry points `_.']}, 'gui-scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create GUI wrappers for the given', '`entry points `_.', 'The difference between ``scripts`` and ``gui-scripts`` is only relevant in', 'Windows.']}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$ref': '#/definitions/entry-point-group'}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$ref': '#/definitions/dependency'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$ref': '#/definitions/dependency'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "build-system" in data_keys: - data_keys.remove("build-system") - data__buildsystem = data["build-system"] - if not isinstance(data__buildsystem, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system must be object", value=data__buildsystem, name="" + (name_prefix or "data") + ".build-system", definition={'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, rule='type') - data__buildsystem_is_dict = isinstance(data__buildsystem, dict) - if data__buildsystem_is_dict: - data__buildsystem_len = len(data__buildsystem) - if not all(prop in data__buildsystem for prop in ['requires']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system must contain ['requires'] properties", value=data__buildsystem, name="" + (name_prefix or "data") + ".build-system", definition={'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, rule='required') - data__buildsystem_keys = set(data__buildsystem.keys()) - if "requires" in data__buildsystem_keys: - data__buildsystem_keys.remove("requires") - data__buildsystem__requires = data__buildsystem["requires"] - if not isinstance(data__buildsystem__requires, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.requires must be array", value=data__buildsystem__requires, name="" + (name_prefix or "data") + ".build-system.requires", definition={'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, rule='type') - data__buildsystem__requires_is_list = isinstance(data__buildsystem__requires, (list, tuple)) - if data__buildsystem__requires_is_list: - data__buildsystem__requires_len = len(data__buildsystem__requires) - for data__buildsystem__requires_x, data__buildsystem__requires_item in enumerate(data__buildsystem__requires): - if not isinstance(data__buildsystem__requires_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.requires[{data__buildsystem__requires_x}]".format(**locals()) + " must be string", value=data__buildsystem__requires_item, name="" + (name_prefix or "data") + ".build-system.requires[{data__buildsystem__requires_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "build-backend" in data__buildsystem_keys: - data__buildsystem_keys.remove("build-backend") - data__buildsystem__buildbackend = data__buildsystem["build-backend"] - if not isinstance(data__buildsystem__buildbackend, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.build-backend must be string", value=data__buildsystem__buildbackend, name="" + (name_prefix or "data") + ".build-system.build-backend", definition={'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, rule='type') - if isinstance(data__buildsystem__buildbackend, str): - if not custom_formats["pep517-backend-reference"](data__buildsystem__buildbackend): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.build-backend must be pep517-backend-reference", value=data__buildsystem__buildbackend, name="" + (name_prefix or "data") + ".build-system.build-backend", definition={'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, rule='format') - if "backend-path" in data__buildsystem_keys: - data__buildsystem_keys.remove("backend-path") - data__buildsystem__backendpath = data__buildsystem["backend-path"] - if not isinstance(data__buildsystem__backendpath, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.backend-path must be array", value=data__buildsystem__backendpath, name="" + (name_prefix or "data") + ".build-system.backend-path", definition={'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}, rule='type') - data__buildsystem__backendpath_is_list = isinstance(data__buildsystem__backendpath, (list, tuple)) - if data__buildsystem__backendpath_is_list: - data__buildsystem__backendpath_len = len(data__buildsystem__backendpath) - for data__buildsystem__backendpath_x, data__buildsystem__backendpath_item in enumerate(data__buildsystem__backendpath): - if not isinstance(data__buildsystem__backendpath_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.backend-path[{data__buildsystem__backendpath_x}]".format(**locals()) + " must be string", value=data__buildsystem__backendpath_item, name="" + (name_prefix or "data") + ".build-system.backend-path[{data__buildsystem__backendpath_x}]".format(**locals()) + "", definition={'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}, rule='type') - if data__buildsystem_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system must not contain "+str(data__buildsystem_keys)+" properties", value=data__buildsystem, name="" + (name_prefix or "data") + ".build-system", definition={'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, rule='additionalProperties') - if "project" in data_keys: - data_keys.remove("project") - data__project = data["project"] - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata(data__project, custom_formats, (name_prefix or "data") + ".project") - if "tool" in data_keys: - data_keys.remove("tool") - data__tool = data["tool"] - if not isinstance(data__tool, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".tool must be object", value=data__tool, name="" + (name_prefix or "data") + ".tool", definition={'type': 'object', 'properties': {'distutils': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://docs.python.org/3/install/', 'title': '``tool.distutils`` table', '$$description': ['Originally, ``distutils`` allowed developers to configure arguments for', '``setup.py`` scripts via `distutils configuration files', '`_.', '``tool.distutils`` subtables could be used with the same purpose', '(NOT CURRENTLY IMPLEMENTED).'], 'type': 'object', 'properties': {'global': {'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}}, 'patternProperties': {'.+': {'type': 'object'}}, '$comment': 'TODO: Is there a practical way of making this schema more specific?'}, 'setuptools': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$ref': '#/definitions/find-directive'}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'$ref': '#/definitions/attr-directive'}, {'$ref': '#/definitions/file-directive'}]}, 'classifiers': {'$ref': '#/definitions/file-directive'}, 'description': {'$ref': '#/definitions/file-directive'}, 'dependencies': {'$ref': '#/definitions/file-directive'}, 'entry-points': {'$ref': '#/definitions/file-directive'}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$ref': '#/definitions/file-directive'}}}, 'readme': {'anyOf': [{'$ref': '#/definitions/file-directive'}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}}}, rule='type') - data__tool_is_dict = isinstance(data__tool, dict) - if data__tool_is_dict: - data__tool_keys = set(data__tool.keys()) - if "distutils" in data__tool_keys: - data__tool_keys.remove("distutils") - data__tool__distutils = data__tool["distutils"] - validate_https___docs_python_org_3_install(data__tool__distutils, custom_formats, (name_prefix or "data") + ".tool.distutils") - if "setuptools" in data__tool_keys: - data__tool_keys.remove("setuptools") - data__tool__setuptools = data__tool["setuptools"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html(data__tool__setuptools, custom_formats, (name_prefix or "data") + ".tool.setuptools") - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-build-dependencies/', 'title': 'Data structure for ``pyproject.toml`` files', '$$description': ['File format containing build-time configurations for the Python ecosystem. ', ':pep:`517` initially defined a build-system independent format for source trees', 'which was complemented by :pep:`518` to provide a way of specifying dependencies ', 'for building Python projects.', 'Please notice the ``project`` table (as initially defined in :pep:`621`) is not included', 'in this schema and should be considered separately.'], 'type': 'object', 'additionalProperties': False, 'properties': {'build-system': {'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, 'project': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create command-line wrappers for the given', '`entry points `_.']}, 'gui-scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create GUI wrappers for the given', '`entry points `_.', 'The difference between ``scripts`` and ``gui-scripts`` is only relevant in', 'Windows.']}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$ref': '#/definitions/entry-point-group'}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$ref': '#/definitions/dependency'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$ref': '#/definitions/dependency'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, 'tool': {'type': 'object', 'properties': {'distutils': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://docs.python.org/3/install/', 'title': '``tool.distutils`` table', '$$description': ['Originally, ``distutils`` allowed developers to configure arguments for', '``setup.py`` scripts via `distutils configuration files', '`_.', '``tool.distutils`` subtables could be used with the same purpose', '(NOT CURRENTLY IMPLEMENTED).'], 'type': 'object', 'properties': {'global': {'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}}, 'patternProperties': {'.+': {'type': 'object'}}, '$comment': 'TODO: Is there a practical way of making this schema more specific?'}, 'setuptools': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$ref': '#/definitions/find-directive'}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'$ref': '#/definitions/attr-directive'}, {'$ref': '#/definitions/file-directive'}]}, 'classifiers': {'$ref': '#/definitions/file-directive'}, 'description': {'$ref': '#/definitions/file-directive'}, 'dependencies': {'$ref': '#/definitions/file-directive'}, 'entry-points': {'$ref': '#/definitions/file-directive'}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$ref': '#/definitions/file-directive'}}}, 'readme': {'anyOf': [{'$ref': '#/definitions/file-directive'}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}}}}, 'project': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create command-line wrappers for the given', '`entry points `_.']}, 'gui-scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create GUI wrappers for the given', '`entry points `_.', 'The difference between ``scripts`` and ``gui-scripts`` is only relevant in', 'Windows.']}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$ref': '#/definitions/entry-point-group'}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$ref': '#/definitions/dependency'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$ref': '#/definitions/dependency'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='additionalProperties') - return data - -def validate_https___setuptools_pypa_io_en_latest_references_keywords_html(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, 'classifiers': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'description': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'dependencies': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'entry-points': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, 'readme': {'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "platforms" in data_keys: - data_keys.remove("platforms") - data__platforms = data["platforms"] - if not isinstance(data__platforms, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".platforms must be array", value=data__platforms, name="" + (name_prefix or "data") + ".platforms", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__platforms_is_list = isinstance(data__platforms, (list, tuple)) - if data__platforms_is_list: - data__platforms_len = len(data__platforms) - for data__platforms_x, data__platforms_item in enumerate(data__platforms): - if not isinstance(data__platforms_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".platforms[{data__platforms_x}]".format(**locals()) + " must be string", value=data__platforms_item, name="" + (name_prefix or "data") + ".platforms[{data__platforms_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "provides" in data_keys: - data_keys.remove("provides") - data__provides = data["provides"] - if not isinstance(data__provides, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".provides must be array", value=data__provides, name="" + (name_prefix or "data") + ".provides", definition={'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, rule='type') - data__provides_is_list = isinstance(data__provides, (list, tuple)) - if data__provides_is_list: - data__provides_len = len(data__provides) - for data__provides_x, data__provides_item in enumerate(data__provides): - if not isinstance(data__provides_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".provides[{data__provides_x}]".format(**locals()) + " must be string", value=data__provides_item, name="" + (name_prefix or "data") + ".provides[{data__provides_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'pep508-identifier'}, rule='type') - if isinstance(data__provides_item, str): - if not custom_formats["pep508-identifier"](data__provides_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".provides[{data__provides_x}]".format(**locals()) + " must be pep508-identifier", value=data__provides_item, name="" + (name_prefix or "data") + ".provides[{data__provides_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'pep508-identifier'}, rule='format') - if "obsoletes" in data_keys: - data_keys.remove("obsoletes") - data__obsoletes = data["obsoletes"] - if not isinstance(data__obsoletes, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".obsoletes must be array", value=data__obsoletes, name="" + (name_prefix or "data") + ".obsoletes", definition={'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, rule='type') - data__obsoletes_is_list = isinstance(data__obsoletes, (list, tuple)) - if data__obsoletes_is_list: - data__obsoletes_len = len(data__obsoletes) - for data__obsoletes_x, data__obsoletes_item in enumerate(data__obsoletes): - if not isinstance(data__obsoletes_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".obsoletes[{data__obsoletes_x}]".format(**locals()) + " must be string", value=data__obsoletes_item, name="" + (name_prefix or "data") + ".obsoletes[{data__obsoletes_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'pep508-identifier'}, rule='type') - if isinstance(data__obsoletes_item, str): - if not custom_formats["pep508-identifier"](data__obsoletes_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".obsoletes[{data__obsoletes_x}]".format(**locals()) + " must be pep508-identifier", value=data__obsoletes_item, name="" + (name_prefix or "data") + ".obsoletes[{data__obsoletes_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'pep508-identifier'}, rule='format') - if "zip-safe" in data_keys: - data_keys.remove("zip-safe") - data__zipsafe = data["zip-safe"] - if not isinstance(data__zipsafe, (bool)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".zip-safe must be boolean", value=data__zipsafe, name="" + (name_prefix or "data") + ".zip-safe", definition={'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, rule='type') - if "script-files" in data_keys: - data_keys.remove("script-files") - data__scriptfiles = data["script-files"] - if not isinstance(data__scriptfiles, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".script-files must be array", value=data__scriptfiles, name="" + (name_prefix or "data") + ".script-files", definition={'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, rule='type') - data__scriptfiles_is_list = isinstance(data__scriptfiles, (list, tuple)) - if data__scriptfiles_is_list: - data__scriptfiles_len = len(data__scriptfiles) - for data__scriptfiles_x, data__scriptfiles_item in enumerate(data__scriptfiles): - if not isinstance(data__scriptfiles_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".script-files[{data__scriptfiles_x}]".format(**locals()) + " must be string", value=data__scriptfiles_item, name="" + (name_prefix or "data") + ".script-files[{data__scriptfiles_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "eager-resources" in data_keys: - data_keys.remove("eager-resources") - data__eagerresources = data["eager-resources"] - if not isinstance(data__eagerresources, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".eager-resources must be array", value=data__eagerresources, name="" + (name_prefix or "data") + ".eager-resources", definition={'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__eagerresources_is_list = isinstance(data__eagerresources, (list, tuple)) - if data__eagerresources_is_list: - data__eagerresources_len = len(data__eagerresources) - for data__eagerresources_x, data__eagerresources_item in enumerate(data__eagerresources): - if not isinstance(data__eagerresources_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".eager-resources[{data__eagerresources_x}]".format(**locals()) + " must be string", value=data__eagerresources_item, name="" + (name_prefix or "data") + ".eager-resources[{data__eagerresources_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "packages" in data_keys: - data_keys.remove("packages") - data__packages = data["packages"] - data__packages_one_of_count1 = 0 - if data__packages_one_of_count1 < 2: - try: - if not isinstance(data__packages, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".packages must be array", value=data__packages, name="" + (name_prefix or "data") + ".packages", definition={'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, rule='type') - data__packages_is_list = isinstance(data__packages, (list, tuple)) - if data__packages_is_list: - data__packages_len = len(data__packages) - for data__packages_x, data__packages_item in enumerate(data__packages): - if not isinstance(data__packages_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".packages[{data__packages_x}]".format(**locals()) + " must be string", value=data__packages_item, name="" + (name_prefix or "data") + ".packages[{data__packages_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='type') - if isinstance(data__packages_item, str): - if not custom_formats["python-module-name"](data__packages_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".packages[{data__packages_x}]".format(**locals()) + " must be python-module-name", value=data__packages_item, name="" + (name_prefix or "data") + ".packages[{data__packages_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='format') - data__packages_one_of_count1 += 1 - except JsonSchemaValueException: pass - if data__packages_one_of_count1 < 2: - try: - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_find_directive(data__packages, custom_formats, (name_prefix or "data") + ".packages") - data__packages_one_of_count1 += 1 - except JsonSchemaValueException: pass - if data__packages_one_of_count1 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".packages must be valid exactly by one definition" + (" (" + str(data__packages_one_of_count1) + " matches found)"), value=data__packages, name="" + (name_prefix or "data") + ".packages", definition={'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}]}, rule='oneOf') - if "package-dir" in data_keys: - data_keys.remove("package-dir") - data__packagedir = data["package-dir"] - if not isinstance(data__packagedir, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be object", value=data__packagedir, name="" + (name_prefix or "data") + ".package-dir", definition={'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, rule='type') - data__packagedir_is_dict = isinstance(data__packagedir, dict) - if data__packagedir_is_dict: - data__packagedir_keys = set(data__packagedir.keys()) - for data__packagedir_key, data__packagedir_val in data__packagedir.items(): - if REGEX_PATTERNS['^.*$'].search(data__packagedir_key): - if data__packagedir_key in data__packagedir_keys: - data__packagedir_keys.remove(data__packagedir_key) - if not isinstance(data__packagedir_val, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir.{data__packagedir_key}".format(**locals()) + " must be string", value=data__packagedir_val, name="" + (name_prefix or "data") + ".package-dir.{data__packagedir_key}".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if data__packagedir_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must not contain "+str(data__packagedir_keys)+" properties", value=data__packagedir, name="" + (name_prefix or "data") + ".package-dir", definition={'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, rule='additionalProperties') - data__packagedir_len = len(data__packagedir) - if data__packagedir_len != 0: - data__packagedir_property_names = True - for data__packagedir_key in data__packagedir: - try: - data__packagedir_key_one_of_count2 = 0 - if data__packagedir_key_one_of_count2 < 2: - try: - if isinstance(data__packagedir_key, str): - if not custom_formats["python-module-name"](data__packagedir_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be python-module-name", value=data__packagedir_key, name="" + (name_prefix or "data") + ".package-dir", definition={'format': 'python-module-name'}, rule='format') - data__packagedir_key_one_of_count2 += 1 - except JsonSchemaValueException: pass - if data__packagedir_key_one_of_count2 < 2: - try: - if data__packagedir_key != "": - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be same as const definition: ", value=data__packagedir_key, name="" + (name_prefix or "data") + ".package-dir", definition={'const': ''}, rule='const') - data__packagedir_key_one_of_count2 += 1 - except JsonSchemaValueException: pass - if data__packagedir_key_one_of_count2 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be valid exactly by one definition" + (" (" + str(data__packagedir_key_one_of_count2) + " matches found)"), value=data__packagedir_key, name="" + (name_prefix or "data") + ".package-dir", definition={'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, rule='oneOf') - except JsonSchemaValueException: - data__packagedir_property_names = False - if not data__packagedir_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be named by propertyName definition", value=data__packagedir, name="" + (name_prefix or "data") + ".package-dir", definition={'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, rule='propertyNames') - if "package-data" in data_keys: - data_keys.remove("package-data") - data__packagedata = data["package-data"] - if not isinstance(data__packagedata, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be object", value=data__packagedata, name="" + (name_prefix or "data") + ".package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='type') - data__packagedata_is_dict = isinstance(data__packagedata, dict) - if data__packagedata_is_dict: - data__packagedata_keys = set(data__packagedata.keys()) - for data__packagedata_key, data__packagedata_val in data__packagedata.items(): - if REGEX_PATTERNS['^.*$'].search(data__packagedata_key): - if data__packagedata_key in data__packagedata_keys: - data__packagedata_keys.remove(data__packagedata_key) - if not isinstance(data__packagedata_val, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data.{data__packagedata_key}".format(**locals()) + " must be array", value=data__packagedata_val, name="" + (name_prefix or "data") + ".package-data.{data__packagedata_key}".format(**locals()) + "", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__packagedata_val_is_list = isinstance(data__packagedata_val, (list, tuple)) - if data__packagedata_val_is_list: - data__packagedata_val_len = len(data__packagedata_val) - for data__packagedata_val_x, data__packagedata_val_item in enumerate(data__packagedata_val): - if not isinstance(data__packagedata_val_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data.{data__packagedata_key}[{data__packagedata_val_x}]".format(**locals()) + " must be string", value=data__packagedata_val_item, name="" + (name_prefix or "data") + ".package-data.{data__packagedata_key}[{data__packagedata_val_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if data__packagedata_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must not contain "+str(data__packagedata_keys)+" properties", value=data__packagedata, name="" + (name_prefix or "data") + ".package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='additionalProperties') - data__packagedata_len = len(data__packagedata) - if data__packagedata_len != 0: - data__packagedata_property_names = True - for data__packagedata_key in data__packagedata: - try: - data__packagedata_key_one_of_count3 = 0 - if data__packagedata_key_one_of_count3 < 2: - try: - if isinstance(data__packagedata_key, str): - if not custom_formats["python-module-name"](data__packagedata_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be python-module-name", value=data__packagedata_key, name="" + (name_prefix or "data") + ".package-data", definition={'format': 'python-module-name'}, rule='format') - data__packagedata_key_one_of_count3 += 1 - except JsonSchemaValueException: pass - if data__packagedata_key_one_of_count3 < 2: - try: - if data__packagedata_key != "*": - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be same as const definition: *", value=data__packagedata_key, name="" + (name_prefix or "data") + ".package-data", definition={'const': '*'}, rule='const') - data__packagedata_key_one_of_count3 += 1 - except JsonSchemaValueException: pass - if data__packagedata_key_one_of_count3 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be valid exactly by one definition" + (" (" + str(data__packagedata_key_one_of_count3) + " matches found)"), value=data__packagedata_key, name="" + (name_prefix or "data") + ".package-data", definition={'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, rule='oneOf') - except JsonSchemaValueException: - data__packagedata_property_names = False - if not data__packagedata_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be named by propertyName definition", value=data__packagedata, name="" + (name_prefix or "data") + ".package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='propertyNames') - if "include-package-data" in data_keys: - data_keys.remove("include-package-data") - data__includepackagedata = data["include-package-data"] - if not isinstance(data__includepackagedata, (bool)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".include-package-data must be boolean", value=data__includepackagedata, name="" + (name_prefix or "data") + ".include-package-data", definition={'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, rule='type') - if "exclude-package-data" in data_keys: - data_keys.remove("exclude-package-data") - data__excludepackagedata = data["exclude-package-data"] - if not isinstance(data__excludepackagedata, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be object", value=data__excludepackagedata, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='type') - data__excludepackagedata_is_dict = isinstance(data__excludepackagedata, dict) - if data__excludepackagedata_is_dict: - data__excludepackagedata_keys = set(data__excludepackagedata.keys()) - for data__excludepackagedata_key, data__excludepackagedata_val in data__excludepackagedata.items(): - if REGEX_PATTERNS['^.*$'].search(data__excludepackagedata_key): - if data__excludepackagedata_key in data__excludepackagedata_keys: - data__excludepackagedata_keys.remove(data__excludepackagedata_key) - if not isinstance(data__excludepackagedata_val, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data.{data__excludepackagedata_key}".format(**locals()) + " must be array", value=data__excludepackagedata_val, name="" + (name_prefix or "data") + ".exclude-package-data.{data__excludepackagedata_key}".format(**locals()) + "", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__excludepackagedata_val_is_list = isinstance(data__excludepackagedata_val, (list, tuple)) - if data__excludepackagedata_val_is_list: - data__excludepackagedata_val_len = len(data__excludepackagedata_val) - for data__excludepackagedata_val_x, data__excludepackagedata_val_item in enumerate(data__excludepackagedata_val): - if not isinstance(data__excludepackagedata_val_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data.{data__excludepackagedata_key}[{data__excludepackagedata_val_x}]".format(**locals()) + " must be string", value=data__excludepackagedata_val_item, name="" + (name_prefix or "data") + ".exclude-package-data.{data__excludepackagedata_key}[{data__excludepackagedata_val_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if data__excludepackagedata_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must not contain "+str(data__excludepackagedata_keys)+" properties", value=data__excludepackagedata, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='additionalProperties') - data__excludepackagedata_len = len(data__excludepackagedata) - if data__excludepackagedata_len != 0: - data__excludepackagedata_property_names = True - for data__excludepackagedata_key in data__excludepackagedata: - try: - data__excludepackagedata_key_one_of_count4 = 0 - if data__excludepackagedata_key_one_of_count4 < 2: - try: - if isinstance(data__excludepackagedata_key, str): - if not custom_formats["python-module-name"](data__excludepackagedata_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be python-module-name", value=data__excludepackagedata_key, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'format': 'python-module-name'}, rule='format') - data__excludepackagedata_key_one_of_count4 += 1 - except JsonSchemaValueException: pass - if data__excludepackagedata_key_one_of_count4 < 2: - try: - if data__excludepackagedata_key != "*": - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be same as const definition: *", value=data__excludepackagedata_key, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'const': '*'}, rule='const') - data__excludepackagedata_key_one_of_count4 += 1 - except JsonSchemaValueException: pass - if data__excludepackagedata_key_one_of_count4 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be valid exactly by one definition" + (" (" + str(data__excludepackagedata_key_one_of_count4) + " matches found)"), value=data__excludepackagedata_key, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, rule='oneOf') - except JsonSchemaValueException: - data__excludepackagedata_property_names = False - if not data__excludepackagedata_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be named by propertyName definition", value=data__excludepackagedata, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='propertyNames') - if "namespace-packages" in data_keys: - data_keys.remove("namespace-packages") - data__namespacepackages = data["namespace-packages"] - if not isinstance(data__namespacepackages, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".namespace-packages must be array", value=data__namespacepackages, name="" + (name_prefix or "data") + ".namespace-packages", definition={'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, rule='type') - data__namespacepackages_is_list = isinstance(data__namespacepackages, (list, tuple)) - if data__namespacepackages_is_list: - data__namespacepackages_len = len(data__namespacepackages) - for data__namespacepackages_x, data__namespacepackages_item in enumerate(data__namespacepackages): - if not isinstance(data__namespacepackages_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".namespace-packages[{data__namespacepackages_x}]".format(**locals()) + " must be string", value=data__namespacepackages_item, name="" + (name_prefix or "data") + ".namespace-packages[{data__namespacepackages_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='type') - if isinstance(data__namespacepackages_item, str): - if not custom_formats["python-module-name"](data__namespacepackages_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".namespace-packages[{data__namespacepackages_x}]".format(**locals()) + " must be python-module-name", value=data__namespacepackages_item, name="" + (name_prefix or "data") + ".namespace-packages[{data__namespacepackages_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='format') - if "py-modules" in data_keys: - data_keys.remove("py-modules") - data__pymodules = data["py-modules"] - if not isinstance(data__pymodules, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".py-modules must be array", value=data__pymodules, name="" + (name_prefix or "data") + ".py-modules", definition={'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, rule='type') - data__pymodules_is_list = isinstance(data__pymodules, (list, tuple)) - if data__pymodules_is_list: - data__pymodules_len = len(data__pymodules) - for data__pymodules_x, data__pymodules_item in enumerate(data__pymodules): - if not isinstance(data__pymodules_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".py-modules[{data__pymodules_x}]".format(**locals()) + " must be string", value=data__pymodules_item, name="" + (name_prefix or "data") + ".py-modules[{data__pymodules_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='type') - if isinstance(data__pymodules_item, str): - if not custom_formats["python-module-name"](data__pymodules_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".py-modules[{data__pymodules_x}]".format(**locals()) + " must be python-module-name", value=data__pymodules_item, name="" + (name_prefix or "data") + ".py-modules[{data__pymodules_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='format') - if "data-files" in data_keys: - data_keys.remove("data-files") - data__datafiles = data["data-files"] - if not isinstance(data__datafiles, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".data-files must be object", value=data__datafiles, name="" + (name_prefix or "data") + ".data-files", definition={'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='type') - data__datafiles_is_dict = isinstance(data__datafiles, dict) - if data__datafiles_is_dict: - data__datafiles_keys = set(data__datafiles.keys()) - for data__datafiles_key, data__datafiles_val in data__datafiles.items(): - if REGEX_PATTERNS['^.*$'].search(data__datafiles_key): - if data__datafiles_key in data__datafiles_keys: - data__datafiles_keys.remove(data__datafiles_key) - if not isinstance(data__datafiles_val, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".data-files.{data__datafiles_key}".format(**locals()) + " must be array", value=data__datafiles_val, name="" + (name_prefix or "data") + ".data-files.{data__datafiles_key}".format(**locals()) + "", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__datafiles_val_is_list = isinstance(data__datafiles_val, (list, tuple)) - if data__datafiles_val_is_list: - data__datafiles_val_len = len(data__datafiles_val) - for data__datafiles_val_x, data__datafiles_val_item in enumerate(data__datafiles_val): - if not isinstance(data__datafiles_val_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".data-files.{data__datafiles_key}[{data__datafiles_val_x}]".format(**locals()) + " must be string", value=data__datafiles_val_item, name="" + (name_prefix or "data") + ".data-files.{data__datafiles_key}[{data__datafiles_val_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "cmdclass" in data_keys: - data_keys.remove("cmdclass") - data__cmdclass = data["cmdclass"] - if not isinstance(data__cmdclass, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".cmdclass must be object", value=data__cmdclass, name="" + (name_prefix or "data") + ".cmdclass", definition={'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, rule='type') - data__cmdclass_is_dict = isinstance(data__cmdclass, dict) - if data__cmdclass_is_dict: - data__cmdclass_keys = set(data__cmdclass.keys()) - for data__cmdclass_key, data__cmdclass_val in data__cmdclass.items(): - if REGEX_PATTERNS['^.*$'].search(data__cmdclass_key): - if data__cmdclass_key in data__cmdclass_keys: - data__cmdclass_keys.remove(data__cmdclass_key) - if not isinstance(data__cmdclass_val, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".cmdclass.{data__cmdclass_key}".format(**locals()) + " must be string", value=data__cmdclass_val, name="" + (name_prefix or "data") + ".cmdclass.{data__cmdclass_key}".format(**locals()) + "", definition={'type': 'string', 'format': 'python-qualified-identifier'}, rule='type') - if isinstance(data__cmdclass_val, str): - if not custom_formats["python-qualified-identifier"](data__cmdclass_val): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".cmdclass.{data__cmdclass_key}".format(**locals()) + " must be python-qualified-identifier", value=data__cmdclass_val, name="" + (name_prefix or "data") + ".cmdclass.{data__cmdclass_key}".format(**locals()) + "", definition={'type': 'string', 'format': 'python-qualified-identifier'}, rule='format') - if "license-files" in data_keys: - data_keys.remove("license-files") - data__licensefiles = data["license-files"] - if not isinstance(data__licensefiles, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license-files must be array", value=data__licensefiles, name="" + (name_prefix or "data") + ".license-files", definition={'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, rule='type') - data__licensefiles_is_list = isinstance(data__licensefiles, (list, tuple)) - if data__licensefiles_is_list: - data__licensefiles_len = len(data__licensefiles) - for data__licensefiles_x, data__licensefiles_item in enumerate(data__licensefiles): - if not isinstance(data__licensefiles_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license-files[{data__licensefiles_x}]".format(**locals()) + " must be string", value=data__licensefiles_item, name="" + (name_prefix or "data") + ".license-files[{data__licensefiles_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - else: data["license-files"] = ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'] - if "dynamic" in data_keys: - data_keys.remove("dynamic") - data__dynamic = data["dynamic"] - if not isinstance(data__dynamic, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must be object", value=data__dynamic, name="" + (name_prefix or "data") + ".dynamic", definition={'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, 'classifiers': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'description': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'dependencies': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'entry-points': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, 'readme': {'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}, rule='type') - data__dynamic_is_dict = isinstance(data__dynamic, dict) - if data__dynamic_is_dict: - data__dynamic_keys = set(data__dynamic.keys()) - if "version" in data__dynamic_keys: - data__dynamic_keys.remove("version") - data__dynamic__version = data__dynamic["version"] - data__dynamic__version_one_of_count5 = 0 - if data__dynamic__version_one_of_count5 < 2: - try: - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_attr_directive(data__dynamic__version, custom_formats, (name_prefix or "data") + ".dynamic.version") - data__dynamic__version_one_of_count5 += 1 - except JsonSchemaValueException: pass - if data__dynamic__version_one_of_count5 < 2: - try: - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__version, custom_formats, (name_prefix or "data") + ".dynamic.version") - data__dynamic__version_one_of_count5 += 1 - except JsonSchemaValueException: pass - if data__dynamic__version_one_of_count5 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.version must be valid exactly by one definition" + (" (" + str(data__dynamic__version_one_of_count5) + " matches found)"), value=data__dynamic__version, name="" + (name_prefix or "data") + ".dynamic.version", definition={'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, rule='oneOf') - if "classifiers" in data__dynamic_keys: - data__dynamic_keys.remove("classifiers") - data__dynamic__classifiers = data__dynamic["classifiers"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__classifiers, custom_formats, (name_prefix or "data") + ".dynamic.classifiers") - if "description" in data__dynamic_keys: - data__dynamic_keys.remove("description") - data__dynamic__description = data__dynamic["description"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__description, custom_formats, (name_prefix or "data") + ".dynamic.description") - if "dependencies" in data__dynamic_keys: - data__dynamic_keys.remove("dependencies") - data__dynamic__dependencies = data__dynamic["dependencies"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__dependencies, custom_formats, (name_prefix or "data") + ".dynamic.dependencies") - if "entry-points" in data__dynamic_keys: - data__dynamic_keys.remove("entry-points") - data__dynamic__entrypoints = data__dynamic["entry-points"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__entrypoints, custom_formats, (name_prefix or "data") + ".dynamic.entry-points") - if "optional-dependencies" in data__dynamic_keys: - data__dynamic_keys.remove("optional-dependencies") - data__dynamic__optionaldependencies = data__dynamic["optional-dependencies"] - if not isinstance(data__dynamic__optionaldependencies, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.optional-dependencies must be object", value=data__dynamic__optionaldependencies, name="" + (name_prefix or "data") + ".dynamic.optional-dependencies", definition={'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, rule='type') - data__dynamic__optionaldependencies_is_dict = isinstance(data__dynamic__optionaldependencies, dict) - if data__dynamic__optionaldependencies_is_dict: - data__dynamic__optionaldependencies_keys = set(data__dynamic__optionaldependencies.keys()) - for data__dynamic__optionaldependencies_key, data__dynamic__optionaldependencies_val in data__dynamic__optionaldependencies.items(): - if REGEX_PATTERNS['.+'].search(data__dynamic__optionaldependencies_key): - if data__dynamic__optionaldependencies_key in data__dynamic__optionaldependencies_keys: - data__dynamic__optionaldependencies_keys.remove(data__dynamic__optionaldependencies_key) - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__optionaldependencies_val, custom_formats, (name_prefix or "data") + ".dynamic.optional-dependencies.{data__dynamic__optionaldependencies_key}") - if data__dynamic__optionaldependencies_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.optional-dependencies must not contain "+str(data__dynamic__optionaldependencies_keys)+" properties", value=data__dynamic__optionaldependencies, name="" + (name_prefix or "data") + ".dynamic.optional-dependencies", definition={'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, rule='additionalProperties') - data__dynamic__optionaldependencies_len = len(data__dynamic__optionaldependencies) - if data__dynamic__optionaldependencies_len != 0: - data__dynamic__optionaldependencies_property_names = True - for data__dynamic__optionaldependencies_key in data__dynamic__optionaldependencies: - try: - if isinstance(data__dynamic__optionaldependencies_key, str): - if not custom_formats["python-identifier"](data__dynamic__optionaldependencies_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.optional-dependencies must be python-identifier", value=data__dynamic__optionaldependencies_key, name="" + (name_prefix or "data") + ".dynamic.optional-dependencies", definition={'format': 'python-identifier'}, rule='format') - except JsonSchemaValueException: - data__dynamic__optionaldependencies_property_names = False - if not data__dynamic__optionaldependencies_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.optional-dependencies must be named by propertyName definition", value=data__dynamic__optionaldependencies, name="" + (name_prefix or "data") + ".dynamic.optional-dependencies", definition={'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, rule='propertyNames') - if "readme" in data__dynamic_keys: - data__dynamic_keys.remove("readme") - data__dynamic__readme = data__dynamic["readme"] - data__dynamic__readme_any_of_count6 = 0 - if not data__dynamic__readme_any_of_count6: - try: - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__readme, custom_formats, (name_prefix or "data") + ".dynamic.readme") - data__dynamic__readme_any_of_count6 += 1 - except JsonSchemaValueException: pass - if not data__dynamic__readme_any_of_count6: - try: - data__dynamic__readme_is_dict = isinstance(data__dynamic__readme, dict) - if data__dynamic__readme_is_dict: - data__dynamic__readme_keys = set(data__dynamic__readme.keys()) - if "content-type" in data__dynamic__readme_keys: - data__dynamic__readme_keys.remove("content-type") - data__dynamic__readme__contenttype = data__dynamic__readme["content-type"] - if not isinstance(data__dynamic__readme__contenttype, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.readme.content-type must be string", value=data__dynamic__readme__contenttype, name="" + (name_prefix or "data") + ".dynamic.readme.content-type", definition={'type': 'string'}, rule='type') - data__dynamic__readme_any_of_count6 += 1 - except JsonSchemaValueException: pass - if not data__dynamic__readme_any_of_count6: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.readme cannot be validated by any definition", value=data__dynamic__readme, name="" + (name_prefix or "data") + ".dynamic.readme", definition={'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}, rule='anyOf') - data__dynamic__readme_is_dict = isinstance(data__dynamic__readme, dict) - if data__dynamic__readme_is_dict: - data__dynamic__readme_len = len(data__dynamic__readme) - if not all(prop in data__dynamic__readme for prop in ['file']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.readme must contain ['file'] properties", value=data__dynamic__readme, name="" + (name_prefix or "data") + ".dynamic.readme", definition={'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}, rule='required') - if data__dynamic_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must not contain "+str(data__dynamic_keys)+" properties", value=data__dynamic, name="" + (name_prefix or "data") + ".dynamic", definition={'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, 'classifiers': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'description': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'dependencies': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'entry-points': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, 'readme': {'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}, rule='additionalProperties') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, 'classifiers': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'description': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'dependencies': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'entry-points': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, 'readme': {'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}, rule='additionalProperties') - return data - -def validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['file']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['file'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, rule='required') - data_keys = set(data.keys()) - if "file" in data_keys: - data_keys.remove("file") - data__file = data["file"] - data__file_one_of_count7 = 0 - if data__file_one_of_count7 < 2: - try: - if not isinstance(data__file, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".file must be string", value=data__file, name="" + (name_prefix or "data") + ".file", definition={'type': 'string'}, rule='type') - data__file_one_of_count7 += 1 - except JsonSchemaValueException: pass - if data__file_one_of_count7 < 2: - try: - if not isinstance(data__file, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".file must be array", value=data__file, name="" + (name_prefix or "data") + ".file", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__file_is_list = isinstance(data__file, (list, tuple)) - if data__file_is_list: - data__file_len = len(data__file) - for data__file_x, data__file_item in enumerate(data__file): - if not isinstance(data__file_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".file[{data__file_x}]".format(**locals()) + " must be string", value=data__file_item, name="" + (name_prefix or "data") + ".file[{data__file_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - data__file_one_of_count7 += 1 - except JsonSchemaValueException: pass - if data__file_one_of_count7 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".file must be valid exactly by one definition" + (" (" + str(data__file_one_of_count7) + " matches found)"), value=data__file, name="" + (name_prefix or "data") + ".file", definition={'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}, rule='oneOf') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, rule='additionalProperties') - return data - -def validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_attr_directive(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['attr']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['attr'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, rule='required') - data_keys = set(data.keys()) - if "attr" in data_keys: - data_keys.remove("attr") - data__attr = data["attr"] - if not isinstance(data__attr, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".attr must be string", value=data__attr, name="" + (name_prefix or "data") + ".attr", definition={'type': 'string'}, rule='type') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, rule='additionalProperties') - return data - -def validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_find_directive(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "find" in data_keys: - data_keys.remove("find") - data__find = data["find"] - if not isinstance(data__find, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find must be object", value=data__find, name="" + (name_prefix or "data") + ".find", definition={'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}, rule='type') - data__find_is_dict = isinstance(data__find, dict) - if data__find_is_dict: - data__find_keys = set(data__find.keys()) - if "where" in data__find_keys: - data__find_keys.remove("where") - data__find__where = data__find["where"] - if not isinstance(data__find__where, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.where must be array", value=data__find__where, name="" + (name_prefix or "data") + ".find.where", definition={'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__find__where_is_list = isinstance(data__find__where, (list, tuple)) - if data__find__where_is_list: - data__find__where_len = len(data__find__where) - for data__find__where_x, data__find__where_item in enumerate(data__find__where): - if not isinstance(data__find__where_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.where[{data__find__where_x}]".format(**locals()) + " must be string", value=data__find__where_item, name="" + (name_prefix or "data") + ".find.where[{data__find__where_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "exclude" in data__find_keys: - data__find_keys.remove("exclude") - data__find__exclude = data__find["exclude"] - if not isinstance(data__find__exclude, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.exclude must be array", value=data__find__exclude, name="" + (name_prefix or "data") + ".find.exclude", definition={'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, rule='type') - data__find__exclude_is_list = isinstance(data__find__exclude, (list, tuple)) - if data__find__exclude_is_list: - data__find__exclude_len = len(data__find__exclude) - for data__find__exclude_x, data__find__exclude_item in enumerate(data__find__exclude): - if not isinstance(data__find__exclude_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.exclude[{data__find__exclude_x}]".format(**locals()) + " must be string", value=data__find__exclude_item, name="" + (name_prefix or "data") + ".find.exclude[{data__find__exclude_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "include" in data__find_keys: - data__find_keys.remove("include") - data__find__include = data__find["include"] - if not isinstance(data__find__include, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.include must be array", value=data__find__include, name="" + (name_prefix or "data") + ".find.include", definition={'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, rule='type') - data__find__include_is_list = isinstance(data__find__include, (list, tuple)) - if data__find__include_is_list: - data__find__include_len = len(data__find__include) - for data__find__include_x, data__find__include_item in enumerate(data__find__include): - if not isinstance(data__find__include_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.include[{data__find__include_x}]".format(**locals()) + " must be string", value=data__find__include_item, name="" + (name_prefix or "data") + ".find.include[{data__find__include_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "namespaces" in data__find_keys: - data__find_keys.remove("namespaces") - data__find__namespaces = data__find["namespaces"] - if not isinstance(data__find__namespaces, (bool)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.namespaces must be boolean", value=data__find__namespaces, name="" + (name_prefix or "data") + ".find.namespaces", definition={'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}, rule='type') - if data__find_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find must not contain "+str(data__find_keys)+" properties", value=data__find, name="" + (name_prefix or "data") + ".find", definition={'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}, rule='additionalProperties') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}, rule='additionalProperties') - return data - -def validate_https___docs_python_org_3_install(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://docs.python.org/3/install/', 'title': '``tool.distutils`` table', '$$description': ['Originally, ``distutils`` allowed developers to configure arguments for', '``setup.py`` scripts via `distutils configuration files', '`_.', '``tool.distutils`` subtables could be used with the same purpose', '(NOT CURRENTLY IMPLEMENTED).'], 'type': 'object', 'properties': {'global': {'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}}, 'patternProperties': {'.+': {'type': 'object'}}, '$comment': 'TODO: Is there a practical way of making this schema more specific?'}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "global" in data_keys: - data_keys.remove("global") - data__global = data["global"] - if not isinstance(data__global, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".global must be object", value=data__global, name="" + (name_prefix or "data") + ".global", definition={'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}, rule='type') - for data_key, data_val in data.items(): - if REGEX_PATTERNS['.+'].search(data_key): - if data_key in data_keys: - data_keys.remove(data_key) - if not isinstance(data_val, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".{data_key}".format(**locals()) + " must be object", value=data_val, name="" + (name_prefix or "data") + ".{data_key}".format(**locals()) + "", definition={'type': 'object'}, rule='type') - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'gui-scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['name']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['name'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'gui-scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, rule='required') - data_keys = set(data.keys()) - if "name" in data_keys: - data_keys.remove("name") - data__name = data["name"] - if not isinstance(data__name, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".name must be string", value=data__name, name="" + (name_prefix or "data") + ".name", definition={'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, rule='type') - if isinstance(data__name, str): - if not custom_formats["pep508-identifier"](data__name): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".name must be pep508-identifier", value=data__name, name="" + (name_prefix or "data") + ".name", definition={'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, rule='format') - if "version" in data_keys: - data_keys.remove("version") - data__version = data["version"] - if not isinstance(data__version, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".version must be string", value=data__version, name="" + (name_prefix or "data") + ".version", definition={'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, rule='type') - if isinstance(data__version, str): - if not custom_formats["pep440"](data__version): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".version must be pep440", value=data__version, name="" + (name_prefix or "data") + ".version", definition={'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, rule='format') - if "description" in data_keys: - data_keys.remove("description") - data__description = data["description"] - if not isinstance(data__description, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".description must be string", value=data__description, name="" + (name_prefix or "data") + ".description", definition={'type': 'string', '$$description': ['The `summary description of the project', '`_']}, rule='type') - if "readme" in data_keys: - data_keys.remove("readme") - data__readme = data["readme"] - data__readme_one_of_count8 = 0 - if data__readme_one_of_count8 < 2: - try: - if not isinstance(data__readme, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must be string", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, rule='type') - data__readme_one_of_count8 += 1 - except JsonSchemaValueException: pass - if data__readme_one_of_count8 < 2: - try: - if not isinstance(data__readme, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must be object", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}, rule='type') - data__readme_any_of_count9 = 0 - if not data__readme_any_of_count9: - try: - data__readme_is_dict = isinstance(data__readme, dict) - if data__readme_is_dict: - data__readme_len = len(data__readme) - if not all(prop in data__readme for prop in ['file']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must contain ['file'] properties", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, rule='required') - data__readme_keys = set(data__readme.keys()) - if "file" in data__readme_keys: - data__readme_keys.remove("file") - data__readme__file = data__readme["file"] - if not isinstance(data__readme__file, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme.file must be string", value=data__readme__file, name="" + (name_prefix or "data") + ".readme.file", definition={'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}, rule='type') - data__readme_any_of_count9 += 1 - except JsonSchemaValueException: pass - if not data__readme_any_of_count9: - try: - data__readme_is_dict = isinstance(data__readme, dict) - if data__readme_is_dict: - data__readme_len = len(data__readme) - if not all(prop in data__readme for prop in ['text']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must contain ['text'] properties", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}, rule='required') - data__readme_keys = set(data__readme.keys()) - if "text" in data__readme_keys: - data__readme_keys.remove("text") - data__readme__text = data__readme["text"] - if not isinstance(data__readme__text, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme.text must be string", value=data__readme__text, name="" + (name_prefix or "data") + ".readme.text", definition={'type': 'string', 'description': 'Full text describing the project.'}, rule='type') - data__readme_any_of_count9 += 1 - except JsonSchemaValueException: pass - if not data__readme_any_of_count9: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme cannot be validated by any definition", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, rule='anyOf') - data__readme_is_dict = isinstance(data__readme, dict) - if data__readme_is_dict: - data__readme_len = len(data__readme) - if not all(prop in data__readme for prop in ['content-type']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must contain ['content-type'] properties", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}, rule='required') - data__readme_keys = set(data__readme.keys()) - if "content-type" in data__readme_keys: - data__readme_keys.remove("content-type") - data__readme__contenttype = data__readme["content-type"] - if not isinstance(data__readme__contenttype, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme.content-type must be string", value=data__readme__contenttype, name="" + (name_prefix or "data") + ".readme.content-type", definition={'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}, rule='type') - data__readme_one_of_count8 += 1 - except JsonSchemaValueException: pass - if data__readme_one_of_count8 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must be valid exactly by one definition" + (" (" + str(data__readme_one_of_count8) + " matches found)"), value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, rule='oneOf') - if "requires-python" in data_keys: - data_keys.remove("requires-python") - data__requirespython = data["requires-python"] - if not isinstance(data__requirespython, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".requires-python must be string", value=data__requirespython, name="" + (name_prefix or "data") + ".requires-python", definition={'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, rule='type') - if isinstance(data__requirespython, str): - if not custom_formats["pep508-versionspec"](data__requirespython): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".requires-python must be pep508-versionspec", value=data__requirespython, name="" + (name_prefix or "data") + ".requires-python", definition={'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, rule='format') - if "license" in data_keys: - data_keys.remove("license") - data__license = data["license"] - data__license_one_of_count10 = 0 - if data__license_one_of_count10 < 2: - try: - data__license_is_dict = isinstance(data__license, dict) - if data__license_is_dict: - data__license_len = len(data__license) - if not all(prop in data__license for prop in ['file']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license must contain ['file'] properties", value=data__license, name="" + (name_prefix or "data") + ".license", definition={'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, rule='required') - data__license_keys = set(data__license.keys()) - if "file" in data__license_keys: - data__license_keys.remove("file") - data__license__file = data__license["file"] - if not isinstance(data__license__file, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license.file must be string", value=data__license__file, name="" + (name_prefix or "data") + ".license.file", definition={'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}, rule='type') - data__license_one_of_count10 += 1 - except JsonSchemaValueException: pass - if data__license_one_of_count10 < 2: - try: - data__license_is_dict = isinstance(data__license, dict) - if data__license_is_dict: - data__license_len = len(data__license) - if not all(prop in data__license for prop in ['text']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license must contain ['text'] properties", value=data__license, name="" + (name_prefix or "data") + ".license", definition={'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}, rule='required') - data__license_keys = set(data__license.keys()) - if "text" in data__license_keys: - data__license_keys.remove("text") - data__license__text = data__license["text"] - if not isinstance(data__license__text, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license.text must be string", value=data__license__text, name="" + (name_prefix or "data") + ".license.text", definition={'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}, rule='type') - data__license_one_of_count10 += 1 - except JsonSchemaValueException: pass - if data__license_one_of_count10 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license must be valid exactly by one definition" + (" (" + str(data__license_one_of_count10) + " matches found)"), value=data__license, name="" + (name_prefix or "data") + ".license", definition={'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, rule='oneOf') - if "authors" in data_keys: - data_keys.remove("authors") - data__authors = data["authors"] - if not isinstance(data__authors, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".authors must be array", value=data__authors, name="" + (name_prefix or "data") + ".authors", definition={'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, rule='type') - data__authors_is_list = isinstance(data__authors, (list, tuple)) - if data__authors_is_list: - data__authors_len = len(data__authors) - for data__authors_x, data__authors_item in enumerate(data__authors): - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_author(data__authors_item, custom_formats, (name_prefix or "data") + ".authors[{data__authors_x}]") - if "maintainers" in data_keys: - data_keys.remove("maintainers") - data__maintainers = data["maintainers"] - if not isinstance(data__maintainers, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".maintainers must be array", value=data__maintainers, name="" + (name_prefix or "data") + ".maintainers", definition={'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, rule='type') - data__maintainers_is_list = isinstance(data__maintainers, (list, tuple)) - if data__maintainers_is_list: - data__maintainers_len = len(data__maintainers) - for data__maintainers_x, data__maintainers_item in enumerate(data__maintainers): - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_author(data__maintainers_item, custom_formats, (name_prefix or "data") + ".maintainers[{data__maintainers_x}]") - if "keywords" in data_keys: - data_keys.remove("keywords") - data__keywords = data["keywords"] - if not isinstance(data__keywords, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".keywords must be array", value=data__keywords, name="" + (name_prefix or "data") + ".keywords", definition={'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, rule='type') - data__keywords_is_list = isinstance(data__keywords, (list, tuple)) - if data__keywords_is_list: - data__keywords_len = len(data__keywords) - for data__keywords_x, data__keywords_item in enumerate(data__keywords): - if not isinstance(data__keywords_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".keywords[{data__keywords_x}]".format(**locals()) + " must be string", value=data__keywords_item, name="" + (name_prefix or "data") + ".keywords[{data__keywords_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "classifiers" in data_keys: - data_keys.remove("classifiers") - data__classifiers = data["classifiers"] - if not isinstance(data__classifiers, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".classifiers must be array", value=data__classifiers, name="" + (name_prefix or "data") + ".classifiers", definition={'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, rule='type') - data__classifiers_is_list = isinstance(data__classifiers, (list, tuple)) - if data__classifiers_is_list: - data__classifiers_len = len(data__classifiers) - for data__classifiers_x, data__classifiers_item in enumerate(data__classifiers): - if not isinstance(data__classifiers_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".classifiers[{data__classifiers_x}]".format(**locals()) + " must be string", value=data__classifiers_item, name="" + (name_prefix or "data") + ".classifiers[{data__classifiers_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, rule='type') - if isinstance(data__classifiers_item, str): - if not custom_formats["trove-classifier"](data__classifiers_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".classifiers[{data__classifiers_x}]".format(**locals()) + " must be trove-classifier", value=data__classifiers_item, name="" + (name_prefix or "data") + ".classifiers[{data__classifiers_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, rule='format') - if "urls" in data_keys: - data_keys.remove("urls") - data__urls = data["urls"] - if not isinstance(data__urls, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".urls must be object", value=data__urls, name="" + (name_prefix or "data") + ".urls", definition={'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, rule='type') - data__urls_is_dict = isinstance(data__urls, dict) - if data__urls_is_dict: - data__urls_keys = set(data__urls.keys()) - for data__urls_key, data__urls_val in data__urls.items(): - if REGEX_PATTERNS['^.+$'].search(data__urls_key): - if data__urls_key in data__urls_keys: - data__urls_keys.remove(data__urls_key) - if not isinstance(data__urls_val, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".urls.{data__urls_key}".format(**locals()) + " must be string", value=data__urls_val, name="" + (name_prefix or "data") + ".urls.{data__urls_key}".format(**locals()) + "", definition={'type': 'string', 'format': 'url'}, rule='type') - if isinstance(data__urls_val, str): - if not custom_formats["url"](data__urls_val): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".urls.{data__urls_key}".format(**locals()) + " must be url", value=data__urls_val, name="" + (name_prefix or "data") + ".urls.{data__urls_key}".format(**locals()) + "", definition={'type': 'string', 'format': 'url'}, rule='format') - if data__urls_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".urls must not contain "+str(data__urls_keys)+" properties", value=data__urls, name="" + (name_prefix or "data") + ".urls", definition={'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, rule='additionalProperties') - if "scripts" in data_keys: - data_keys.remove("scripts") - data__scripts = data["scripts"] - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_entry_point_group(data__scripts, custom_formats, (name_prefix or "data") + ".scripts") - if "gui-scripts" in data_keys: - data_keys.remove("gui-scripts") - data__guiscripts = data["gui-scripts"] - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_entry_point_group(data__guiscripts, custom_formats, (name_prefix or "data") + ".gui-scripts") - if "entry-points" in data_keys: - data_keys.remove("entry-points") - data__entrypoints = data["entry-points"] - data__entrypoints_is_dict = isinstance(data__entrypoints, dict) - if data__entrypoints_is_dict: - data__entrypoints_keys = set(data__entrypoints.keys()) - for data__entrypoints_key, data__entrypoints_val in data__entrypoints.items(): - if REGEX_PATTERNS['^.+$'].search(data__entrypoints_key): - if data__entrypoints_key in data__entrypoints_keys: - data__entrypoints_keys.remove(data__entrypoints_key) - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_entry_point_group(data__entrypoints_val, custom_formats, (name_prefix or "data") + ".entry-points.{data__entrypoints_key}") - if data__entrypoints_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".entry-points must not contain "+str(data__entrypoints_keys)+" properties", value=data__entrypoints, name="" + (name_prefix or "data") + ".entry-points", definition={'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, rule='additionalProperties') - data__entrypoints_len = len(data__entrypoints) - if data__entrypoints_len != 0: - data__entrypoints_property_names = True - for data__entrypoints_key in data__entrypoints: - try: - if isinstance(data__entrypoints_key, str): - if not custom_formats["python-entrypoint-group"](data__entrypoints_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".entry-points must be python-entrypoint-group", value=data__entrypoints_key, name="" + (name_prefix or "data") + ".entry-points", definition={'format': 'python-entrypoint-group'}, rule='format') - except JsonSchemaValueException: - data__entrypoints_property_names = False - if not data__entrypoints_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".entry-points must be named by propertyName definition", value=data__entrypoints, name="" + (name_prefix or "data") + ".entry-points", definition={'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, rule='propertyNames') - if "dependencies" in data_keys: - data_keys.remove("dependencies") - data__dependencies = data["dependencies"] - if not isinstance(data__dependencies, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dependencies must be array", value=data__dependencies, name="" + (name_prefix or "data") + ".dependencies", definition={'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, rule='type') - data__dependencies_is_list = isinstance(data__dependencies, (list, tuple)) - if data__dependencies_is_list: - data__dependencies_len = len(data__dependencies) - for data__dependencies_x, data__dependencies_item in enumerate(data__dependencies): - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_dependency(data__dependencies_item, custom_formats, (name_prefix or "data") + ".dependencies[{data__dependencies_x}]") - if "optional-dependencies" in data_keys: - data_keys.remove("optional-dependencies") - data__optionaldependencies = data["optional-dependencies"] - if not isinstance(data__optionaldependencies, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies must be object", value=data__optionaldependencies, name="" + (name_prefix or "data") + ".optional-dependencies", definition={'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='type') - data__optionaldependencies_is_dict = isinstance(data__optionaldependencies, dict) - if data__optionaldependencies_is_dict: - data__optionaldependencies_keys = set(data__optionaldependencies.keys()) - for data__optionaldependencies_key, data__optionaldependencies_val in data__optionaldependencies.items(): - if REGEX_PATTERNS['^.+$'].search(data__optionaldependencies_key): - if data__optionaldependencies_key in data__optionaldependencies_keys: - data__optionaldependencies_keys.remove(data__optionaldependencies_key) - if not isinstance(data__optionaldependencies_val, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies.{data__optionaldependencies_key}".format(**locals()) + " must be array", value=data__optionaldependencies_val, name="" + (name_prefix or "data") + ".optional-dependencies.{data__optionaldependencies_key}".format(**locals()) + "", definition={'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, rule='type') - data__optionaldependencies_val_is_list = isinstance(data__optionaldependencies_val, (list, tuple)) - if data__optionaldependencies_val_is_list: - data__optionaldependencies_val_len = len(data__optionaldependencies_val) - for data__optionaldependencies_val_x, data__optionaldependencies_val_item in enumerate(data__optionaldependencies_val): - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_dependency(data__optionaldependencies_val_item, custom_formats, (name_prefix or "data") + ".optional-dependencies.{data__optionaldependencies_key}[{data__optionaldependencies_val_x}]") - if data__optionaldependencies_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies must not contain "+str(data__optionaldependencies_keys)+" properties", value=data__optionaldependencies, name="" + (name_prefix or "data") + ".optional-dependencies", definition={'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='additionalProperties') - data__optionaldependencies_len = len(data__optionaldependencies) - if data__optionaldependencies_len != 0: - data__optionaldependencies_property_names = True - for data__optionaldependencies_key in data__optionaldependencies: - try: - if isinstance(data__optionaldependencies_key, str): - if not custom_formats["pep508-identifier"](data__optionaldependencies_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies must be pep508-identifier", value=data__optionaldependencies_key, name="" + (name_prefix or "data") + ".optional-dependencies", definition={'format': 'pep508-identifier'}, rule='format') - except JsonSchemaValueException: - data__optionaldependencies_property_names = False - if not data__optionaldependencies_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies must be named by propertyName definition", value=data__optionaldependencies, name="" + (name_prefix or "data") + ".optional-dependencies", definition={'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='propertyNames') - if "dynamic" in data_keys: - data_keys.remove("dynamic") - data__dynamic = data["dynamic"] - if not isinstance(data__dynamic, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must be array", value=data__dynamic, name="" + (name_prefix or "data") + ".dynamic", definition={'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}, rule='type') - data__dynamic_is_list = isinstance(data__dynamic, (list, tuple)) - if data__dynamic_is_list: - data__dynamic_len = len(data__dynamic) - for data__dynamic_x, data__dynamic_item in enumerate(data__dynamic): - if data__dynamic_item not in ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic[{data__dynamic_x}]".format(**locals()) + " must be one of ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']", value=data__dynamic_item, name="" + (name_prefix or "data") + ".dynamic[{data__dynamic_x}]".format(**locals()) + "", definition={'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}, rule='enum') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'gui-scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, rule='additionalProperties') - try: - try: - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['dynamic']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['dynamic'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, rule='required') - data_keys = set(data.keys()) - if "dynamic" in data_keys: - data_keys.remove("dynamic") - data__dynamic = data["dynamic"] - data__dynamic_is_list = isinstance(data__dynamic, (list, tuple)) - if data__dynamic_is_list: - data__dynamic_contains = False - for data__dynamic_key in data__dynamic: - try: - if data__dynamic_key != "version": - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must be same as const definition: version", value=data__dynamic_key, name="" + (name_prefix or "data") + ".dynamic", definition={'const': 'version'}, rule='const') - data__dynamic_contains = True - break - except JsonSchemaValueException: pass - if not data__dynamic_contains: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must contain one of contains definition", value=data__dynamic, name="" + (name_prefix or "data") + ".dynamic", definition={'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}, rule='contains') - except JsonSchemaValueException: pass - else: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must NOT match a disallowed definition", value=data, name="" + (name_prefix or "data") + "", definition={'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, rule='not') - except JsonSchemaValueException: - pass - else: - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['version']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['version'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, rule='required') - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_dependency(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be string", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}, rule='type') - if isinstance(data, str): - if not custom_formats["pep508"](data): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be pep508", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}, rule='format') - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_entry_point_group(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - for data_key, data_val in data.items(): - if REGEX_PATTERNS['^.+$'].search(data_key): - if data_key in data_keys: - data_keys.remove(data_key) - if not isinstance(data_val, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".{data_key}".format(**locals()) + " must be string", value=data_val, name="" + (name_prefix or "data") + ".{data_key}".format(**locals()) + "", definition={'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}, rule='type') - if isinstance(data_val, str): - if not custom_formats["python-entrypoint-reference"](data_val): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".{data_key}".format(**locals()) + " must be python-entrypoint-reference", value=data_val, name="" + (name_prefix or "data") + ".{data_key}".format(**locals()) + "", definition={'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}, rule='format') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, rule='additionalProperties') - data_len = len(data) - if data_len != 0: - data_property_names = True - for data_key in data: - try: - if isinstance(data_key, str): - if not custom_formats["python-entrypoint-name"](data_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be python-entrypoint-name", value=data_key, name="" + (name_prefix or "data") + "", definition={'format': 'python-entrypoint-name'}, rule='format') - except JsonSchemaValueException: - data_property_names = False - if not data_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be named by propertyName definition", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, rule='propertyNames') - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_author(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "name" in data_keys: - data_keys.remove("name") - data__name = data["name"] - if not isinstance(data__name, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".name must be string", value=data__name, name="" + (name_prefix or "data") + ".name", definition={'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, rule='type') - if "email" in data_keys: - data_keys.remove("email") - data__email = data["email"] - if not isinstance(data__email, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".email must be string", value=data__email, name="" + (name_prefix or "data") + ".email", definition={'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}, rule='type') - if isinstance(data__email, str): - if not REGEX_PATTERNS["idn-email_re_pattern"].match(data__email): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".email must be idn-email", value=data__email, name="" + (name_prefix or "data") + ".email", definition={'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}, rule='format') - return data \ No newline at end of file diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/formats.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/formats.py deleted file mode 100755 index 638ac11..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/formats.py +++ /dev/null @@ -1,259 +0,0 @@ -import logging -import os -import re -import string -import typing -from itertools import chain as _chain - -_logger = logging.getLogger(__name__) - -# ------------------------------------------------------------------------------------- -# PEP 440 - -VERSION_PATTERN = r""" - v? - (?: - (?:(?P[0-9]+)!)? # epoch - (?P[0-9]+(?:\.[0-9]+)*) # release segment - (?P

                                          # pre-release
-            [-_\.]?
-            (?P(a|b|c|rc|alpha|beta|pre|preview))
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-        (?P                                         # post release
-            (?:-(?P[0-9]+))
-            |
-            (?:
-                [-_\.]?
-                (?Ppost|rev|r)
-                [-_\.]?
-                (?P[0-9]+)?
-            )
-        )?
-        (?P                                          # dev release
-            [-_\.]?
-            (?Pdev)
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-    )
-    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
-"""
-
-VERSION_REGEX = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.X | re.I)
-
-
-def pep440(version: str) -> bool:
-    return VERSION_REGEX.match(version) is not None
-
-
-# -------------------------------------------------------------------------------------
-# PEP 508
-
-PEP508_IDENTIFIER_PATTERN = r"([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])"
-PEP508_IDENTIFIER_REGEX = re.compile(f"^{PEP508_IDENTIFIER_PATTERN}$", re.I)
-
-
-def pep508_identifier(name: str) -> bool:
-    return PEP508_IDENTIFIER_REGEX.match(name) is not None
-
-
-try:
-    try:
-        from packaging import requirements as _req
-    except ImportError:  # pragma: no cover
-        # let's try setuptools vendored version
-        from setuptools._vendor.packaging import requirements as _req  # type: ignore
-
-    def pep508(value: str) -> bool:
-        try:
-            _req.Requirement(value)
-            return True
-        except _req.InvalidRequirement:
-            return False
-
-except ImportError:  # pragma: no cover
-    _logger.warning(
-        "Could not find an installation of `packaging`. Requirements, dependencies and "
-        "versions might not be validated. "
-        "To enforce validation, please install `packaging`."
-    )
-
-    def pep508(value: str) -> bool:
-        return True
-
-
-def pep508_versionspec(value: str) -> bool:
-    """Expression that can be used to specify/lock versions (including ranges)"""
-    if any(c in value for c in (";", "]", "@")):
-        # In PEP 508:
-        # conditional markers, extras and URL specs are not included in the
-        # versionspec
-        return False
-    # Let's pretend we have a dependency called `requirement` with the given
-    # version spec, then we can re-use the pep508 function for validation:
-    return pep508(f"requirement{value}")
-
-
-# -------------------------------------------------------------------------------------
-# PEP 517
-
-
-def pep517_backend_reference(value: str) -> bool:
-    module, _, obj = value.partition(":")
-    identifiers = (i.strip() for i in _chain(module.split("."), obj.split(".")))
-    return all(python_identifier(i) for i in identifiers if i)
-
-
-# -------------------------------------------------------------------------------------
-# Classifiers - PEP 301
-
-
-def _download_classifiers() -> str:
-    import ssl
-    from email.message import Message
-    from urllib.request import urlopen
-
-    url = "https://pypi.org/pypi?:action=list_classifiers"
-    context = ssl.create_default_context()
-    with urlopen(url, context=context) as response:
-        headers = Message()
-        headers["content_type"] = response.getheader("content-type", "text/plain")
-        return response.read().decode(headers.get_param("charset", "utf-8"))
-
-
-class _TroveClassifier:
-    """The ``trove_classifiers`` package is the official way of validating classifiers,
-    however this package might not be always available.
-    As a workaround we can still download a list from PyPI.
-    We also don't want to be over strict about it, so simply skipping silently is an
-    option (classifiers will be validated anyway during the upload to PyPI).
-    """
-
-    def __init__(self):
-        self.downloaded: typing.Union[None, False, typing.Set[str]] = None
-        self._skip_download = False
-        # None => not cached yet
-        # False => cache not available
-        self.__name__ = "trove_classifier"  # Emulate a public function
-
-    def _disable_download(self):
-        # This is a private API. Only setuptools has the consent of using it.
-        self._skip_download = True
-
-    def __call__(self, value: str) -> bool:
-        if self.downloaded is False or self._skip_download is True:
-            return True
-
-        if os.getenv("NO_NETWORK") or os.getenv("VALIDATE_PYPROJECT_NO_NETWORK"):
-            self.downloaded = False
-            msg = (
-                "Install ``trove-classifiers`` to ensure proper validation. "
-                "Skipping download of classifiers list from PyPI (NO_NETWORK)."
-            )
-            _logger.debug(msg)
-            return True
-
-        if self.downloaded is None:
-            msg = (
-                "Install ``trove-classifiers`` to ensure proper validation. "
-                "Meanwhile a list of classifiers will be downloaded from PyPI."
-            )
-            _logger.debug(msg)
-            try:
-                self.downloaded = set(_download_classifiers().splitlines())
-            except Exception:
-                self.downloaded = False
-                _logger.debug("Problem with download, skipping validation")
-                return True
-
-        return value in self.downloaded or value.lower().startswith("private ::")
-
-
-try:
-    from trove_classifiers import classifiers as _trove_classifiers
-
-    def trove_classifier(value: str) -> bool:
-        return value in _trove_classifiers or value.lower().startswith("private ::")
-
-except ImportError:  # pragma: no cover
-    trove_classifier = _TroveClassifier()
-
-
-# -------------------------------------------------------------------------------------
-# Non-PEP related
-
-
-def url(value: str) -> bool:
-    from urllib.parse import urlparse
-
-    try:
-        parts = urlparse(value)
-        if not parts.scheme:
-            _logger.warning(
-                "For maximum compatibility please make sure to include a "
-                "`scheme` prefix in your URL (e.g. 'http://'). "
-                f"Given value: {value}"
-            )
-            if not (value.startswith("/") or value.startswith("\\") or "@" in value):
-                parts = urlparse(f"http://{value}")
-
-        return bool(parts.scheme and parts.netloc)
-    except Exception:
-        return False
-
-
-# https://packaging.python.org/specifications/entry-points/
-ENTRYPOINT_PATTERN = r"[^\[\s=]([^=]*[^\s=])?"
-ENTRYPOINT_REGEX = re.compile(f"^{ENTRYPOINT_PATTERN}$", re.I)
-RECOMMEDED_ENTRYPOINT_PATTERN = r"[\w.-]+"
-RECOMMEDED_ENTRYPOINT_REGEX = re.compile(f"^{RECOMMEDED_ENTRYPOINT_PATTERN}$", re.I)
-ENTRYPOINT_GROUP_PATTERN = r"\w+(\.\w+)*"
-ENTRYPOINT_GROUP_REGEX = re.compile(f"^{ENTRYPOINT_GROUP_PATTERN}$", re.I)
-
-
-def python_identifier(value: str) -> bool:
-    return value.isidentifier()
-
-
-def python_qualified_identifier(value: str) -> bool:
-    if value.startswith(".") or value.endswith("."):
-        return False
-    return all(python_identifier(m) for m in value.split("."))
-
-
-def python_module_name(value: str) -> bool:
-    return python_qualified_identifier(value)
-
-
-def python_entrypoint_group(value: str) -> bool:
-    return ENTRYPOINT_GROUP_REGEX.match(value) is not None
-
-
-def python_entrypoint_name(value: str) -> bool:
-    if not ENTRYPOINT_REGEX.match(value):
-        return False
-    if not RECOMMEDED_ENTRYPOINT_REGEX.match(value):
-        msg = f"Entry point `{value}` does not follow recommended pattern: "
-        msg += RECOMMEDED_ENTRYPOINT_PATTERN
-        _logger.warning(msg)
-    return True
-
-
-def python_entrypoint_reference(value: str) -> bool:
-    module, _, rest = value.partition(":")
-    if "[" in rest:
-        obj, _, extras_ = rest.partition("[")
-        if extras_.strip()[-1] != "]":
-            return False
-        extras = (x.strip() for x in extras_.strip(string.whitespace + "[]").split(","))
-        if not all(pep508_identifier(e) for e in extras):
-            return False
-        _logger.warning(f"`{value}` - using extras for entry points is not recommended")
-    else:
-        obj = rest
-
-    module_parts = module.split(".")
-    identifiers = _chain(module_parts, obj.split(".")) if rest else module_parts
-    return all(python_identifier(i.strip()) for i in identifiers)
diff --git a/venv/lib/python3.11/site-packages/setuptools/config/expand.py b/venv/lib/python3.11/site-packages/setuptools/config/expand.py
deleted file mode 100755
index c8db2c4..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/config/expand.py
+++ /dev/null
@@ -1,462 +0,0 @@
-"""Utility functions to expand configuration directives or special values
-(such glob patterns).
-
-We can split the process of interpreting configuration files into 2 steps:
-
-1. The parsing the file contents from strings to value objects
-   that can be understand by Python (for example a string with a comma
-   separated list of keywords into an actual Python list of strings).
-
-2. The expansion (or post-processing) of these values according to the
-   semantics ``setuptools`` assign to them (for example a configuration field
-   with the ``file:`` directive should be expanded from a list of file paths to
-   a single string with the contents of those files concatenated)
-
-This module focus on the second step, and therefore allow sharing the expansion
-functions among several configuration file formats.
-
-**PRIVATE MODULE**: API reserved for setuptools internal usage only.
-"""
-import ast
-import importlib
-import io
-import os
-import pathlib
-import sys
-import warnings
-from glob import iglob
-from configparser import ConfigParser
-from importlib.machinery import ModuleSpec
-from itertools import chain
-from typing import (
-    TYPE_CHECKING,
-    Callable,
-    Dict,
-    Iterable,
-    Iterator,
-    List,
-    Mapping,
-    Optional,
-    Tuple,
-    TypeVar,
-    Union,
-    cast
-)
-from pathlib import Path
-from types import ModuleType
-
-from distutils.errors import DistutilsOptionError
-
-from .._path import same_path as _same_path
-
-if TYPE_CHECKING:
-    from setuptools.dist import Distribution  # noqa
-    from setuptools.discovery import ConfigDiscovery  # noqa
-    from distutils.dist import DistributionMetadata  # noqa
-
-chain_iter = chain.from_iterable
-_Path = Union[str, os.PathLike]
-_K = TypeVar("_K")
-_V = TypeVar("_V", covariant=True)
-
-
-class StaticModule:
-    """Proxy to a module object that avoids executing arbitrary code."""
-
-    def __init__(self, name: str, spec: ModuleSpec):
-        module = ast.parse(pathlib.Path(spec.origin).read_bytes())
-        vars(self).update(locals())
-        del self.self
-
-    def _find_assignments(self) -> Iterator[Tuple[ast.AST, ast.AST]]:
-        for statement in self.module.body:
-            if isinstance(statement, ast.Assign):
-                yield from ((target, statement.value) for target in statement.targets)
-            elif isinstance(statement, ast.AnnAssign) and statement.value:
-                yield (statement.target, statement.value)
-
-    def __getattr__(self, attr):
-        """Attempt to load an attribute "statically", via :func:`ast.literal_eval`."""
-        try:
-            return next(
-                ast.literal_eval(value)
-                for target, value in self._find_assignments()
-                if isinstance(target, ast.Name) and target.id == attr
-            )
-        except Exception as e:
-            raise AttributeError(f"{self.name} has no attribute {attr}") from e
-
-
-def glob_relative(
-    patterns: Iterable[str], root_dir: Optional[_Path] = None
-) -> List[str]:
-    """Expand the list of glob patterns, but preserving relative paths.
-
-    :param list[str] patterns: List of glob patterns
-    :param str root_dir: Path to which globs should be relative
-                         (current directory by default)
-    :rtype: list
-    """
-    glob_characters = {'*', '?', '[', ']', '{', '}'}
-    expanded_values = []
-    root_dir = root_dir or os.getcwd()
-    for value in patterns:
-
-        # Has globby characters?
-        if any(char in value for char in glob_characters):
-            # then expand the glob pattern while keeping paths *relative*:
-            glob_path = os.path.abspath(os.path.join(root_dir, value))
-            expanded_values.extend(sorted(
-                os.path.relpath(path, root_dir).replace(os.sep, "/")
-                for path in iglob(glob_path, recursive=True)))
-
-        else:
-            # take the value as-is
-            path = os.path.relpath(value, root_dir).replace(os.sep, "/")
-            expanded_values.append(path)
-
-    return expanded_values
-
-
-def read_files(filepaths: Union[str, bytes, Iterable[_Path]], root_dir=None) -> str:
-    """Return the content of the files concatenated using ``\n`` as str
-
-    This function is sandboxed and won't reach anything outside ``root_dir``
-
-    (By default ``root_dir`` is the current directory).
-    """
-    from setuptools.extern.more_itertools import always_iterable
-
-    root_dir = os.path.abspath(root_dir or os.getcwd())
-    _filepaths = (os.path.join(root_dir, path) for path in always_iterable(filepaths))
-    return '\n'.join(
-        _read_file(path)
-        for path in _filter_existing_files(_filepaths)
-        if _assert_local(path, root_dir)
-    )
-
-
-def _filter_existing_files(filepaths: Iterable[_Path]) -> Iterator[_Path]:
-    for path in filepaths:
-        if os.path.isfile(path):
-            yield path
-        else:
-            warnings.warn(f"File {path!r} cannot be found")
-
-
-def _read_file(filepath: Union[bytes, _Path]) -> str:
-    with io.open(filepath, encoding='utf-8') as f:
-        return f.read()
-
-
-def _assert_local(filepath: _Path, root_dir: str):
-    if Path(os.path.abspath(root_dir)) not in Path(os.path.abspath(filepath)).parents:
-        msg = f"Cannot access {filepath!r} (or anything outside {root_dir!r})"
-        raise DistutilsOptionError(msg)
-
-    return True
-
-
-def read_attr(
-    attr_desc: str,
-    package_dir: Optional[Mapping[str, str]] = None,
-    root_dir: Optional[_Path] = None
-):
-    """Reads the value of an attribute from a module.
-
-    This function will try to read the attributed statically first
-    (via :func:`ast.literal_eval`), and only evaluate the module if it fails.
-
-    Examples:
-        read_attr("package.attr")
-        read_attr("package.module.attr")
-
-    :param str attr_desc: Dot-separated string describing how to reach the
-        attribute (see examples above)
-    :param dict[str, str] package_dir: Mapping of package names to their
-        location in disk (represented by paths relative to ``root_dir``).
-    :param str root_dir: Path to directory containing all the packages in
-        ``package_dir`` (current directory by default).
-    :rtype: str
-    """
-    root_dir = root_dir or os.getcwd()
-    attrs_path = attr_desc.strip().split('.')
-    attr_name = attrs_path.pop()
-    module_name = '.'.join(attrs_path)
-    module_name = module_name or '__init__'
-    _parent_path, path, module_name = _find_module(module_name, package_dir, root_dir)
-    spec = _find_spec(module_name, path)
-
-    try:
-        return getattr(StaticModule(module_name, spec), attr_name)
-    except Exception:
-        # fallback to evaluate module
-        module = _load_spec(spec, module_name)
-        return getattr(module, attr_name)
-
-
-def _find_spec(module_name: str, module_path: Optional[_Path]) -> ModuleSpec:
-    spec = importlib.util.spec_from_file_location(module_name, module_path)
-    spec = spec or importlib.util.find_spec(module_name)
-
-    if spec is None:
-        raise ModuleNotFoundError(module_name)
-
-    return spec
-
-
-def _load_spec(spec: ModuleSpec, module_name: str) -> ModuleType:
-    name = getattr(spec, "__name__", module_name)
-    if name in sys.modules:
-        return sys.modules[name]
-    module = importlib.util.module_from_spec(spec)
-    sys.modules[name] = module  # cache (it also ensures `==` works on loaded items)
-    spec.loader.exec_module(module)  # type: ignore
-    return module
-
-
-def _find_module(
-    module_name: str, package_dir: Optional[Mapping[str, str]], root_dir: _Path
-) -> Tuple[_Path, Optional[str], str]:
-    """Given a module (that could normally be imported by ``module_name``
-    after the build is complete), find the path to the parent directory where
-    it is contained and the canonical name that could be used to import it
-    considering the ``package_dir`` in the build configuration and ``root_dir``
-    """
-    parent_path = root_dir
-    module_parts = module_name.split('.')
-    if package_dir:
-        if module_parts[0] in package_dir:
-            # A custom path was specified for the module we want to import
-            custom_path = package_dir[module_parts[0]]
-            parts = custom_path.rsplit('/', 1)
-            if len(parts) > 1:
-                parent_path = os.path.join(root_dir, parts[0])
-                parent_module = parts[1]
-            else:
-                parent_module = custom_path
-            module_name = ".".join([parent_module, *module_parts[1:]])
-        elif '' in package_dir:
-            # A custom parent directory was specified for all root modules
-            parent_path = os.path.join(root_dir, package_dir[''])
-
-    path_start = os.path.join(parent_path, *module_name.split("."))
-    candidates = chain(
-        (f"{path_start}.py", os.path.join(path_start, "__init__.py")),
-        iglob(f"{path_start}.*")
-    )
-    module_path = next((x for x in candidates if os.path.isfile(x)), None)
-    return parent_path, module_path, module_name
-
-
-def resolve_class(
-    qualified_class_name: str,
-    package_dir: Optional[Mapping[str, str]] = None,
-    root_dir: Optional[_Path] = None
-) -> Callable:
-    """Given a qualified class name, return the associated class object"""
-    root_dir = root_dir or os.getcwd()
-    idx = qualified_class_name.rfind('.')
-    class_name = qualified_class_name[idx + 1 :]
-    pkg_name = qualified_class_name[:idx]
-
-    _parent_path, path, module_name = _find_module(pkg_name, package_dir, root_dir)
-    module = _load_spec(_find_spec(module_name, path), module_name)
-    return getattr(module, class_name)
-
-
-def cmdclass(
-    values: Dict[str, str],
-    package_dir: Optional[Mapping[str, str]] = None,
-    root_dir: Optional[_Path] = None
-) -> Dict[str, Callable]:
-    """Given a dictionary mapping command names to strings for qualified class
-    names, apply :func:`resolve_class` to the dict values.
-    """
-    return {k: resolve_class(v, package_dir, root_dir) for k, v in values.items()}
-
-
-def find_packages(
-    *,
-    namespaces=True,
-    fill_package_dir: Optional[Dict[str, str]] = None,
-    root_dir: Optional[_Path] = None,
-    **kwargs
-) -> List[str]:
-    """Works similarly to :func:`setuptools.find_packages`, but with all
-    arguments given as keyword arguments. Moreover, ``where`` can be given
-    as a list (the results will be simply concatenated).
-
-    When the additional keyword argument ``namespaces`` is ``True``, it will
-    behave like :func:`setuptools.find_namespace_packages`` (i.e. include
-    implicit namespaces as per :pep:`420`).
-
-    The ``where`` argument will be considered relative to ``root_dir`` (or the current
-    working directory when ``root_dir`` is not given).
-
-    If the ``fill_package_dir`` argument is passed, this function will consider it as a
-    similar data structure to the ``package_dir`` configuration parameter add fill-in
-    any missing package location.
-
-    :rtype: list
-    """
-    from setuptools.discovery import construct_package_dir
-    from setuptools.extern.more_itertools import unique_everseen, always_iterable
-
-    if namespaces:
-        from setuptools.discovery import PEP420PackageFinder as PackageFinder
-    else:
-        from setuptools.discovery import PackageFinder  # type: ignore
-
-    root_dir = root_dir or os.curdir
-    where = kwargs.pop('where', ['.'])
-    packages: List[str] = []
-    fill_package_dir = {} if fill_package_dir is None else fill_package_dir
-    search = list(unique_everseen(always_iterable(where)))
-
-    if len(search) == 1 and all(not _same_path(search[0], x) for x in (".", root_dir)):
-        fill_package_dir.setdefault("", search[0])
-
-    for path in search:
-        package_path = _nest_path(root_dir, path)
-        pkgs = PackageFinder.find(package_path, **kwargs)
-        packages.extend(pkgs)
-        if pkgs and not (
-            fill_package_dir.get("") == path
-            or os.path.samefile(package_path, root_dir)
-        ):
-            fill_package_dir.update(construct_package_dir(pkgs, path))
-
-    return packages
-
-
-def _nest_path(parent: _Path, path: _Path) -> str:
-    path = parent if path in {".", ""} else os.path.join(parent, path)
-    return os.path.normpath(path)
-
-
-def version(value: Union[Callable, Iterable[Union[str, int]], str]) -> str:
-    """When getting the version directly from an attribute,
-    it should be normalised to string.
-    """
-    if callable(value):
-        value = value()
-
-    value = cast(Iterable[Union[str, int]], value)
-
-    if not isinstance(value, str):
-        if hasattr(value, '__iter__'):
-            value = '.'.join(map(str, value))
-        else:
-            value = '%s' % value
-
-    return value
-
-
-def canonic_package_data(package_data: dict) -> dict:
-    if "*" in package_data:
-        package_data[""] = package_data.pop("*")
-    return package_data
-
-
-def canonic_data_files(
-    data_files: Union[list, dict], root_dir: Optional[_Path] = None
-) -> List[Tuple[str, List[str]]]:
-    """For compatibility with ``setup.py``, ``data_files`` should be a list
-    of pairs instead of a dict.
-
-    This function also expands glob patterns.
-    """
-    if isinstance(data_files, list):
-        return data_files
-
-    return [
-        (dest, glob_relative(patterns, root_dir))
-        for dest, patterns in data_files.items()
-    ]
-
-
-def entry_points(text: str, text_source="entry-points") -> Dict[str, dict]:
-    """Given the contents of entry-points file,
-    process it into a 2-level dictionary (``dict[str, dict[str, str]]``).
-    The first level keys are entry-point groups, the second level keys are
-    entry-point names, and the second level values are references to objects
-    (that correspond to the entry-point value).
-    """
-    parser = ConfigParser(default_section=None, delimiters=("=",))  # type: ignore
-    parser.optionxform = str  # case sensitive
-    parser.read_string(text, text_source)
-    groups = {k: dict(v.items()) for k, v in parser.items()}
-    groups.pop(parser.default_section, None)
-    return groups
-
-
-class EnsurePackagesDiscovered:
-    """Some expand functions require all the packages to already be discovered before
-    they run, e.g. :func:`read_attr`, :func:`resolve_class`, :func:`cmdclass`.
-
-    Therefore in some cases we will need to run autodiscovery during the evaluation of
-    the configuration. However, it is better to postpone calling package discovery as
-    much as possible, because some parameters can influence it (e.g. ``package_dir``),
-    and those might not have been processed yet.
-    """
-
-    def __init__(self, distribution: "Distribution"):
-        self._dist = distribution
-        self._called = False
-
-    def __call__(self):
-        """Trigger the automatic package discovery, if it is still necessary."""
-        if not self._called:
-            self._called = True
-            self._dist.set_defaults(name=False)  # Skip name, we can still be parsing
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, _exc_type, _exc_value, _traceback):
-        if self._called:
-            self._dist.set_defaults.analyse_name()  # Now we can set a default name
-
-    def _get_package_dir(self) -> Mapping[str, str]:
-        self()
-        pkg_dir = self._dist.package_dir
-        return {} if pkg_dir is None else pkg_dir
-
-    @property
-    def package_dir(self) -> Mapping[str, str]:
-        """Proxy to ``package_dir`` that may trigger auto-discovery when used."""
-        return LazyMappingProxy(self._get_package_dir)
-
-
-class LazyMappingProxy(Mapping[_K, _V]):
-    """Mapping proxy that delays resolving the target object, until really needed.
-
-    >>> def obtain_mapping():
-    ...     print("Running expensive function!")
-    ...     return {"key": "value", "other key": "other value"}
-    >>> mapping = LazyMappingProxy(obtain_mapping)
-    >>> mapping["key"]
-    Running expensive function!
-    'value'
-    >>> mapping["other key"]
-    'other value'
-    """
-
-    def __init__(self, obtain_mapping_value: Callable[[], Mapping[_K, _V]]):
-        self._obtain = obtain_mapping_value
-        self._value: Optional[Mapping[_K, _V]] = None
-
-    def _target(self) -> Mapping[_K, _V]:
-        if self._value is None:
-            self._value = self._obtain()
-        return self._value
-
-    def __getitem__(self, key: _K) -> _V:
-        return self._target()[key]
-
-    def __len__(self) -> int:
-        return len(self._target())
-
-    def __iter__(self) -> Iterator[_K]:
-        return iter(self._target())
diff --git a/venv/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py b/venv/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py
deleted file mode 100755
index 9ce5502..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py
+++ /dev/null
@@ -1,498 +0,0 @@
-"""
-Load setuptools configuration from ``pyproject.toml`` files.
-
-**PRIVATE MODULE**: API reserved for setuptools internal usage only.
-"""
-import logging
-import os
-import warnings
-from contextlib import contextmanager
-from functools import partial
-from typing import TYPE_CHECKING, Callable, Dict, Optional, Mapping, Set, Union
-
-from setuptools.errors import FileError, OptionError
-
-from . import expand as _expand
-from ._apply_pyprojecttoml import apply as _apply
-from ._apply_pyprojecttoml import _PREVIOUSLY_DEFINED, _WouldIgnoreField
-
-if TYPE_CHECKING:
-    from setuptools.dist import Distribution  # noqa
-
-_Path = Union[str, os.PathLike]
-_logger = logging.getLogger(__name__)
-
-
-def load_file(filepath: _Path) -> dict:
-    from setuptools.extern import tomli  # type: ignore
-
-    with open(filepath, "rb") as file:
-        return tomli.load(file)
-
-
-def validate(config: dict, filepath: _Path) -> bool:
-    from . import _validate_pyproject as validator
-
-    trove_classifier = validator.FORMAT_FUNCTIONS.get("trove-classifier")
-    if hasattr(trove_classifier, "_disable_download"):
-        # Improve reproducibility by default. See issue 31 for validate-pyproject.
-        trove_classifier._disable_download()  # type: ignore
-
-    try:
-        return validator.validate(config)
-    except validator.ValidationError as ex:
-        summary = f"configuration error: {ex.summary}"
-        if ex.name.strip("`") != "project":
-            # Probably it is just a field missing/misnamed, not worthy the verbosity...
-            _logger.debug(summary)
-            _logger.debug(ex.details)
-
-        error = f"invalid pyproject.toml config: {ex.name}."
-        raise ValueError(f"{error}\n{summary}") from None
-
-
-def apply_configuration(
-    dist: "Distribution",
-    filepath: _Path,
-    ignore_option_errors=False,
-) -> "Distribution":
-    """Apply the configuration from a ``pyproject.toml`` file into an existing
-    distribution object.
-    """
-    config = read_configuration(filepath, True, ignore_option_errors, dist)
-    return _apply(dist, config, filepath)
-
-
-def read_configuration(
-    filepath: _Path,
-    expand=True,
-    ignore_option_errors=False,
-    dist: Optional["Distribution"] = None,
-):
-    """Read given configuration file and returns options from it as a dict.
-
-    :param str|unicode filepath: Path to configuration file in the ``pyproject.toml``
-        format.
-
-    :param bool expand: Whether to expand directives and other computed values
-        (i.e. post-process the given configuration)
-
-    :param bool ignore_option_errors: Whether to silently ignore
-        options, values of which could not be resolved (e.g. due to exceptions
-        in directives such as file:, attr:, etc.).
-        If False exceptions are propagated as expected.
-
-    :param Distribution|None: Distribution object to which the configuration refers.
-        If not given a dummy object will be created and discarded after the
-        configuration is read. This is used for auto-discovery of packages and in the
-        case a dynamic configuration (e.g. ``attr`` or ``cmdclass``) is expanded.
-        When ``expand=False`` this object is simply ignored.
-
-    :rtype: dict
-    """
-    filepath = os.path.abspath(filepath)
-
-    if not os.path.isfile(filepath):
-        raise FileError(f"Configuration file {filepath!r} does not exist.")
-
-    asdict = load_file(filepath) or {}
-    project_table = asdict.get("project", {})
-    tool_table = asdict.get("tool", {})
-    setuptools_table = tool_table.get("setuptools", {})
-    if not asdict or not (project_table or setuptools_table):
-        return {}  # User is not using pyproject to configure setuptools
-
-    if setuptools_table:
-        # TODO: Remove the following once the feature stabilizes:
-        msg = "Support for `[tool.setuptools]` in `pyproject.toml` is still *beta*."
-        warnings.warn(msg, _BetaConfiguration)
-
-    # There is an overall sense in the community that making include_package_data=True
-    # the default would be an improvement.
-    # `ini2toml` backfills include_package_data=False when nothing is explicitly given,
-    # therefore setting a default here is backwards compatible.
-    orig_setuptools_table = setuptools_table.copy()
-    if dist and getattr(dist, "include_package_data", None) is not None:
-        setuptools_table.setdefault("include-package-data", dist.include_package_data)
-    else:
-        setuptools_table.setdefault("include-package-data", True)
-    # Persist changes:
-    asdict["tool"] = tool_table
-    tool_table["setuptools"] = setuptools_table
-
-    try:
-        # Don't complain about unrelated errors (e.g. tools not using the "tool" table)
-        subset = {"project": project_table, "tool": {"setuptools": setuptools_table}}
-        validate(subset, filepath)
-    except Exception as ex:
-        # TODO: Remove the following once the feature stabilizes:
-        if _skip_bad_config(project_table, orig_setuptools_table, dist):
-            return {}
-        # TODO: After the previous statement is removed the try/except can be replaced
-        # by the _ignore_errors context manager.
-        if ignore_option_errors:
-            _logger.debug(f"ignored error: {ex.__class__.__name__} - {ex}")
-        else:
-            raise  # re-raise exception
-
-    if expand:
-        root_dir = os.path.dirname(filepath)
-        return expand_configuration(asdict, root_dir, ignore_option_errors, dist)
-
-    return asdict
-
-
-def _skip_bad_config(
-    project_cfg: dict, setuptools_cfg: dict, dist: Optional["Distribution"]
-) -> bool:
-    """Be temporarily forgiving with invalid ``pyproject.toml``"""
-    # See pypa/setuptools#3199 and pypa/cibuildwheel#1064
-
-    if dist is None or (
-        dist.metadata.name is None
-        and dist.metadata.version is None
-        and dist.install_requires is None
-    ):
-        # It seems that the build is not getting any configuration from other places
-        return False
-
-    if setuptools_cfg:
-        # If `[tool.setuptools]` is set, then `pyproject.toml` config is intentional
-        return False
-
-    given_config = set(project_cfg.keys())
-    popular_subset = {"name", "version", "python_requires", "requires-python"}
-    if given_config <= popular_subset:
-        # It seems that the docs in cibuildtool has been inadvertently encouraging users
-        # to create `pyproject.toml` files that are not compliant with the standards.
-        # Let's be forgiving for the time being.
-        warnings.warn(_InvalidFile.message(), _InvalidFile, stacklevel=2)
-        return True
-
-    return False
-
-
-def expand_configuration(
-    config: dict,
-    root_dir: Optional[_Path] = None,
-    ignore_option_errors: bool = False,
-    dist: Optional["Distribution"] = None,
-) -> dict:
-    """Given a configuration with unresolved fields (e.g. dynamic, cmdclass, ...)
-    find their final values.
-
-    :param dict config: Dict containing the configuration for the distribution
-    :param str root_dir: Top-level directory for the distribution/project
-        (the same directory where ``pyproject.toml`` is place)
-    :param bool ignore_option_errors: see :func:`read_configuration`
-    :param Distribution|None: Distribution object to which the configuration refers.
-        If not given a dummy object will be created and discarded after the
-        configuration is read. Used in the case a dynamic configuration
-        (e.g. ``attr`` or ``cmdclass``).
-
-    :rtype: dict
-    """
-    return _ConfigExpander(config, root_dir, ignore_option_errors, dist).expand()
-
-
-class _ConfigExpander:
-    def __init__(
-        self,
-        config: dict,
-        root_dir: Optional[_Path] = None,
-        ignore_option_errors: bool = False,
-        dist: Optional["Distribution"] = None,
-    ):
-        self.config = config
-        self.root_dir = root_dir or os.getcwd()
-        self.project_cfg = config.get("project", {})
-        self.dynamic = self.project_cfg.get("dynamic", [])
-        self.setuptools_cfg = config.get("tool", {}).get("setuptools", {})
-        self.dynamic_cfg = self.setuptools_cfg.get("dynamic", {})
-        self.ignore_option_errors = ignore_option_errors
-        self._dist = dist
-        self._referenced_files: Set[str] = set()
-
-    def _ensure_dist(self) -> "Distribution":
-        from setuptools.dist import Distribution
-
-        attrs = {"src_root": self.root_dir, "name": self.project_cfg.get("name", None)}
-        return self._dist or Distribution(attrs)
-
-    def _process_field(self, container: dict, field: str, fn: Callable):
-        if field in container:
-            with _ignore_errors(self.ignore_option_errors):
-                container[field] = fn(container[field])
-
-    def _canonic_package_data(self, field="package-data"):
-        package_data = self.setuptools_cfg.get(field, {})
-        return _expand.canonic_package_data(package_data)
-
-    def expand(self):
-        self._expand_packages()
-        self._canonic_package_data()
-        self._canonic_package_data("exclude-package-data")
-
-        # A distribution object is required for discovering the correct package_dir
-        dist = self._ensure_dist()
-        ctx = _EnsurePackagesDiscovered(dist, self.project_cfg, self.setuptools_cfg)
-        with ctx as ensure_discovered:
-            package_dir = ensure_discovered.package_dir
-            self._expand_data_files()
-            self._expand_cmdclass(package_dir)
-            self._expand_all_dynamic(dist, package_dir)
-
-        dist._referenced_files.update(self._referenced_files)
-        return self.config
-
-    def _expand_packages(self):
-        packages = self.setuptools_cfg.get("packages")
-        if packages is None or isinstance(packages, (list, tuple)):
-            return
-
-        find = packages.get("find")
-        if isinstance(find, dict):
-            find["root_dir"] = self.root_dir
-            find["fill_package_dir"] = self.setuptools_cfg.setdefault("package-dir", {})
-            with _ignore_errors(self.ignore_option_errors):
-                self.setuptools_cfg["packages"] = _expand.find_packages(**find)
-
-    def _expand_data_files(self):
-        data_files = partial(_expand.canonic_data_files, root_dir=self.root_dir)
-        self._process_field(self.setuptools_cfg, "data-files", data_files)
-
-    def _expand_cmdclass(self, package_dir: Mapping[str, str]):
-        root_dir = self.root_dir
-        cmdclass = partial(_expand.cmdclass, package_dir=package_dir, root_dir=root_dir)
-        self._process_field(self.setuptools_cfg, "cmdclass", cmdclass)
-
-    def _expand_all_dynamic(self, dist: "Distribution", package_dir: Mapping[str, str]):
-        special = (  # need special handling
-            "version",
-            "readme",
-            "entry-points",
-            "scripts",
-            "gui-scripts",
-            "classifiers",
-            "dependencies",
-            "optional-dependencies",
-        )
-        # `_obtain` functions are assumed to raise appropriate exceptions/warnings.
-        obtained_dynamic = {
-            field: self._obtain(dist, field, package_dir)
-            for field in self.dynamic
-            if field not in special
-        }
-        obtained_dynamic.update(
-            self._obtain_entry_points(dist, package_dir) or {},
-            version=self._obtain_version(dist, package_dir),
-            readme=self._obtain_readme(dist),
-            classifiers=self._obtain_classifiers(dist),
-            dependencies=self._obtain_dependencies(dist),
-            optional_dependencies=self._obtain_optional_dependencies(dist),
-        )
-        # `None` indicates there is nothing in `tool.setuptools.dynamic` but the value
-        # might have already been set by setup.py/extensions, so avoid overwriting.
-        updates = {k: v for k, v in obtained_dynamic.items() if v is not None}
-        self.project_cfg.update(updates)
-
-    def _ensure_previously_set(self, dist: "Distribution", field: str):
-        previous = _PREVIOUSLY_DEFINED[field](dist)
-        if previous is None and not self.ignore_option_errors:
-            msg = (
-                f"No configuration found for dynamic {field!r}.\n"
-                "Some dynamic fields need to be specified via `tool.setuptools.dynamic`"
-                "\nothers must be specified via the equivalent attribute in `setup.py`."
-            )
-            raise OptionError(msg)
-
-    def _expand_directive(
-        self, specifier: str, directive, package_dir: Mapping[str, str]
-    ):
-        from setuptools.extern.more_itertools import always_iterable  # type: ignore
-
-        with _ignore_errors(self.ignore_option_errors):
-            root_dir = self.root_dir
-            if "file" in directive:
-                self._referenced_files.update(always_iterable(directive["file"]))
-                return _expand.read_files(directive["file"], root_dir)
-            if "attr" in directive:
-                return _expand.read_attr(directive["attr"], package_dir, root_dir)
-            raise ValueError(f"invalid `{specifier}`: {directive!r}")
-        return None
-
-    def _obtain(self, dist: "Distribution", field: str, package_dir: Mapping[str, str]):
-        if field in self.dynamic_cfg:
-            return self._expand_directive(
-                f"tool.setuptools.dynamic.{field}",
-                self.dynamic_cfg[field],
-                package_dir,
-            )
-        self._ensure_previously_set(dist, field)
-        return None
-
-    def _obtain_version(self, dist: "Distribution", package_dir: Mapping[str, str]):
-        # Since plugins can set version, let's silently skip if it cannot be obtained
-        if "version" in self.dynamic and "version" in self.dynamic_cfg:
-            return _expand.version(self._obtain(dist, "version", package_dir))
-        return None
-
-    def _obtain_readme(self, dist: "Distribution") -> Optional[Dict[str, str]]:
-        if "readme" not in self.dynamic:
-            return None
-
-        dynamic_cfg = self.dynamic_cfg
-        if "readme" in dynamic_cfg:
-            return {
-                "text": self._obtain(dist, "readme", {}),
-                "content-type": dynamic_cfg["readme"].get("content-type", "text/x-rst"),
-            }
-
-        self._ensure_previously_set(dist, "readme")
-        return None
-
-    def _obtain_entry_points(
-        self, dist: "Distribution", package_dir: Mapping[str, str]
-    ) -> Optional[Dict[str, dict]]:
-        fields = ("entry-points", "scripts", "gui-scripts")
-        if not any(field in self.dynamic for field in fields):
-            return None
-
-        text = self._obtain(dist, "entry-points", package_dir)
-        if text is None:
-            return None
-
-        groups = _expand.entry_points(text)
-        expanded = {"entry-points": groups}
-
-        def _set_scripts(field: str, group: str):
-            if group in groups:
-                value = groups.pop(group)
-                if field not in self.dynamic:
-                    msg = _WouldIgnoreField.message(field, value)
-                    warnings.warn(msg, _WouldIgnoreField)
-                # TODO: Don't set field when support for pyproject.toml stabilizes
-                #       instead raise an error as specified in PEP 621
-                expanded[field] = value
-
-        _set_scripts("scripts", "console_scripts")
-        _set_scripts("gui-scripts", "gui_scripts")
-
-        return expanded
-
-    def _obtain_classifiers(self, dist: "Distribution"):
-        if "classifiers" in self.dynamic:
-            value = self._obtain(dist, "classifiers", {})
-            if value:
-                return value.splitlines()
-        return None
-
-    def _obtain_dependencies(self, dist: "Distribution"):
-        if "dependencies" in self.dynamic:
-            value = self._obtain(dist, "dependencies", {})
-            if value:
-                return _parse_requirements_list(value)
-        return None
-
-    def _obtain_optional_dependencies(self, dist: "Distribution"):
-        if "optional-dependencies" not in self.dynamic:
-            return None
-        if "optional-dependencies" in self.dynamic_cfg:
-            optional_dependencies_map = self.dynamic_cfg["optional-dependencies"]
-            assert isinstance(optional_dependencies_map, dict)
-            return {
-                group: _parse_requirements_list(self._expand_directive(
-                    f"tool.setuptools.dynamic.optional-dependencies.{group}",
-                    directive,
-                    {},
-                ))
-                for group, directive in optional_dependencies_map.items()
-            }
-        self._ensure_previously_set(dist, "optional-dependencies")
-        return None
-
-
-def _parse_requirements_list(value):
-    return [
-        line
-        for line in value.splitlines()
-        if line.strip() and not line.strip().startswith("#")
-    ]
-
-
-@contextmanager
-def _ignore_errors(ignore_option_errors: bool):
-    if not ignore_option_errors:
-        yield
-        return
-
-    try:
-        yield
-    except Exception as ex:
-        _logger.debug(f"ignored error: {ex.__class__.__name__} - {ex}")
-
-
-class _EnsurePackagesDiscovered(_expand.EnsurePackagesDiscovered):
-    def __init__(
-        self, distribution: "Distribution", project_cfg: dict, setuptools_cfg: dict
-    ):
-        super().__init__(distribution)
-        self._project_cfg = project_cfg
-        self._setuptools_cfg = setuptools_cfg
-
-    def __enter__(self):
-        """When entering the context, the values of ``packages``, ``py_modules`` and
-        ``package_dir`` that are missing in ``dist`` are copied from ``setuptools_cfg``.
-        """
-        dist, cfg = self._dist, self._setuptools_cfg
-        package_dir: Dict[str, str] = cfg.setdefault("package-dir", {})
-        package_dir.update(dist.package_dir or {})
-        dist.package_dir = package_dir  # needs to be the same object
-
-        dist.set_defaults._ignore_ext_modules()  # pyproject.toml-specific behaviour
-
-        # Set `name`, `py_modules` and `packages` in dist to short-circuit
-        # auto-discovery, but avoid overwriting empty lists purposefully set by users.
-        if dist.metadata.name is None:
-            dist.metadata.name = self._project_cfg.get("name")
-        if dist.py_modules is None:
-            dist.py_modules = cfg.get("py-modules")
-        if dist.packages is None:
-            dist.packages = cfg.get("packages")
-
-        return super().__enter__()
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        """When exiting the context, if values of ``packages``, ``py_modules`` and
-        ``package_dir`` are missing in ``setuptools_cfg``, copy from ``dist``.
-        """
-        # If anything was discovered set them back, so they count in the final config.
-        self._setuptools_cfg.setdefault("packages", self._dist.packages)
-        self._setuptools_cfg.setdefault("py-modules", self._dist.py_modules)
-        return super().__exit__(exc_type, exc_value, traceback)
-
-
-class _BetaConfiguration(UserWarning):
-    """Explicitly inform users that some `pyproject.toml` configuration is *beta*"""
-
-
-class _InvalidFile(UserWarning):
-    """The given `pyproject.toml` file is invalid and would be ignored.
-    !!\n\n
-    ############################
-    # Invalid `pyproject.toml` #
-    ############################
-
-    Any configurations in `pyproject.toml` will be ignored.
-    Please note that future releases of setuptools will halt the build process
-    if an invalid file is given.
-
-    To prevent setuptools from considering `pyproject.toml` please
-    DO NOT include the `[project]` or `[tool.setuptools]` tables in your file.
-    \n\n!!
-    """
-
-    @classmethod
-    def message(cls):
-        from inspect import cleandoc
-        return cleandoc(cls.__doc__)
diff --git a/venv/lib/python3.11/site-packages/setuptools/config/setupcfg.py b/venv/lib/python3.11/site-packages/setuptools/config/setupcfg.py
deleted file mode 100755
index 3df3b6e..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/config/setupcfg.py
+++ /dev/null
@@ -1,769 +0,0 @@
-"""
-Load setuptools configuration from ``setup.cfg`` files.
-
-**API will be made private in the future**
-"""
-import os
-
-import contextlib
-import functools
-import warnings
-from collections import defaultdict
-from functools import partial
-from functools import wraps
-from typing import (TYPE_CHECKING, Callable, Any, Dict, Generic, Iterable, List,
-                    Optional, Set, Tuple, TypeVar, Union)
-
-from distutils.errors import DistutilsOptionError, DistutilsFileError
-from setuptools.extern.packaging.requirements import Requirement, InvalidRequirement
-from setuptools.extern.packaging.version import Version, InvalidVersion
-from setuptools.extern.packaging.specifiers import SpecifierSet
-from setuptools._deprecation_warning import SetuptoolsDeprecationWarning
-
-from . import expand
-
-if TYPE_CHECKING:
-    from setuptools.dist import Distribution  # noqa
-    from distutils.dist import DistributionMetadata  # noqa
-
-_Path = Union[str, os.PathLike]
-SingleCommandOptions = Dict["str", Tuple["str", Any]]
-"""Dict that associate the name of the options of a particular command to a
-tuple. The first element of the tuple indicates the origin of the option value
-(e.g. the name of the configuration file where it was read from),
-while the second element of the tuple is the option value itself
-"""
-AllCommandOptions = Dict["str", SingleCommandOptions]  # cmd name => its options
-Target = TypeVar("Target", bound=Union["Distribution", "DistributionMetadata"])
-
-
-def read_configuration(
-    filepath: _Path,
-    find_others=False,
-    ignore_option_errors=False
-) -> dict:
-    """Read given configuration file and returns options from it as a dict.
-
-    :param str|unicode filepath: Path to configuration file
-        to get options from.
-
-    :param bool find_others: Whether to search for other configuration files
-        which could be on in various places.
-
-    :param bool ignore_option_errors: Whether to silently ignore
-        options, values of which could not be resolved (e.g. due to exceptions
-        in directives such as file:, attr:, etc.).
-        If False exceptions are propagated as expected.
-
-    :rtype: dict
-    """
-    from setuptools.dist import Distribution
-
-    dist = Distribution()
-    filenames = dist.find_config_files() if find_others else []
-    handlers = _apply(dist, filepath, filenames, ignore_option_errors)
-    return configuration_to_dict(handlers)
-
-
-def apply_configuration(dist: "Distribution", filepath: _Path) -> "Distribution":
-    """Apply the configuration from a ``setup.cfg`` file into an existing
-    distribution object.
-    """
-    _apply(dist, filepath)
-    dist._finalize_requires()
-    return dist
-
-
-def _apply(
-    dist: "Distribution", filepath: _Path,
-    other_files: Iterable[_Path] = (),
-    ignore_option_errors: bool = False,
-) -> Tuple["ConfigHandler", ...]:
-    """Read configuration from ``filepath`` and applies to the ``dist`` object."""
-    from setuptools.dist import _Distribution
-
-    filepath = os.path.abspath(filepath)
-
-    if not os.path.isfile(filepath):
-        raise DistutilsFileError('Configuration file %s does not exist.' % filepath)
-
-    current_directory = os.getcwd()
-    os.chdir(os.path.dirname(filepath))
-    filenames = [*other_files, filepath]
-
-    try:
-        _Distribution.parse_config_files(dist, filenames=filenames)
-        handlers = parse_configuration(
-            dist, dist.command_options, ignore_option_errors=ignore_option_errors
-        )
-        dist._finalize_license_files()
-    finally:
-        os.chdir(current_directory)
-
-    return handlers
-
-
-def _get_option(target_obj: Target, key: str):
-    """
-    Given a target object and option key, get that option from
-    the target object, either through a get_{key} method or
-    from an attribute directly.
-    """
-    getter_name = 'get_{key}'.format(**locals())
-    by_attribute = functools.partial(getattr, target_obj, key)
-    getter = getattr(target_obj, getter_name, by_attribute)
-    return getter()
-
-
-def configuration_to_dict(handlers: Tuple["ConfigHandler", ...]) -> dict:
-    """Returns configuration data gathered by given handlers as a dict.
-
-    :param list[ConfigHandler] handlers: Handlers list,
-        usually from parse_configuration()
-
-    :rtype: dict
-    """
-    config_dict: dict = defaultdict(dict)
-
-    for handler in handlers:
-        for option in handler.set_options:
-            value = _get_option(handler.target_obj, option)
-            config_dict[handler.section_prefix][option] = value
-
-    return config_dict
-
-
-def parse_configuration(
-    distribution: "Distribution",
-    command_options: AllCommandOptions,
-    ignore_option_errors=False
-) -> Tuple["ConfigMetadataHandler", "ConfigOptionsHandler"]:
-    """Performs additional parsing of configuration options
-    for a distribution.
-
-    Returns a list of used option handlers.
-
-    :param Distribution distribution:
-    :param dict command_options:
-    :param bool ignore_option_errors: Whether to silently ignore
-        options, values of which could not be resolved (e.g. due to exceptions
-        in directives such as file:, attr:, etc.).
-        If False exceptions are propagated as expected.
-    :rtype: list
-    """
-    with expand.EnsurePackagesDiscovered(distribution) as ensure_discovered:
-        options = ConfigOptionsHandler(
-            distribution,
-            command_options,
-            ignore_option_errors,
-            ensure_discovered,
-        )
-
-        options.parse()
-        if not distribution.package_dir:
-            distribution.package_dir = options.package_dir  # Filled by `find_packages`
-
-        meta = ConfigMetadataHandler(
-            distribution.metadata,
-            command_options,
-            ignore_option_errors,
-            ensure_discovered,
-            distribution.package_dir,
-            distribution.src_root,
-        )
-        meta.parse()
-        distribution._referenced_files.update(
-            options._referenced_files, meta._referenced_files
-        )
-
-    return meta, options
-
-
-def _warn_accidental_env_marker_misconfig(label: str, orig_value: str, parsed: list):
-    """Because users sometimes misinterpret this configuration:
-
-    [options.extras_require]
-    foo = bar;python_version<"4"
-
-    It looks like one requirement with an environment marker
-    but because there is no newline, it's parsed as two requirements
-    with a semicolon as separator.
-
-    Therefore, if:
-        * input string does not contain a newline AND
-        * parsed result contains two requirements AND
-        * parsing of the two parts from the result (";")
-        leads in a valid Requirement with a valid marker
-    a UserWarning is shown to inform the user about the possible problem.
-    """
-    if "\n" in orig_value or len(parsed) != 2:
-        return
-
-    with contextlib.suppress(InvalidRequirement):
-        original_requirements_str = ";".join(parsed)
-        req = Requirement(original_requirements_str)
-        if req.marker is not None:
-            msg = (
-                f"One of the parsed requirements in `{label}` "
-                f"looks like a valid environment marker: '{parsed[1]}'\n"
-                "Make sure that the config is correct and check "
-                "https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#opt-2"  # noqa: E501
-            )
-            warnings.warn(msg, UserWarning)
-
-
-class ConfigHandler(Generic[Target]):
-    """Handles metadata supplied in configuration files."""
-
-    section_prefix: str
-    """Prefix for config sections handled by this handler.
-    Must be provided by class heirs.
-
-    """
-
-    aliases: Dict[str, str] = {}
-    """Options aliases.
-    For compatibility with various packages. E.g.: d2to1 and pbr.
-    Note: `-` in keys is replaced with `_` by config parser.
-
-    """
-
-    def __init__(
-        self,
-        target_obj: Target,
-        options: AllCommandOptions,
-        ignore_option_errors,
-        ensure_discovered: expand.EnsurePackagesDiscovered,
-    ):
-        sections: AllCommandOptions = {}
-
-        section_prefix = self.section_prefix
-        for section_name, section_options in options.items():
-            if not section_name.startswith(section_prefix):
-                continue
-
-            section_name = section_name.replace(section_prefix, '').strip('.')
-            sections[section_name] = section_options
-
-        self.ignore_option_errors = ignore_option_errors
-        self.target_obj = target_obj
-        self.sections = sections
-        self.set_options: List[str] = []
-        self.ensure_discovered = ensure_discovered
-        self._referenced_files: Set[str] = set()
-        """After parsing configurations, this property will enumerate
-        all files referenced by the "file:" directive. Private API for setuptools only.
-        """
-
-    @property
-    def parsers(self):
-        """Metadata item name to parser function mapping."""
-        raise NotImplementedError(
-            '%s must provide .parsers property' % self.__class__.__name__
-        )
-
-    def __setitem__(self, option_name, value):
-        unknown = tuple()
-        target_obj = self.target_obj
-
-        # Translate alias into real name.
-        option_name = self.aliases.get(option_name, option_name)
-
-        current_value = getattr(target_obj, option_name, unknown)
-
-        if current_value is unknown:
-            raise KeyError(option_name)
-
-        if current_value:
-            # Already inhabited. Skipping.
-            return
-
-        skip_option = False
-        parser = self.parsers.get(option_name)
-        if parser:
-            try:
-                value = parser(value)
-
-            except Exception:
-                skip_option = True
-                if not self.ignore_option_errors:
-                    raise
-
-        if skip_option:
-            return
-
-        setter = getattr(target_obj, 'set_%s' % option_name, None)
-        if setter is None:
-            setattr(target_obj, option_name, value)
-        else:
-            setter(value)
-
-        self.set_options.append(option_name)
-
-    @classmethod
-    def _parse_list(cls, value, separator=','):
-        """Represents value as a list.
-
-        Value is split either by separator (defaults to comma) or by lines.
-
-        :param value:
-        :param separator: List items separator character.
-        :rtype: list
-        """
-        if isinstance(value, list):  # _get_parser_compound case
-            return value
-
-        if '\n' in value:
-            value = value.splitlines()
-        else:
-            value = value.split(separator)
-
-        return [chunk.strip() for chunk in value if chunk.strip()]
-
-    @classmethod
-    def _parse_dict(cls, value):
-        """Represents value as a dict.
-
-        :param value:
-        :rtype: dict
-        """
-        separator = '='
-        result = {}
-        for line in cls._parse_list(value):
-            key, sep, val = line.partition(separator)
-            if sep != separator:
-                raise DistutilsOptionError(
-                    'Unable to parse option value to dict: %s' % value
-                )
-            result[key.strip()] = val.strip()
-
-        return result
-
-    @classmethod
-    def _parse_bool(cls, value):
-        """Represents value as boolean.
-
-        :param value:
-        :rtype: bool
-        """
-        value = value.lower()
-        return value in ('1', 'true', 'yes')
-
-    @classmethod
-    def _exclude_files_parser(cls, key):
-        """Returns a parser function to make sure field inputs
-        are not files.
-
-        Parses a value after getting the key so error messages are
-        more informative.
-
-        :param key:
-        :rtype: callable
-        """
-
-        def parser(value):
-            exclude_directive = 'file:'
-            if value.startswith(exclude_directive):
-                raise ValueError(
-                    'Only strings are accepted for the {0} field, '
-                    'files are not accepted'.format(key)
-                )
-            return value
-
-        return parser
-
-    def _parse_file(self, value, root_dir: _Path):
-        """Represents value as a string, allowing including text
-        from nearest files using `file:` directive.
-
-        Directive is sandboxed and won't reach anything outside
-        directory with setup.py.
-
-        Examples:
-            file: README.rst, CHANGELOG.md, src/file.txt
-
-        :param str value:
-        :rtype: str
-        """
-        include_directive = 'file:'
-
-        if not isinstance(value, str):
-            return value
-
-        if not value.startswith(include_directive):
-            return value
-
-        spec = value[len(include_directive) :]
-        filepaths = [path.strip() for path in spec.split(',')]
-        self._referenced_files.update(filepaths)
-        return expand.read_files(filepaths, root_dir)
-
-    def _parse_attr(self, value, package_dir, root_dir: _Path):
-        """Represents value as a module attribute.
-
-        Examples:
-            attr: package.attr
-            attr: package.module.attr
-
-        :param str value:
-        :rtype: str
-        """
-        attr_directive = 'attr:'
-        if not value.startswith(attr_directive):
-            return value
-
-        attr_desc = value.replace(attr_directive, '')
-
-        # Make sure package_dir is populated correctly, so `attr:` directives can work
-        package_dir.update(self.ensure_discovered.package_dir)
-        return expand.read_attr(attr_desc, package_dir, root_dir)
-
-    @classmethod
-    def _get_parser_compound(cls, *parse_methods):
-        """Returns parser function to represents value as a list.
-
-        Parses a value applying given methods one after another.
-
-        :param parse_methods:
-        :rtype: callable
-        """
-
-        def parse(value):
-            parsed = value
-
-            for method in parse_methods:
-                parsed = method(parsed)
-
-            return parsed
-
-        return parse
-
-    @classmethod
-    def _parse_section_to_dict_with_key(cls, section_options, values_parser):
-        """Parses section options into a dictionary.
-
-        Applies a given parser to each option in a section.
-
-        :param dict section_options:
-        :param callable values_parser: function with 2 args corresponding to key, value
-        :rtype: dict
-        """
-        value = {}
-        for key, (_, val) in section_options.items():
-            value[key] = values_parser(key, val)
-        return value
-
-    @classmethod
-    def _parse_section_to_dict(cls, section_options, values_parser=None):
-        """Parses section options into a dictionary.
-
-        Optionally applies a given parser to each value.
-
-        :param dict section_options:
-        :param callable values_parser: function with 1 arg corresponding to option value
-        :rtype: dict
-        """
-        parser = (lambda _, v: values_parser(v)) if values_parser else (lambda _, v: v)
-        return cls._parse_section_to_dict_with_key(section_options, parser)
-
-    def parse_section(self, section_options):
-        """Parses configuration file section.
-
-        :param dict section_options:
-        """
-        for (name, (_, value)) in section_options.items():
-            with contextlib.suppress(KeyError):
-                # Keep silent for a new option may appear anytime.
-                self[name] = value
-
-    def parse(self):
-        """Parses configuration file items from one
-        or more related sections.
-
-        """
-        for section_name, section_options in self.sections.items():
-
-            method_postfix = ''
-            if section_name:  # [section.option] variant
-                method_postfix = '_%s' % section_name
-
-            section_parser_method: Optional[Callable] = getattr(
-                self,
-                # Dots in section names are translated into dunderscores.
-                ('parse_section%s' % method_postfix).replace('.', '__'),
-                None,
-            )
-
-            if section_parser_method is None:
-                raise DistutilsOptionError(
-                    'Unsupported distribution option section: [%s.%s]'
-                    % (self.section_prefix, section_name)
-                )
-
-            section_parser_method(section_options)
-
-    def _deprecated_config_handler(self, func, msg, warning_class):
-        """this function will wrap around parameters that are deprecated
-
-        :param msg: deprecation message
-        :param warning_class: class of warning exception to be raised
-        :param func: function to be wrapped around
-        """
-
-        @wraps(func)
-        def config_handler(*args, **kwargs):
-            warnings.warn(msg, warning_class)
-            return func(*args, **kwargs)
-
-        return config_handler
-
-
-class ConfigMetadataHandler(ConfigHandler["DistributionMetadata"]):
-
-    section_prefix = 'metadata'
-
-    aliases = {
-        'home_page': 'url',
-        'summary': 'description',
-        'classifier': 'classifiers',
-        'platform': 'platforms',
-    }
-
-    strict_mode = False
-    """We need to keep it loose, to be partially compatible with
-    `pbr` and `d2to1` packages which also uses `metadata` section.
-
-    """
-
-    def __init__(
-        self,
-        target_obj: "DistributionMetadata",
-        options: AllCommandOptions,
-        ignore_option_errors: bool,
-        ensure_discovered: expand.EnsurePackagesDiscovered,
-        package_dir: Optional[dict] = None,
-        root_dir: _Path = os.curdir
-    ):
-        super().__init__(target_obj, options, ignore_option_errors, ensure_discovered)
-        self.package_dir = package_dir
-        self.root_dir = root_dir
-
-    @property
-    def parsers(self):
-        """Metadata item name to parser function mapping."""
-        parse_list = self._parse_list
-        parse_file = partial(self._parse_file, root_dir=self.root_dir)
-        parse_dict = self._parse_dict
-        exclude_files_parser = self._exclude_files_parser
-
-        return {
-            'platforms': parse_list,
-            'keywords': parse_list,
-            'provides': parse_list,
-            'requires': self._deprecated_config_handler(
-                parse_list,
-                "The requires parameter is deprecated, please use "
-                "install_requires for runtime dependencies.",
-                SetuptoolsDeprecationWarning,
-            ),
-            'obsoletes': parse_list,
-            'classifiers': self._get_parser_compound(parse_file, parse_list),
-            'license': exclude_files_parser('license'),
-            'license_file': self._deprecated_config_handler(
-                exclude_files_parser('license_file'),
-                "The license_file parameter is deprecated, "
-                "use license_files instead.",
-                SetuptoolsDeprecationWarning,
-            ),
-            'license_files': parse_list,
-            'description': parse_file,
-            'long_description': parse_file,
-            'version': self._parse_version,
-            'project_urls': parse_dict,
-        }
-
-    def _parse_version(self, value):
-        """Parses `version` option value.
-
-        :param value:
-        :rtype: str
-
-        """
-        version = self._parse_file(value, self.root_dir)
-
-        if version != value:
-            version = version.strip()
-            # Be strict about versions loaded from file because it's easy to
-            # accidentally include newlines and other unintended content
-            try:
-                Version(version)
-            except InvalidVersion:
-                tmpl = (
-                    'Version loaded from {value} does not '
-                    'comply with PEP 440: {version}'
-                )
-                raise DistutilsOptionError(tmpl.format(**locals()))
-
-            return version
-
-        return expand.version(self._parse_attr(value, self.package_dir, self.root_dir))
-
-
-class ConfigOptionsHandler(ConfigHandler["Distribution"]):
-
-    section_prefix = 'options'
-
-    def __init__(
-        self,
-        target_obj: "Distribution",
-        options: AllCommandOptions,
-        ignore_option_errors: bool,
-        ensure_discovered: expand.EnsurePackagesDiscovered,
-    ):
-        super().__init__(target_obj, options, ignore_option_errors, ensure_discovered)
-        self.root_dir = target_obj.src_root
-        self.package_dir: Dict[str, str] = {}  # To be filled by `find_packages`
-
-    @classmethod
-    def _parse_list_semicolon(cls, value):
-        return cls._parse_list(value, separator=';')
-
-    def _parse_file_in_root(self, value):
-        return self._parse_file(value, root_dir=self.root_dir)
-
-    def _parse_requirements_list(self, label: str, value: str):
-        # Parse a requirements list, either by reading in a `file:`, or a list.
-        parsed = self._parse_list_semicolon(self._parse_file_in_root(value))
-        _warn_accidental_env_marker_misconfig(label, value, parsed)
-        # Filter it to only include lines that are not comments. `parse_list`
-        # will have stripped each line and filtered out empties.
-        return [line for line in parsed if not line.startswith("#")]
-
-    @property
-    def parsers(self):
-        """Metadata item name to parser function mapping."""
-        parse_list = self._parse_list
-        parse_bool = self._parse_bool
-        parse_dict = self._parse_dict
-        parse_cmdclass = self._parse_cmdclass
-
-        return {
-            'zip_safe': parse_bool,
-            'include_package_data': parse_bool,
-            'package_dir': parse_dict,
-            'scripts': parse_list,
-            'eager_resources': parse_list,
-            'dependency_links': parse_list,
-            'namespace_packages': self._deprecated_config_handler(
-                parse_list,
-                "The namespace_packages parameter is deprecated, "
-                "consider using implicit namespaces instead (PEP 420).",
-                SetuptoolsDeprecationWarning,
-            ),
-            'install_requires': partial(
-                self._parse_requirements_list, "install_requires"
-            ),
-            'setup_requires': self._parse_list_semicolon,
-            'tests_require': self._parse_list_semicolon,
-            'packages': self._parse_packages,
-            'entry_points': self._parse_file_in_root,
-            'py_modules': parse_list,
-            'python_requires': SpecifierSet,
-            'cmdclass': parse_cmdclass,
-        }
-
-    def _parse_cmdclass(self, value):
-        package_dir = self.ensure_discovered.package_dir
-        return expand.cmdclass(self._parse_dict(value), package_dir, self.root_dir)
-
-    def _parse_packages(self, value):
-        """Parses `packages` option value.
-
-        :param value:
-        :rtype: list
-        """
-        find_directives = ['find:', 'find_namespace:']
-        trimmed_value = value.strip()
-
-        if trimmed_value not in find_directives:
-            return self._parse_list(value)
-
-        # Read function arguments from a dedicated section.
-        find_kwargs = self.parse_section_packages__find(
-            self.sections.get('packages.find', {})
-        )
-
-        find_kwargs.update(
-            namespaces=(trimmed_value == find_directives[1]),
-            root_dir=self.root_dir,
-            fill_package_dir=self.package_dir,
-        )
-
-        return expand.find_packages(**find_kwargs)
-
-    def parse_section_packages__find(self, section_options):
-        """Parses `packages.find` configuration file section.
-
-        To be used in conjunction with _parse_packages().
-
-        :param dict section_options:
-        """
-        section_data = self._parse_section_to_dict(section_options, self._parse_list)
-
-        valid_keys = ['where', 'include', 'exclude']
-
-        find_kwargs = dict(
-            [(k, v) for k, v in section_data.items() if k in valid_keys and v]
-        )
-
-        where = find_kwargs.get('where')
-        if where is not None:
-            find_kwargs['where'] = where[0]  # cast list to single val
-
-        return find_kwargs
-
-    def parse_section_entry_points(self, section_options):
-        """Parses `entry_points` configuration file section.
-
-        :param dict section_options:
-        """
-        parsed = self._parse_section_to_dict(section_options, self._parse_list)
-        self['entry_points'] = parsed
-
-    def _parse_package_data(self, section_options):
-        package_data = self._parse_section_to_dict(section_options, self._parse_list)
-        return expand.canonic_package_data(package_data)
-
-    def parse_section_package_data(self, section_options):
-        """Parses `package_data` configuration file section.
-
-        :param dict section_options:
-        """
-        self['package_data'] = self._parse_package_data(section_options)
-
-    def parse_section_exclude_package_data(self, section_options):
-        """Parses `exclude_package_data` configuration file section.
-
-        :param dict section_options:
-        """
-        self['exclude_package_data'] = self._parse_package_data(section_options)
-
-    def parse_section_extras_require(self, section_options):
-        """Parses `extras_require` configuration file section.
-
-        :param dict section_options:
-        """
-        parsed = self._parse_section_to_dict_with_key(
-            section_options,
-            lambda k, v: self._parse_requirements_list(f"extras_require[{k}]", v)
-        )
-
-        self['extras_require'] = parsed
-
-    def parse_section_data_files(self, section_options):
-        """Parses `data_files` configuration file section.
-
-        :param dict section_options:
-        """
-        parsed = self._parse_section_to_dict(section_options, self._parse_list)
-        self['data_files'] = expand.canonic_data_files(parsed, self.root_dir)
diff --git a/venv/lib/python3.11/site-packages/setuptools/dep_util.py b/venv/lib/python3.11/site-packages/setuptools/dep_util.py
deleted file mode 100755
index 521eb71..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/dep_util.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from distutils.dep_util import newer_group
-
-
-# yes, this is was almost entirely copy-pasted from
-# 'newer_pairwise()', this is just another convenience
-# function.
-def newer_pairwise_group(sources_groups, targets):
-    """Walk both arguments in parallel, testing if each source group is newer
-    than its corresponding target. Returns a pair of lists (sources_groups,
-    targets) where sources is newer than target, according to the semantics
-    of 'newer_group()'.
-    """
-    if len(sources_groups) != len(targets):
-        raise ValueError(
-            "'sources_group' and 'targets' must be the same length")
-
-    # build a pair of lists (sources_groups, targets) where source is newer
-    n_sources = []
-    n_targets = []
-    for i in range(len(sources_groups)):
-        if newer_group(sources_groups[i], targets[i]):
-            n_sources.append(sources_groups[i])
-            n_targets.append(targets[i])
-
-    return n_sources, n_targets
diff --git a/venv/lib/python3.11/site-packages/setuptools/depends.py b/venv/lib/python3.11/site-packages/setuptools/depends.py
deleted file mode 100755
index adffd12..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/depends.py
+++ /dev/null
@@ -1,176 +0,0 @@
-import sys
-import marshal
-import contextlib
-import dis
-
-from setuptools.extern.packaging import version
-
-from ._imp import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE
-from . import _imp
-
-
-__all__ = [
-    'Require', 'find_module', 'get_module_constant', 'extract_constant'
-]
-
-
-class Require:
-    """A prerequisite to building or installing a distribution"""
-
-    def __init__(
-            self, name, requested_version, module, homepage='',
-            attribute=None, format=None):
-
-        if format is None and requested_version is not None:
-            format = version.Version
-
-        if format is not None:
-            requested_version = format(requested_version)
-            if attribute is None:
-                attribute = '__version__'
-
-        self.__dict__.update(locals())
-        del self.self
-
-    def full_name(self):
-        """Return full package/distribution name, w/version"""
-        if self.requested_version is not None:
-            return '%s-%s' % (self.name, self.requested_version)
-        return self.name
-
-    def version_ok(self, version):
-        """Is 'version' sufficiently up-to-date?"""
-        return self.attribute is None or self.format is None or \
-            str(version) != "unknown" and self.format(version) >= self.requested_version
-
-    def get_version(self, paths=None, default="unknown"):
-        """Get version number of installed module, 'None', or 'default'
-
-        Search 'paths' for module.  If not found, return 'None'.  If found,
-        return the extracted version attribute, or 'default' if no version
-        attribute was specified, or the value cannot be determined without
-        importing the module.  The version is formatted according to the
-        requirement's version format (if any), unless it is 'None' or the
-        supplied 'default'.
-        """
-
-        if self.attribute is None:
-            try:
-                f, p, i = find_module(self.module, paths)
-                if f:
-                    f.close()
-                return default
-            except ImportError:
-                return None
-
-        v = get_module_constant(self.module, self.attribute, default, paths)
-
-        if v is not None and v is not default and self.format is not None:
-            return self.format(v)
-
-        return v
-
-    def is_present(self, paths=None):
-        """Return true if dependency is present on 'paths'"""
-        return self.get_version(paths) is not None
-
-    def is_current(self, paths=None):
-        """Return true if dependency is present and up-to-date on 'paths'"""
-        version = self.get_version(paths)
-        if version is None:
-            return False
-        return self.version_ok(str(version))
-
-
-def maybe_close(f):
-    @contextlib.contextmanager
-    def empty():
-        yield
-        return
-    if not f:
-        return empty()
-
-    return contextlib.closing(f)
-
-
-def get_module_constant(module, symbol, default=-1, paths=None):
-    """Find 'module' by searching 'paths', and extract 'symbol'
-
-    Return 'None' if 'module' does not exist on 'paths', or it does not define
-    'symbol'.  If the module defines 'symbol' as a constant, return the
-    constant.  Otherwise, return 'default'."""
-
-    try:
-        f, path, (suffix, mode, kind) = info = find_module(module, paths)
-    except ImportError:
-        # Module doesn't exist
-        return None
-
-    with maybe_close(f):
-        if kind == PY_COMPILED:
-            f.read(8)  # skip magic & date
-            code = marshal.load(f)
-        elif kind == PY_FROZEN:
-            code = _imp.get_frozen_object(module, paths)
-        elif kind == PY_SOURCE:
-            code = compile(f.read(), path, 'exec')
-        else:
-            # Not something we can parse; we'll have to import it.  :(
-            imported = _imp.get_module(module, paths, info)
-            return getattr(imported, symbol, None)
-
-    return extract_constant(code, symbol, default)
-
-
-def extract_constant(code, symbol, default=-1):
-    """Extract the constant value of 'symbol' from 'code'
-
-    If the name 'symbol' is bound to a constant value by the Python code
-    object 'code', return that value.  If 'symbol' is bound to an expression,
-    return 'default'.  Otherwise, return 'None'.
-
-    Return value is based on the first assignment to 'symbol'.  'symbol' must
-    be a global, or at least a non-"fast" local in the code block.  That is,
-    only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol'
-    must be present in 'code.co_names'.
-    """
-    if symbol not in code.co_names:
-        # name's not there, can't possibly be an assignment
-        return None
-
-    name_idx = list(code.co_names).index(symbol)
-
-    STORE_NAME = 90
-    STORE_GLOBAL = 97
-    LOAD_CONST = 100
-
-    const = default
-
-    for byte_code in dis.Bytecode(code):
-        op = byte_code.opcode
-        arg = byte_code.arg
-
-        if op == LOAD_CONST:
-            const = code.co_consts[arg]
-        elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL):
-            return const
-        else:
-            const = default
-
-
-def _update_globals():
-    """
-    Patch the globals to remove the objects not available on some platforms.
-
-    XXX it'd be better to test assertions about bytecode instead.
-    """
-
-    if not sys.platform.startswith('java') and sys.platform != 'cli':
-        return
-    incompatible = 'extract_constant', 'get_module_constant'
-    for name in incompatible:
-        del globals()[name]
-        __all__.remove(name)
-
-
-_update_globals()
diff --git a/venv/lib/python3.11/site-packages/setuptools/discovery.py b/venv/lib/python3.11/site-packages/setuptools/discovery.py
deleted file mode 100755
index 6244a18..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/discovery.py
+++ /dev/null
@@ -1,601 +0,0 @@
-"""Automatic discovery of Python modules and packages (for inclusion in the
-distribution) and other config values.
-
-For the purposes of this module, the following nomenclature is used:
-
-- "src-layout": a directory representing a Python project that contains a "src"
-  folder. Everything under the "src" folder is meant to be included in the
-  distribution when packaging the project. Example::
-
-    .
-    ├── tox.ini
-    ├── pyproject.toml
-    └── src/
-        └── mypkg/
-            ├── __init__.py
-            ├── mymodule.py
-            └── my_data_file.txt
-
-- "flat-layout": a Python project that does not use "src-layout" but instead
-  have a directory under the project root for each package::
-
-    .
-    ├── tox.ini
-    ├── pyproject.toml
-    └── mypkg/
-        ├── __init__.py
-        ├── mymodule.py
-        └── my_data_file.txt
-
-- "single-module": a project that contains a single Python script direct under
-  the project root (no directory used)::
-
-    .
-    ├── tox.ini
-    ├── pyproject.toml
-    └── mymodule.py
-
-"""
-
-import itertools
-import os
-from fnmatch import fnmatchcase
-from glob import glob
-from pathlib import Path
-from typing import (
-    TYPE_CHECKING,
-    Callable,
-    Dict,
-    Iterable,
-    Iterator,
-    List,
-    Mapping,
-    Optional,
-    Tuple,
-    Union
-)
-
-import _distutils_hack.override  # noqa: F401
-
-from distutils import log
-from distutils.util import convert_path
-
-_Path = Union[str, os.PathLike]
-_Filter = Callable[[str], bool]
-StrIter = Iterator[str]
-
-chain_iter = itertools.chain.from_iterable
-
-if TYPE_CHECKING:
-    from setuptools import Distribution  # noqa
-
-
-def _valid_name(path: _Path) -> bool:
-    # Ignore invalid names that cannot be imported directly
-    return os.path.basename(path).isidentifier()
-
-
-class _Finder:
-    """Base class that exposes functionality for module/package finders"""
-
-    ALWAYS_EXCLUDE: Tuple[str, ...] = ()
-    DEFAULT_EXCLUDE: Tuple[str, ...] = ()
-
-    @classmethod
-    def find(
-        cls,
-        where: _Path = '.',
-        exclude: Iterable[str] = (),
-        include: Iterable[str] = ('*',)
-    ) -> List[str]:
-        """Return a list of all Python items (packages or modules, depending on
-        the finder implementation) found within directory 'where'.
-
-        'where' is the root directory which will be searched.
-        It should be supplied as a "cross-platform" (i.e. URL-style) path;
-        it will be converted to the appropriate local path syntax.
-
-        'exclude' is a sequence of names to exclude; '*' can be used
-        as a wildcard in the names.
-        When finding packages, 'foo.*' will exclude all subpackages of 'foo'
-        (but not 'foo' itself).
-
-        'include' is a sequence of names to include.
-        If it's specified, only the named items will be included.
-        If it's not specified, all found items will be included.
-        'include' can contain shell style wildcard patterns just like
-        'exclude'.
-        """
-
-        exclude = exclude or cls.DEFAULT_EXCLUDE
-        return list(
-            cls._find_iter(
-                convert_path(str(where)),
-                cls._build_filter(*cls.ALWAYS_EXCLUDE, *exclude),
-                cls._build_filter(*include),
-            )
-        )
-
-    @classmethod
-    def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter:
-        raise NotImplementedError
-
-    @staticmethod
-    def _build_filter(*patterns: str) -> _Filter:
-        """
-        Given a list of patterns, return a callable that will be true only if
-        the input matches at least one of the patterns.
-        """
-        return lambda name: any(fnmatchcase(name, pat) for pat in patterns)
-
-
-class PackageFinder(_Finder):
-    """
-    Generate a list of all Python packages found within a directory
-    """
-
-    ALWAYS_EXCLUDE = ("ez_setup", "*__pycache__")
-
-    @classmethod
-    def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter:
-        """
-        All the packages found in 'where' that pass the 'include' filter, but
-        not the 'exclude' filter.
-        """
-        for root, dirs, files in os.walk(str(where), followlinks=True):
-            # Copy dirs to iterate over it, then empty dirs.
-            all_dirs = dirs[:]
-            dirs[:] = []
-
-            for dir in all_dirs:
-                full_path = os.path.join(root, dir)
-                rel_path = os.path.relpath(full_path, where)
-                package = rel_path.replace(os.path.sep, '.')
-
-                # Skip directory trees that are not valid packages
-                if '.' in dir or not cls._looks_like_package(full_path, package):
-                    continue
-
-                # Should this package be included?
-                if include(package) and not exclude(package):
-                    yield package
-
-                # Keep searching subdirectories, as there may be more packages
-                # down there, even if the parent was excluded.
-                dirs.append(dir)
-
-    @staticmethod
-    def _looks_like_package(path: _Path, _package_name: str) -> bool:
-        """Does a directory look like a package?"""
-        return os.path.isfile(os.path.join(path, '__init__.py'))
-
-
-class PEP420PackageFinder(PackageFinder):
-    @staticmethod
-    def _looks_like_package(_path: _Path, _package_name: str) -> bool:
-        return True
-
-
-class ModuleFinder(_Finder):
-    """Find isolated Python modules.
-    This function will **not** recurse subdirectories.
-    """
-
-    @classmethod
-    def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter:
-        for file in glob(os.path.join(where, "*.py")):
-            module, _ext = os.path.splitext(os.path.basename(file))
-
-            if not cls._looks_like_module(module):
-                continue
-
-            if include(module) and not exclude(module):
-                yield module
-
-    _looks_like_module = staticmethod(_valid_name)
-
-
-# We have to be extra careful in the case of flat layout to not include files
-# and directories not meant for distribution (e.g. tool-related)
-
-
-class FlatLayoutPackageFinder(PEP420PackageFinder):
-    _EXCLUDE = (
-        "ci",
-        "bin",
-        "doc",
-        "docs",
-        "documentation",
-        "manpages",
-        "news",
-        "changelog",
-        "test",
-        "tests",
-        "unit_test",
-        "unit_tests",
-        "example",
-        "examples",
-        "scripts",
-        "tools",
-        "util",
-        "utils",
-        "python",
-        "build",
-        "dist",
-        "venv",
-        "env",
-        "requirements",
-        # ---- Task runners / Build tools ----
-        "tasks",  # invoke
-        "fabfile",  # fabric
-        "site_scons",  # SCons
-        # ---- Other tools ----
-        "benchmark",
-        "benchmarks",
-        "exercise",
-        "exercises",
-        # ---- Hidden directories/Private packages ----
-        "[._]*",
-    )
-
-    DEFAULT_EXCLUDE = tuple(chain_iter((p, f"{p}.*") for p in _EXCLUDE))
-    """Reserved package names"""
-
-    @staticmethod
-    def _looks_like_package(_path: _Path, package_name: str) -> bool:
-        names = package_name.split('.')
-        # Consider PEP 561
-        root_pkg_is_valid = names[0].isidentifier() or names[0].endswith("-stubs")
-        return root_pkg_is_valid and all(name.isidentifier() for name in names[1:])
-
-
-class FlatLayoutModuleFinder(ModuleFinder):
-    DEFAULT_EXCLUDE = (
-        "setup",
-        "conftest",
-        "test",
-        "tests",
-        "example",
-        "examples",
-        "build",
-        # ---- Task runners ----
-        "toxfile",
-        "noxfile",
-        "pavement",
-        "dodo",
-        "tasks",
-        "fabfile",
-        # ---- Other tools ----
-        "[Ss][Cc]onstruct",  # SCons
-        "conanfile",  # Connan: C/C++ build tool
-        "manage",  # Django
-        "benchmark",
-        "benchmarks",
-        "exercise",
-        "exercises",
-        "htmlcov",
-        # ---- Hidden files/Private modules ----
-        "[._]*",
-    )
-    """Reserved top-level module names"""
-
-
-def _find_packages_within(root_pkg: str, pkg_dir: _Path) -> List[str]:
-    nested = PEP420PackageFinder.find(pkg_dir)
-    return [root_pkg] + [".".join((root_pkg, n)) for n in nested]
-
-
-class ConfigDiscovery:
-    """Fill-in metadata and options that can be automatically derived
-    (from other metadata/options, the file system or conventions)
-    """
-
-    def __init__(self, distribution: "Distribution"):
-        self.dist = distribution
-        self._called = False
-        self._disabled = False
-        self._skip_ext_modules = False
-
-    def _disable(self):
-        """Internal API to disable automatic discovery"""
-        self._disabled = True
-
-    def _ignore_ext_modules(self):
-        """Internal API to disregard ext_modules.
-
-        Normally auto-discovery would not be triggered if ``ext_modules`` are set
-        (this is done for backward compatibility with existing packages relying on
-        ``setup.py`` or ``setup.cfg``). However, ``setuptools`` can call this function
-        to ignore given ``ext_modules`` and proceed with the auto-discovery if
-        ``packages`` and ``py_modules`` are not given (e.g. when using pyproject.toml
-        metadata).
-        """
-        self._skip_ext_modules = True
-
-    @property
-    def _root_dir(self) -> _Path:
-        # The best is to wait until `src_root` is set in dist, before using _root_dir.
-        return self.dist.src_root or os.curdir
-
-    @property
-    def _package_dir(self) -> Dict[str, str]:
-        if self.dist.package_dir is None:
-            return {}
-        return self.dist.package_dir
-
-    def __call__(self, force=False, name=True, ignore_ext_modules=False):
-        """Automatically discover missing configuration fields
-        and modifies the given ``distribution`` object in-place.
-
-        Note that by default this will only have an effect the first time the
-        ``ConfigDiscovery`` object is called.
-
-        To repeatedly invoke automatic discovery (e.g. when the project
-        directory changes), please use ``force=True`` (or create a new
-        ``ConfigDiscovery`` instance).
-        """
-        if force is False and (self._called or self._disabled):
-            # Avoid overhead of multiple calls
-            return
-
-        self._analyse_package_layout(ignore_ext_modules)
-        if name:
-            self.analyse_name()  # depends on ``packages`` and ``py_modules``
-
-        self._called = True
-
-    def _explicitly_specified(self, ignore_ext_modules: bool) -> bool:
-        """``True`` if the user has specified some form of package/module listing"""
-        ignore_ext_modules = ignore_ext_modules or self._skip_ext_modules
-        ext_modules = not (self.dist.ext_modules is None or ignore_ext_modules)
-        return (
-            self.dist.packages is not None
-            or self.dist.py_modules is not None
-            or ext_modules
-            or hasattr(self.dist, "configuration") and self.dist.configuration
-            # ^ Some projects use numpy.distutils.misc_util.Configuration
-        )
-
-    def _analyse_package_layout(self, ignore_ext_modules: bool) -> bool:
-        if self._explicitly_specified(ignore_ext_modules):
-            # For backward compatibility, just try to find modules/packages
-            # when nothing is given
-            return True
-
-        log.debug(
-            "No `packages` or `py_modules` configuration, performing "
-            "automatic discovery."
-        )
-
-        return (
-            self._analyse_explicit_layout()
-            or self._analyse_src_layout()
-            # flat-layout is the trickiest for discovery so it should be last
-            or self._analyse_flat_layout()
-        )
-
-    def _analyse_explicit_layout(self) -> bool:
-        """The user can explicitly give a package layout via ``package_dir``"""
-        package_dir = self._package_dir.copy()  # don't modify directly
-        package_dir.pop("", None)  # This falls under the "src-layout" umbrella
-        root_dir = self._root_dir
-
-        if not package_dir:
-            return False
-
-        log.debug(f"`explicit-layout` detected -- analysing {package_dir}")
-        pkgs = chain_iter(
-            _find_packages_within(pkg, os.path.join(root_dir, parent_dir))
-            for pkg, parent_dir in package_dir.items()
-        )
-        self.dist.packages = list(pkgs)
-        log.debug(f"discovered packages -- {self.dist.packages}")
-        return True
-
-    def _analyse_src_layout(self) -> bool:
-        """Try to find all packages or modules under the ``src`` directory
-        (or anything pointed by ``package_dir[""]``).
-
-        The "src-layout" is relatively safe for automatic discovery.
-        We assume that everything within is meant to be included in the
-        distribution.
-
-        If ``package_dir[""]`` is not given, but the ``src`` directory exists,
-        this function will set ``package_dir[""] = "src"``.
-        """
-        package_dir = self._package_dir
-        src_dir = os.path.join(self._root_dir, package_dir.get("", "src"))
-        if not os.path.isdir(src_dir):
-            return False
-
-        log.debug(f"`src-layout` detected -- analysing {src_dir}")
-        package_dir.setdefault("", os.path.basename(src_dir))
-        self.dist.package_dir = package_dir  # persist eventual modifications
-        self.dist.packages = PEP420PackageFinder.find(src_dir)
-        self.dist.py_modules = ModuleFinder.find(src_dir)
-        log.debug(f"discovered packages -- {self.dist.packages}")
-        log.debug(f"discovered py_modules -- {self.dist.py_modules}")
-        return True
-
-    def _analyse_flat_layout(self) -> bool:
-        """Try to find all packages and modules under the project root.
-
-        Since the ``flat-layout`` is more dangerous in terms of accidentally including
-        extra files/directories, this function is more conservative and will raise an
-        error if multiple packages or modules are found.
-
-        This assumes that multi-package dists are uncommon and refuse to support that
-        use case in order to be able to prevent unintended errors.
-        """
-        log.debug(f"`flat-layout` detected -- analysing {self._root_dir}")
-        return self._analyse_flat_packages() or self._analyse_flat_modules()
-
-    def _analyse_flat_packages(self) -> bool:
-        self.dist.packages = FlatLayoutPackageFinder.find(self._root_dir)
-        top_level = remove_nested_packages(remove_stubs(self.dist.packages))
-        log.debug(f"discovered packages -- {self.dist.packages}")
-        self._ensure_no_accidental_inclusion(top_level, "packages")
-        return bool(top_level)
-
-    def _analyse_flat_modules(self) -> bool:
-        self.dist.py_modules = FlatLayoutModuleFinder.find(self._root_dir)
-        log.debug(f"discovered py_modules -- {self.dist.py_modules}")
-        self._ensure_no_accidental_inclusion(self.dist.py_modules, "modules")
-        return bool(self.dist.py_modules)
-
-    def _ensure_no_accidental_inclusion(self, detected: List[str], kind: str):
-        if len(detected) > 1:
-            from inspect import cleandoc
-
-            from setuptools.errors import PackageDiscoveryError
-
-            msg = f"""Multiple top-level {kind} discovered in a flat-layout: {detected}.
-
-            To avoid accidental inclusion of unwanted files or directories,
-            setuptools will not proceed with this build.
-
-            If you are trying to create a single distribution with multiple {kind}
-            on purpose, you should not rely on automatic discovery.
-            Instead, consider the following options:
-
-            1. set up custom discovery (`find` directive with `include` or `exclude`)
-            2. use a `src-layout`
-            3. explicitly set `py_modules` or `packages` with a list of names
-
-            To find more information, look for "package discovery" on setuptools docs.
-            """
-            raise PackageDiscoveryError(cleandoc(msg))
-
-    def analyse_name(self):
-        """The packages/modules are the essential contribution of the author.
-        Therefore the name of the distribution can be derived from them.
-        """
-        if self.dist.metadata.name or self.dist.name:
-            # get_name() is not reliable (can return "UNKNOWN")
-            return None
-
-        log.debug("No `name` configuration, performing automatic discovery")
-
-        name = (
-            self._find_name_single_package_or_module()
-            or self._find_name_from_packages()
-        )
-        if name:
-            self.dist.metadata.name = name
-
-    def _find_name_single_package_or_module(self) -> Optional[str]:
-        """Exactly one module or package"""
-        for field in ('packages', 'py_modules'):
-            items = getattr(self.dist, field, None) or []
-            if items and len(items) == 1:
-                log.debug(f"Single module/package detected, name: {items[0]}")
-                return items[0]
-
-        return None
-
-    def _find_name_from_packages(self) -> Optional[str]:
-        """Try to find the root package that is not a PEP 420 namespace"""
-        if not self.dist.packages:
-            return None
-
-        packages = remove_stubs(sorted(self.dist.packages, key=len))
-        package_dir = self.dist.package_dir or {}
-
-        parent_pkg = find_parent_package(packages, package_dir, self._root_dir)
-        if parent_pkg:
-            log.debug(f"Common parent package detected, name: {parent_pkg}")
-            return parent_pkg
-
-        log.warn("No parent package detected, impossible to derive `name`")
-        return None
-
-
-def remove_nested_packages(packages: List[str]) -> List[str]:
-    """Remove nested packages from a list of packages.
-
-    >>> remove_nested_packages(["a", "a.b1", "a.b2", "a.b1.c1"])
-    ['a']
-    >>> remove_nested_packages(["a", "b", "c.d", "c.d.e.f", "g.h", "a.a1"])
-    ['a', 'b', 'c.d', 'g.h']
-    """
-    pkgs = sorted(packages, key=len)
-    top_level = pkgs[:]
-    size = len(pkgs)
-    for i, name in enumerate(reversed(pkgs)):
-        if any(name.startswith(f"{other}.") for other in top_level):
-            top_level.pop(size - i - 1)
-
-    return top_level
-
-
-def remove_stubs(packages: List[str]) -> List[str]:
-    """Remove type stubs (:pep:`561`) from a list of packages.
-
-    >>> remove_stubs(["a", "a.b", "a-stubs", "a-stubs.b.c", "b", "c-stubs"])
-    ['a', 'a.b', 'b']
-    """
-    return [pkg for pkg in packages if not pkg.split(".")[0].endswith("-stubs")]
-
-
-def find_parent_package(
-    packages: List[str], package_dir: Mapping[str, str], root_dir: _Path
-) -> Optional[str]:
-    """Find the parent package that is not a namespace."""
-    packages = sorted(packages, key=len)
-    common_ancestors = []
-    for i, name in enumerate(packages):
-        if not all(n.startswith(f"{name}.") for n in packages[i+1:]):
-            # Since packages are sorted by length, this condition is able
-            # to find a list of all common ancestors.
-            # When there is divergence (e.g. multiple root packages)
-            # the list will be empty
-            break
-        common_ancestors.append(name)
-
-    for name in common_ancestors:
-        pkg_path = find_package_path(name, package_dir, root_dir)
-        init = os.path.join(pkg_path, "__init__.py")
-        if os.path.isfile(init):
-            return name
-
-    return None
-
-
-def find_package_path(
-    name: str, package_dir: Mapping[str, str], root_dir: _Path
-) -> str:
-    """Given a package name, return the path where it should be found on
-    disk, considering the ``package_dir`` option.
-
-    >>> path = find_package_path("my.pkg", {"": "root/is/nested"}, ".")
-    >>> path.replace(os.sep, "/")
-    './root/is/nested/my/pkg'
-
-    >>> path = find_package_path("my.pkg", {"my": "root/is/nested"}, ".")
-    >>> path.replace(os.sep, "/")
-    './root/is/nested/pkg'
-
-    >>> path = find_package_path("my.pkg", {"my.pkg": "root/is/nested"}, ".")
-    >>> path.replace(os.sep, "/")
-    './root/is/nested'
-
-    >>> path = find_package_path("other.pkg", {"my.pkg": "root/is/nested"}, ".")
-    >>> path.replace(os.sep, "/")
-    './other/pkg'
-    """
-    parts = name.split(".")
-    for i in range(len(parts), 0, -1):
-        # Look backwards, the most specific package_dir first
-        partial_name = ".".join(parts[:i])
-        if partial_name in package_dir:
-            parent = package_dir[partial_name]
-            return os.path.join(root_dir, parent, *parts[i:])
-
-    parent = package_dir.get("") or ""
-    return os.path.join(root_dir, *parent.split("/"), *parts)
-
-
-def construct_package_dir(packages: List[str], package_path: _Path) -> Dict[str, str]:
-    parent_pkgs = remove_nested_packages(packages)
-    prefix = Path(package_path).parts
-    return {pkg: "/".join([*prefix, *pkg.split(".")]) for pkg in parent_pkgs}
diff --git a/venv/lib/python3.11/site-packages/setuptools/dist.py b/venv/lib/python3.11/site-packages/setuptools/dist.py
deleted file mode 100755
index 32fff13..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/dist.py
+++ /dev/null
@@ -1,1218 +0,0 @@
-__all__ = ['Distribution']
-
-import io
-import sys
-import re
-import os
-import warnings
-import numbers
-import distutils.log
-import distutils.core
-import distutils.cmd
-import distutils.dist
-import distutils.command
-from distutils.util import strtobool
-from distutils.debug import DEBUG
-from distutils.fancy_getopt import translate_longopt
-from glob import iglob
-import itertools
-import textwrap
-from typing import List, Optional, Set, TYPE_CHECKING
-from pathlib import Path
-
-from collections import defaultdict
-from email import message_from_file
-
-from distutils.errors import DistutilsOptionError, DistutilsSetupError
-from distutils.util import rfc822_escape
-
-from setuptools.extern import packaging
-from setuptools.extern import ordered_set
-from setuptools.extern.more_itertools import unique_everseen, partition
-
-from ._importlib import metadata
-
-from . import SetuptoolsDeprecationWarning
-
-import setuptools
-import setuptools.command
-from setuptools import windows_support
-from setuptools.monkey import get_unpatched
-from setuptools.config import setupcfg, pyprojecttoml
-from setuptools.discovery import ConfigDiscovery
-
-import pkg_resources
-from setuptools.extern.packaging import version
-from . import _reqs
-from . import _entry_points
-
-if TYPE_CHECKING:
-    from email.message import Message
-
-__import__('setuptools.extern.packaging.specifiers')
-__import__('setuptools.extern.packaging.version')
-
-
-def _get_unpatched(cls):
-    warnings.warn("Do not call this function", DistDeprecationWarning)
-    return get_unpatched(cls)
-
-
-def get_metadata_version(self):
-    mv = getattr(self, 'metadata_version', None)
-    if mv is None:
-        mv = version.Version('2.1')
-        self.metadata_version = mv
-    return mv
-
-
-def rfc822_unescape(content: str) -> str:
-    """Reverse RFC-822 escaping by removing leading whitespaces from content."""
-    lines = content.splitlines()
-    if len(lines) == 1:
-        return lines[0].lstrip()
-    return '\n'.join((lines[0].lstrip(), textwrap.dedent('\n'.join(lines[1:]))))
-
-
-def _read_field_from_msg(msg: "Message", field: str) -> Optional[str]:
-    """Read Message header field."""
-    value = msg[field]
-    if value == 'UNKNOWN':
-        return None
-    return value
-
-
-def _read_field_unescaped_from_msg(msg: "Message", field: str) -> Optional[str]:
-    """Read Message header field and apply rfc822_unescape."""
-    value = _read_field_from_msg(msg, field)
-    if value is None:
-        return value
-    return rfc822_unescape(value)
-
-
-def _read_list_from_msg(msg: "Message", field: str) -> Optional[List[str]]:
-    """Read Message header field and return all results as list."""
-    values = msg.get_all(field, None)
-    if values == []:
-        return None
-    return values
-
-
-def _read_payload_from_msg(msg: "Message") -> Optional[str]:
-    value = msg.get_payload().strip()
-    if value == 'UNKNOWN' or not value:
-        return None
-    return value
-
-
-def read_pkg_file(self, file):
-    """Reads the metadata values from a file object."""
-    msg = message_from_file(file)
-
-    self.metadata_version = version.Version(msg['metadata-version'])
-    self.name = _read_field_from_msg(msg, 'name')
-    self.version = _read_field_from_msg(msg, 'version')
-    self.description = _read_field_from_msg(msg, 'summary')
-    # we are filling author only.
-    self.author = _read_field_from_msg(msg, 'author')
-    self.maintainer = None
-    self.author_email = _read_field_from_msg(msg, 'author-email')
-    self.maintainer_email = None
-    self.url = _read_field_from_msg(msg, 'home-page')
-    self.download_url = _read_field_from_msg(msg, 'download-url')
-    self.license = _read_field_unescaped_from_msg(msg, 'license')
-
-    self.long_description = _read_field_unescaped_from_msg(msg, 'description')
-    if (
-        self.long_description is None and
-        self.metadata_version >= version.Version('2.1')
-    ):
-        self.long_description = _read_payload_from_msg(msg)
-    self.description = _read_field_from_msg(msg, 'summary')
-
-    if 'keywords' in msg:
-        self.keywords = _read_field_from_msg(msg, 'keywords').split(',')
-
-    self.platforms = _read_list_from_msg(msg, 'platform')
-    self.classifiers = _read_list_from_msg(msg, 'classifier')
-
-    # PEP 314 - these fields only exist in 1.1
-    if self.metadata_version == version.Version('1.1'):
-        self.requires = _read_list_from_msg(msg, 'requires')
-        self.provides = _read_list_from_msg(msg, 'provides')
-        self.obsoletes = _read_list_from_msg(msg, 'obsoletes')
-    else:
-        self.requires = None
-        self.provides = None
-        self.obsoletes = None
-
-    self.license_files = _read_list_from_msg(msg, 'license-file')
-
-
-def single_line(val):
-    """
-    Quick and dirty validation for Summary pypa/setuptools#1390.
-    """
-    if '\n' in val:
-        # TODO: Replace with `raise ValueError("newlines not allowed")`
-        # after reviewing #2893.
-        warnings.warn("newlines not allowed and will break in the future")
-        val = val.strip().split('\n')[0]
-    return val
-
-
-# Based on Python 3.5 version
-def write_pkg_file(self, file):  # noqa: C901  # is too complex (14)  # FIXME
-    """Write the PKG-INFO format data to a file object."""
-    version = self.get_metadata_version()
-
-    def write_field(key, value):
-        file.write("%s: %s\n" % (key, value))
-
-    write_field('Metadata-Version', str(version))
-    write_field('Name', self.get_name())
-    write_field('Version', self.get_version())
-
-    summary = self.get_description()
-    if summary:
-        write_field('Summary', single_line(summary))
-
-    optional_fields = (
-        ('Home-page', 'url'),
-        ('Download-URL', 'download_url'),
-        ('Author', 'author'),
-        ('Author-email', 'author_email'),
-        ('Maintainer', 'maintainer'),
-        ('Maintainer-email', 'maintainer_email'),
-    )
-
-    for field, attr in optional_fields:
-        attr_val = getattr(self, attr, None)
-        if attr_val is not None:
-            write_field(field, attr_val)
-
-    license = self.get_license()
-    if license:
-        write_field('License', rfc822_escape(license))
-
-    for project_url in self.project_urls.items():
-        write_field('Project-URL', '%s, %s' % project_url)
-
-    keywords = ','.join(self.get_keywords())
-    if keywords:
-        write_field('Keywords', keywords)
-
-    platforms = self.get_platforms() or []
-    for platform in platforms:
-        write_field('Platform', platform)
-
-    self._write_list(file, 'Classifier', self.get_classifiers())
-
-    # PEP 314
-    self._write_list(file, 'Requires', self.get_requires())
-    self._write_list(file, 'Provides', self.get_provides())
-    self._write_list(file, 'Obsoletes', self.get_obsoletes())
-
-    # Setuptools specific for PEP 345
-    if hasattr(self, 'python_requires'):
-        write_field('Requires-Python', self.python_requires)
-
-    # PEP 566
-    if self.long_description_content_type:
-        write_field('Description-Content-Type', self.long_description_content_type)
-    if self.provides_extras:
-        for extra in sorted(self.provides_extras):
-            write_field('Provides-Extra', extra)
-
-    self._write_list(file, 'License-File', self.license_files or [])
-
-    long_description = self.get_long_description()
-    if long_description:
-        file.write("\n%s" % long_description)
-        if not long_description.endswith("\n"):
-            file.write("\n")
-
-
-sequence = tuple, list
-
-
-def check_importable(dist, attr, value):
-    try:
-        ep = metadata.EntryPoint(value=value, name=None, group=None)
-        assert not ep.extras
-    except (TypeError, ValueError, AttributeError, AssertionError) as e:
-        raise DistutilsSetupError(
-            "%r must be importable 'module:attrs' string (got %r)" % (attr, value)
-        ) from e
-
-
-def assert_string_list(dist, attr, value):
-    """Verify that value is a string list"""
-    try:
-        # verify that value is a list or tuple to exclude unordered
-        # or single-use iterables
-        assert isinstance(value, (list, tuple))
-        # verify that elements of value are strings
-        assert ''.join(value) != value
-    except (TypeError, ValueError, AttributeError, AssertionError) as e:
-        raise DistutilsSetupError(
-            "%r must be a list of strings (got %r)" % (attr, value)
-        ) from e
-
-
-def check_nsp(dist, attr, value):
-    """Verify that namespace packages are valid"""
-    ns_packages = value
-    assert_string_list(dist, attr, ns_packages)
-    for nsp in ns_packages:
-        if not dist.has_contents_for(nsp):
-            raise DistutilsSetupError(
-                "Distribution contains no modules or packages for "
-                + "namespace package %r" % nsp
-            )
-        parent, sep, child = nsp.rpartition('.')
-        if parent and parent not in ns_packages:
-            distutils.log.warn(
-                "WARNING: %r is declared as a package namespace, but %r"
-                " is not: please correct this in setup.py",
-                nsp,
-                parent,
-            )
-        msg = (
-            "The namespace_packages parameter is deprecated, "
-            "consider using implicit namespaces instead (PEP 420)."
-        )
-        warnings.warn(msg, SetuptoolsDeprecationWarning)
-
-
-def check_extras(dist, attr, value):
-    """Verify that extras_require mapping is valid"""
-    try:
-        list(itertools.starmap(_check_extra, value.items()))
-    except (TypeError, ValueError, AttributeError) as e:
-        raise DistutilsSetupError(
-            "'extras_require' must be a dictionary whose values are "
-            "strings or lists of strings containing valid project/version "
-            "requirement specifiers."
-        ) from e
-
-
-def _check_extra(extra, reqs):
-    name, sep, marker = extra.partition(':')
-    if marker and pkg_resources.invalid_marker(marker):
-        raise DistutilsSetupError("Invalid environment marker: " + marker)
-    list(_reqs.parse(reqs))
-
-
-def assert_bool(dist, attr, value):
-    """Verify that value is True, False, 0, or 1"""
-    if bool(value) != value:
-        tmpl = "{attr!r} must be a boolean value (got {value!r})"
-        raise DistutilsSetupError(tmpl.format(attr=attr, value=value))
-
-
-def invalid_unless_false(dist, attr, value):
-    if not value:
-        warnings.warn(f"{attr} is ignored.", DistDeprecationWarning)
-        return
-    raise DistutilsSetupError(f"{attr} is invalid.")
-
-
-def check_requirements(dist, attr, value):
-    """Verify that install_requires is a valid requirements list"""
-    try:
-        list(_reqs.parse(value))
-        if isinstance(value, (dict, set)):
-            raise TypeError("Unordered types are not allowed")
-    except (TypeError, ValueError) as error:
-        tmpl = (
-            "{attr!r} must be a string or list of strings "
-            "containing valid project/version requirement specifiers; {error}"
-        )
-        raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error
-
-
-def check_specifier(dist, attr, value):
-    """Verify that value is a valid version specifier"""
-    try:
-        packaging.specifiers.SpecifierSet(value)
-    except (packaging.specifiers.InvalidSpecifier, AttributeError) as error:
-        tmpl = (
-            "{attr!r} must be a string " "containing valid version specifiers; {error}"
-        )
-        raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error
-
-
-def check_entry_points(dist, attr, value):
-    """Verify that entry_points map is parseable"""
-    try:
-        _entry_points.load(value)
-    except Exception as e:
-        raise DistutilsSetupError(e) from e
-
-
-def check_test_suite(dist, attr, value):
-    if not isinstance(value, str):
-        raise DistutilsSetupError("test_suite must be a string")
-
-
-def check_package_data(dist, attr, value):
-    """Verify that value is a dictionary of package names to glob lists"""
-    if not isinstance(value, dict):
-        raise DistutilsSetupError(
-            "{!r} must be a dictionary mapping package names to lists of "
-            "string wildcard patterns".format(attr)
-        )
-    for k, v in value.items():
-        if not isinstance(k, str):
-            raise DistutilsSetupError(
-                "keys of {!r} dict must be strings (got {!r})".format(attr, k)
-            )
-        assert_string_list(dist, 'values of {!r} dict'.format(attr), v)
-
-
-def check_packages(dist, attr, value):
-    for pkgname in value:
-        if not re.match(r'\w+(\.\w+)*', pkgname):
-            distutils.log.warn(
-                "WARNING: %r not a valid package name; please use only "
-                ".-separated package names in setup.py",
-                pkgname,
-            )
-
-
-_Distribution = get_unpatched(distutils.core.Distribution)
-
-
-class Distribution(_Distribution):
-    """Distribution with support for tests and package data
-
-    This is an enhanced version of 'distutils.dist.Distribution' that
-    effectively adds the following new optional keyword arguments to 'setup()':
-
-     'install_requires' -- a string or sequence of strings specifying project
-        versions that the distribution requires when installed, in the format
-        used by 'pkg_resources.require()'.  They will be installed
-        automatically when the package is installed.  If you wish to use
-        packages that are not available in PyPI, or want to give your users an
-        alternate download location, you can add a 'find_links' option to the
-        '[easy_install]' section of your project's 'setup.cfg' file, and then
-        setuptools will scan the listed web pages for links that satisfy the
-        requirements.
-
-     'extras_require' -- a dictionary mapping names of optional "extras" to the
-        additional requirement(s) that using those extras incurs. For example,
-        this::
-
-            extras_require = dict(reST = ["docutils>=0.3", "reSTedit"])
-
-        indicates that the distribution can optionally provide an extra
-        capability called "reST", but it can only be used if docutils and
-        reSTedit are installed.  If the user installs your package using
-        EasyInstall and requests one of your extras, the corresponding
-        additional requirements will be installed if needed.
-
-     'test_suite' -- the name of a test suite to run for the 'test' command.
-        If the user runs 'python setup.py test', the package will be installed,
-        and the named test suite will be run.  The format is the same as
-        would be used on a 'unittest.py' command line.  That is, it is the
-        dotted name of an object to import and call to generate a test suite.
-
-     'package_data' -- a dictionary mapping package names to lists of filenames
-        or globs to use to find data files contained in the named packages.
-        If the dictionary has filenames or globs listed under '""' (the empty
-        string), those names will be searched for in every package, in addition
-        to any names for the specific package.  Data files found using these
-        names/globs will be installed along with the package, in the same
-        location as the package.  Note that globs are allowed to reference
-        the contents of non-package subdirectories, as long as you use '/' as
-        a path separator.  (Globs are automatically converted to
-        platform-specific paths at runtime.)
-
-    In addition to these new keywords, this class also has several new methods
-    for manipulating the distribution's contents.  For example, the 'include()'
-    and 'exclude()' methods can be thought of as in-place add and subtract
-    commands that add or remove packages, modules, extensions, and so on from
-    the distribution.
-    """
-
-    _DISTUTILS_UNSUPPORTED_METADATA = {
-        'long_description_content_type': lambda: None,
-        'project_urls': dict,
-        'provides_extras': ordered_set.OrderedSet,
-        'license_file': lambda: None,
-        'license_files': lambda: None,
-    }
-
-    _patched_dist = None
-
-    def patch_missing_pkg_info(self, attrs):
-        # Fake up a replacement for the data that would normally come from
-        # PKG-INFO, but which might not yet be built if this is a fresh
-        # checkout.
-        #
-        if not attrs or 'name' not in attrs or 'version' not in attrs:
-            return
-        key = pkg_resources.safe_name(str(attrs['name'])).lower()
-        dist = pkg_resources.working_set.by_key.get(key)
-        if dist is not None and not dist.has_metadata('PKG-INFO'):
-            dist._version = pkg_resources.safe_version(str(attrs['version']))
-            self._patched_dist = dist
-
-    def __init__(self, attrs=None):
-        have_package_data = hasattr(self, "package_data")
-        if not have_package_data:
-            self.package_data = {}
-        attrs = attrs or {}
-        self.dist_files = []
-        # Filter-out setuptools' specific options.
-        self.src_root = attrs.pop("src_root", None)
-        self.patch_missing_pkg_info(attrs)
-        self.dependency_links = attrs.pop('dependency_links', [])
-        self.setup_requires = attrs.pop('setup_requires', [])
-        for ep in metadata.entry_points(group='distutils.setup_keywords'):
-            vars(self).setdefault(ep.name, None)
-        _Distribution.__init__(
-            self,
-            {
-                k: v
-                for k, v in attrs.items()
-                if k not in self._DISTUTILS_UNSUPPORTED_METADATA
-            },
-        )
-
-        # Private API (setuptools-use only, not restricted to Distribution)
-        # Stores files that are referenced by the configuration and need to be in the
-        # sdist (e.g. `version = file: VERSION.txt`)
-        self._referenced_files: Set[str] = set()
-
-        # Save the original dependencies before they are processed into the egg format
-        self._orig_extras_require = {}
-        self._orig_install_requires = []
-        self._tmp_extras_require = defaultdict(ordered_set.OrderedSet)
-
-        self.set_defaults = ConfigDiscovery(self)
-
-        self._set_metadata_defaults(attrs)
-
-        self.metadata.version = self._normalize_version(
-            self._validate_version(self.metadata.version)
-        )
-        self._finalize_requires()
-
-    def _validate_metadata(self):
-        required = {"name"}
-        provided = {
-            key
-            for key in vars(self.metadata)
-            if getattr(self.metadata, key, None) is not None
-        }
-        missing = required - provided
-
-        if missing:
-            msg = f"Required package metadata is missing: {missing}"
-            raise DistutilsSetupError(msg)
-
-    def _set_metadata_defaults(self, attrs):
-        """
-        Fill-in missing metadata fields not supported by distutils.
-        Some fields may have been set by other tools (e.g. pbr).
-        Those fields (vars(self.metadata)) take precedence to
-        supplied attrs.
-        """
-        for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items():
-            vars(self.metadata).setdefault(option, attrs.get(option, default()))
-
-    @staticmethod
-    def _normalize_version(version):
-        if isinstance(version, setuptools.sic) or version is None:
-            return version
-
-        normalized = str(packaging.version.Version(version))
-        if version != normalized:
-            tmpl = "Normalizing '{version}' to '{normalized}'"
-            warnings.warn(tmpl.format(**locals()))
-            return normalized
-        return version
-
-    @staticmethod
-    def _validate_version(version):
-        if isinstance(version, numbers.Number):
-            # Some people apparently take "version number" too literally :)
-            version = str(version)
-
-        if version is not None:
-            try:
-                packaging.version.Version(version)
-            except (packaging.version.InvalidVersion, TypeError):
-                warnings.warn(
-                    "The version specified (%r) is an invalid version, this "
-                    "may not work as expected with newer versions of "
-                    "setuptools, pip, and PyPI. Please see PEP 440 for more "
-                    "details." % version
-                )
-                return setuptools.sic(version)
-        return version
-
-    def _finalize_requires(self):
-        """
-        Set `metadata.python_requires` and fix environment markers
-        in `install_requires` and `extras_require`.
-        """
-        if getattr(self, 'python_requires', None):
-            self.metadata.python_requires = self.python_requires
-
-        if getattr(self, 'extras_require', None):
-            # Save original before it is messed by _convert_extras_requirements
-            self._orig_extras_require = self._orig_extras_require or self.extras_require
-            for extra in self.extras_require.keys():
-                # Since this gets called multiple times at points where the
-                # keys have become 'converted' extras, ensure that we are only
-                # truly adding extras we haven't seen before here.
-                extra = extra.split(':')[0]
-                if extra:
-                    self.metadata.provides_extras.add(extra)
-
-        if getattr(self, 'install_requires', None) and not self._orig_install_requires:
-            # Save original before it is messed by _move_install_requirements_markers
-            self._orig_install_requires = self.install_requires
-
-        self._convert_extras_requirements()
-        self._move_install_requirements_markers()
-
-    def _convert_extras_requirements(self):
-        """
-        Convert requirements in `extras_require` of the form
-        `"extra": ["barbazquux; {marker}"]` to
-        `"extra:{marker}": ["barbazquux"]`.
-        """
-        spec_ext_reqs = getattr(self, 'extras_require', None) or {}
-        tmp = defaultdict(ordered_set.OrderedSet)
-        self._tmp_extras_require = getattr(self, '_tmp_extras_require', tmp)
-        for section, v in spec_ext_reqs.items():
-            # Do not strip empty sections.
-            self._tmp_extras_require[section]
-            for r in _reqs.parse(v):
-                suffix = self._suffix_for(r)
-                self._tmp_extras_require[section + suffix].append(r)
-
-    @staticmethod
-    def _suffix_for(req):
-        """
-        For a requirement, return the 'extras_require' suffix for
-        that requirement.
-        """
-        return ':' + str(req.marker) if req.marker else ''
-
-    def _move_install_requirements_markers(self):
-        """
-        Move requirements in `install_requires` that are using environment
-        markers `extras_require`.
-        """
-
-        # divide the install_requires into two sets, simple ones still
-        # handled by install_requires and more complex ones handled
-        # by extras_require.
-
-        def is_simple_req(req):
-            return not req.marker
-
-        spec_inst_reqs = getattr(self, 'install_requires', None) or ()
-        inst_reqs = list(_reqs.parse(spec_inst_reqs))
-        simple_reqs = filter(is_simple_req, inst_reqs)
-        complex_reqs = itertools.filterfalse(is_simple_req, inst_reqs)
-        self.install_requires = list(map(str, simple_reqs))
-
-        for r in complex_reqs:
-            self._tmp_extras_require[':' + str(r.marker)].append(r)
-        self.extras_require = dict(
-            # list(dict.fromkeys(...))  ensures a list of unique strings
-            (k, list(dict.fromkeys(str(r) for r in map(self._clean_req, v))))
-            for k, v in self._tmp_extras_require.items()
-        )
-
-    def _clean_req(self, req):
-        """
-        Given a Requirement, remove environment markers and return it.
-        """
-        req.marker = None
-        return req
-
-    def _finalize_license_files(self):
-        """Compute names of all license files which should be included."""
-        license_files: Optional[List[str]] = self.metadata.license_files
-        patterns: List[str] = license_files if license_files else []
-
-        license_file: Optional[str] = self.metadata.license_file
-        if license_file and license_file not in patterns:
-            patterns.append(license_file)
-
-        if license_files is None and license_file is None:
-            # Default patterns match the ones wheel uses
-            # See https://wheel.readthedocs.io/en/stable/user_guide.html
-            # -> 'Including license files in the generated wheel file'
-            patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*')
-
-        self.metadata.license_files = list(
-            unique_everseen(self._expand_patterns(patterns))
-        )
-
-    @staticmethod
-    def _expand_patterns(patterns):
-        """
-        >>> list(Distribution._expand_patterns(['LICENSE']))
-        ['LICENSE']
-        >>> list(Distribution._expand_patterns(['setup.cfg', 'LIC*']))
-        ['setup.cfg', 'LICENSE']
-        """
-        return (
-            path
-            for pattern in patterns
-            for path in sorted(iglob(pattern))
-            if not path.endswith('~') and os.path.isfile(path)
-        )
-
-    # FIXME: 'Distribution._parse_config_files' is too complex (14)
-    def _parse_config_files(self, filenames=None):  # noqa: C901
-        """
-        Adapted from distutils.dist.Distribution.parse_config_files,
-        this method provides the same functionality in subtly-improved
-        ways.
-        """
-        from configparser import ConfigParser
-
-        # Ignore install directory options if we have a venv
-        ignore_options = (
-            []
-            if sys.prefix == sys.base_prefix
-            else [
-                'install-base',
-                'install-platbase',
-                'install-lib',
-                'install-platlib',
-                'install-purelib',
-                'install-headers',
-                'install-scripts',
-                'install-data',
-                'prefix',
-                'exec-prefix',
-                'home',
-                'user',
-                'root',
-            ]
-        )
-
-        ignore_options = frozenset(ignore_options)
-
-        if filenames is None:
-            filenames = self.find_config_files()
-
-        if DEBUG:
-            self.announce("Distribution.parse_config_files():")
-
-        parser = ConfigParser()
-        parser.optionxform = str
-        for filename in filenames:
-            with io.open(filename, encoding='utf-8') as reader:
-                if DEBUG:
-                    self.announce("  reading {filename}".format(**locals()))
-                parser.read_file(reader)
-            for section in parser.sections():
-                options = parser.options(section)
-                opt_dict = self.get_option_dict(section)
-
-                for opt in options:
-                    if opt == '__name__' or opt in ignore_options:
-                        continue
-
-                    val = parser.get(section, opt)
-                    opt = self.warn_dash_deprecation(opt, section)
-                    opt = self.make_option_lowercase(opt, section)
-                    opt_dict[opt] = (filename, val)
-
-            # Make the ConfigParser forget everything (so we retain
-            # the original filenames that options come from)
-            parser.__init__()
-
-        if 'global' not in self.command_options:
-            return
-
-        # If there was a "global" section in the config file, use it
-        # to set Distribution options.
-
-        for (opt, (src, val)) in self.command_options['global'].items():
-            alias = self.negative_opt.get(opt)
-            if alias:
-                val = not strtobool(val)
-            elif opt in ('verbose', 'dry_run'):  # ugh!
-                val = strtobool(val)
-
-            try:
-                setattr(self, alias or opt, val)
-            except ValueError as e:
-                raise DistutilsOptionError(e) from e
-
-    def warn_dash_deprecation(self, opt, section):
-        if section in (
-            'options.extras_require',
-            'options.data_files',
-        ):
-            return opt
-
-        underscore_opt = opt.replace('-', '_')
-        commands = list(itertools.chain(
-            distutils.command.__all__,
-            self._setuptools_commands(),
-        ))
-        if (
-            not section.startswith('options')
-            and section != 'metadata'
-            and section not in commands
-        ):
-            return underscore_opt
-
-        if '-' in opt:
-            warnings.warn(
-                "Usage of dash-separated '%s' will not be supported in future "
-                "versions. Please use the underscore name '%s' instead"
-                % (opt, underscore_opt)
-            )
-        return underscore_opt
-
-    def _setuptools_commands(self):
-        try:
-            return metadata.distribution('setuptools').entry_points.names
-        except metadata.PackageNotFoundError:
-            # during bootstrapping, distribution doesn't exist
-            return []
-
-    def make_option_lowercase(self, opt, section):
-        if section != 'metadata' or opt.islower():
-            return opt
-
-        lowercase_opt = opt.lower()
-        warnings.warn(
-            "Usage of uppercase key '%s' in '%s' will be deprecated in future "
-            "versions. Please use lowercase '%s' instead"
-            % (opt, section, lowercase_opt)
-        )
-        return lowercase_opt
-
-    # FIXME: 'Distribution._set_command_options' is too complex (14)
-    def _set_command_options(self, command_obj, option_dict=None):  # noqa: C901
-        """
-        Set the options for 'command_obj' from 'option_dict'.  Basically
-        this means copying elements of a dictionary ('option_dict') to
-        attributes of an instance ('command').
-
-        'command_obj' must be a Command instance.  If 'option_dict' is not
-        supplied, uses the standard option dictionary for this command
-        (from 'self.command_options').
-
-        (Adopted from distutils.dist.Distribution._set_command_options)
-        """
-        command_name = command_obj.get_command_name()
-        if option_dict is None:
-            option_dict = self.get_option_dict(command_name)
-
-        if DEBUG:
-            self.announce("  setting options for '%s' command:" % command_name)
-        for (option, (source, value)) in option_dict.items():
-            if DEBUG:
-                self.announce("    %s = %s (from %s)" % (option, value, source))
-            try:
-                bool_opts = [translate_longopt(o) for o in command_obj.boolean_options]
-            except AttributeError:
-                bool_opts = []
-            try:
-                neg_opt = command_obj.negative_opt
-            except AttributeError:
-                neg_opt = {}
-
-            try:
-                is_string = isinstance(value, str)
-                if option in neg_opt and is_string:
-                    setattr(command_obj, neg_opt[option], not strtobool(value))
-                elif option in bool_opts and is_string:
-                    setattr(command_obj, option, strtobool(value))
-                elif hasattr(command_obj, option):
-                    setattr(command_obj, option, value)
-                else:
-                    raise DistutilsOptionError(
-                        "error in %s: command '%s' has no such option '%s'"
-                        % (source, command_name, option)
-                    )
-            except ValueError as e:
-                raise DistutilsOptionError(e) from e
-
-    def _get_project_config_files(self, filenames):
-        """Add default file and split between INI and TOML"""
-        tomlfiles = []
-        standard_project_metadata = Path(self.src_root or os.curdir, "pyproject.toml")
-        if filenames is not None:
-            parts = partition(lambda f: Path(f).suffix == ".toml", filenames)
-            filenames = list(parts[0])  # 1st element => predicate is False
-            tomlfiles = list(parts[1])  # 2nd element => predicate is True
-        elif standard_project_metadata.exists():
-            tomlfiles = [standard_project_metadata]
-        return filenames, tomlfiles
-
-    def parse_config_files(self, filenames=None, ignore_option_errors=False):
-        """Parses configuration files from various levels
-        and loads configuration.
-        """
-        inifiles, tomlfiles = self._get_project_config_files(filenames)
-
-        self._parse_config_files(filenames=inifiles)
-
-        setupcfg.parse_configuration(
-            self, self.command_options, ignore_option_errors=ignore_option_errors
-        )
-        for filename in tomlfiles:
-            pyprojecttoml.apply_configuration(self, filename, ignore_option_errors)
-
-        self._finalize_requires()
-        self._finalize_license_files()
-
-    def fetch_build_eggs(self, requires):
-        """Resolve pre-setup requirements"""
-        resolved_dists = pkg_resources.working_set.resolve(
-            _reqs.parse(requires),
-            installer=self.fetch_build_egg,
-            replace_conflicting=True,
-        )
-        for dist in resolved_dists:
-            pkg_resources.working_set.add(dist, replace=True)
-        return resolved_dists
-
-    def finalize_options(self):
-        """
-        Allow plugins to apply arbitrary operations to the
-        distribution. Each hook may optionally define a 'order'
-        to influence the order of execution. Smaller numbers
-        go first and the default is 0.
-        """
-        group = 'setuptools.finalize_distribution_options'
-
-        def by_order(hook):
-            return getattr(hook, 'order', 0)
-
-        defined = metadata.entry_points(group=group)
-        filtered = itertools.filterfalse(self._removed, defined)
-        loaded = map(lambda e: e.load(), filtered)
-        for ep in sorted(loaded, key=by_order):
-            ep(self)
-
-    @staticmethod
-    def _removed(ep):
-        """
-        When removing an entry point, if metadata is loaded
-        from an older version of Setuptools, that removed
-        entry point will attempt to be loaded and will fail.
-        See #2765 for more details.
-        """
-        removed = {
-            # removed 2021-09-05
-            '2to3_doctests',
-        }
-        return ep.name in removed
-
-    def _finalize_setup_keywords(self):
-        for ep in metadata.entry_points(group='distutils.setup_keywords'):
-            value = getattr(self, ep.name, None)
-            if value is not None:
-                ep.load()(self, ep.name, value)
-
-    def get_egg_cache_dir(self):
-        egg_cache_dir = os.path.join(os.curdir, '.eggs')
-        if not os.path.exists(egg_cache_dir):
-            os.mkdir(egg_cache_dir)
-            windows_support.hide_file(egg_cache_dir)
-            readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
-            with open(readme_txt_filename, 'w') as f:
-                f.write(
-                    'This directory contains eggs that were downloaded '
-                    'by setuptools to build, test, and run plug-ins.\n\n'
-                )
-                f.write(
-                    'This directory caches those eggs to prevent '
-                    'repeated downloads.\n\n'
-                )
-                f.write('However, it is safe to delete this directory.\n\n')
-
-        return egg_cache_dir
-
-    def fetch_build_egg(self, req):
-        """Fetch an egg needed for building"""
-        from setuptools.installer import fetch_build_egg
-
-        return fetch_build_egg(self, req)
-
-    def get_command_class(self, command):
-        """Pluggable version of get_command_class()"""
-        if command in self.cmdclass:
-            return self.cmdclass[command]
-
-        eps = metadata.entry_points(group='distutils.commands', name=command)
-        for ep in eps:
-            self.cmdclass[command] = cmdclass = ep.load()
-            return cmdclass
-        else:
-            return _Distribution.get_command_class(self, command)
-
-    def print_commands(self):
-        for ep in metadata.entry_points(group='distutils.commands'):
-            if ep.name not in self.cmdclass:
-                cmdclass = ep.load()
-                self.cmdclass[ep.name] = cmdclass
-        return _Distribution.print_commands(self)
-
-    def get_command_list(self):
-        for ep in metadata.entry_points(group='distutils.commands'):
-            if ep.name not in self.cmdclass:
-                cmdclass = ep.load()
-                self.cmdclass[ep.name] = cmdclass
-        return _Distribution.get_command_list(self)
-
-    def include(self, **attrs):
-        """Add items to distribution that are named in keyword arguments
-
-        For example, 'dist.include(py_modules=["x"])' would add 'x' to
-        the distribution's 'py_modules' attribute, if it was not already
-        there.
-
-        Currently, this method only supports inclusion for attributes that are
-        lists or tuples.  If you need to add support for adding to other
-        attributes in this or a subclass, you can add an '_include_X' method,
-        where 'X' is the name of the attribute.  The method will be called with
-        the value passed to 'include()'.  So, 'dist.include(foo={"bar":"baz"})'
-        will try to call 'dist._include_foo({"bar":"baz"})', which can then
-        handle whatever special inclusion logic is needed.
-        """
-        for k, v in attrs.items():
-            include = getattr(self, '_include_' + k, None)
-            if include:
-                include(v)
-            else:
-                self._include_misc(k, v)
-
-    def exclude_package(self, package):
-        """Remove packages, modules, and extensions in named package"""
-
-        pfx = package + '.'
-        if self.packages:
-            self.packages = [
-                p for p in self.packages if p != package and not p.startswith(pfx)
-            ]
-
-        if self.py_modules:
-            self.py_modules = [
-                p for p in self.py_modules if p != package and not p.startswith(pfx)
-            ]
-
-        if self.ext_modules:
-            self.ext_modules = [
-                p
-                for p in self.ext_modules
-                if p.name != package and not p.name.startswith(pfx)
-            ]
-
-    def has_contents_for(self, package):
-        """Return true if 'exclude_package(package)' would do something"""
-
-        pfx = package + '.'
-
-        for p in self.iter_distribution_names():
-            if p == package or p.startswith(pfx):
-                return True
-
-    def _exclude_misc(self, name, value):
-        """Handle 'exclude()' for list/tuple attrs without a special handler"""
-        if not isinstance(value, sequence):
-            raise DistutilsSetupError(
-                "%s: setting must be a list or tuple (%r)" % (name, value)
-            )
-        try:
-            old = getattr(self, name)
-        except AttributeError as e:
-            raise DistutilsSetupError("%s: No such distribution setting" % name) from e
-        if old is not None and not isinstance(old, sequence):
-            raise DistutilsSetupError(
-                name + ": this setting cannot be changed via include/exclude"
-            )
-        elif old:
-            setattr(self, name, [item for item in old if item not in value])
-
-    def _include_misc(self, name, value):
-        """Handle 'include()' for list/tuple attrs without a special handler"""
-
-        if not isinstance(value, sequence):
-            raise DistutilsSetupError("%s: setting must be a list (%r)" % (name, value))
-        try:
-            old = getattr(self, name)
-        except AttributeError as e:
-            raise DistutilsSetupError("%s: No such distribution setting" % name) from e
-        if old is None:
-            setattr(self, name, value)
-        elif not isinstance(old, sequence):
-            raise DistutilsSetupError(
-                name + ": this setting cannot be changed via include/exclude"
-            )
-        else:
-            new = [item for item in value if item not in old]
-            setattr(self, name, old + new)
-
-    def exclude(self, **attrs):
-        """Remove items from distribution that are named in keyword arguments
-
-        For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from
-        the distribution's 'py_modules' attribute.  Excluding packages uses
-        the 'exclude_package()' method, so all of the package's contained
-        packages, modules, and extensions are also excluded.
-
-        Currently, this method only supports exclusion from attributes that are
-        lists or tuples.  If you need to add support for excluding from other
-        attributes in this or a subclass, you can add an '_exclude_X' method,
-        where 'X' is the name of the attribute.  The method will be called with
-        the value passed to 'exclude()'.  So, 'dist.exclude(foo={"bar":"baz"})'
-        will try to call 'dist._exclude_foo({"bar":"baz"})', which can then
-        handle whatever special exclusion logic is needed.
-        """
-        for k, v in attrs.items():
-            exclude = getattr(self, '_exclude_' + k, None)
-            if exclude:
-                exclude(v)
-            else:
-                self._exclude_misc(k, v)
-
-    def _exclude_packages(self, packages):
-        if not isinstance(packages, sequence):
-            raise DistutilsSetupError(
-                "packages: setting must be a list or tuple (%r)" % (packages,)
-            )
-        list(map(self.exclude_package, packages))
-
-    def _parse_command_opts(self, parser, args):
-        # Remove --with-X/--without-X options when processing command args
-        self.global_options = self.__class__.global_options
-        self.negative_opt = self.__class__.negative_opt
-
-        # First, expand any aliases
-        command = args[0]
-        aliases = self.get_option_dict('aliases')
-        while command in aliases:
-            src, alias = aliases[command]
-            del aliases[command]  # ensure each alias can expand only once!
-            import shlex
-
-            args[:1] = shlex.split(alias, True)
-            command = args[0]
-
-        nargs = _Distribution._parse_command_opts(self, parser, args)
-
-        # Handle commands that want to consume all remaining arguments
-        cmd_class = self.get_command_class(command)
-        if getattr(cmd_class, 'command_consumes_arguments', None):
-            self.get_option_dict(command)['args'] = ("command line", nargs)
-            if nargs is not None:
-                return []
-
-        return nargs
-
-    def get_cmdline_options(self):
-        """Return a '{cmd: {opt:val}}' map of all command-line options
-
-        Option names are all long, but do not include the leading '--', and
-        contain dashes rather than underscores.  If the option doesn't take
-        an argument (e.g. '--quiet'), the 'val' is 'None'.
-
-        Note that options provided by config files are intentionally excluded.
-        """
-
-        d = {}
-
-        for cmd, opts in self.command_options.items():
-
-            for opt, (src, val) in opts.items():
-
-                if src != "command line":
-                    continue
-
-                opt = opt.replace('_', '-')
-
-                if val == 0:
-                    cmdobj = self.get_command_obj(cmd)
-                    neg_opt = self.negative_opt.copy()
-                    neg_opt.update(getattr(cmdobj, 'negative_opt', {}))
-                    for neg, pos in neg_opt.items():
-                        if pos == opt:
-                            opt = neg
-                            val = None
-                            break
-                    else:
-                        raise AssertionError("Shouldn't be able to get here")
-
-                elif val == 1:
-                    val = None
-
-                d.setdefault(cmd, {})[opt] = val
-
-        return d
-
-    def iter_distribution_names(self):
-        """Yield all packages, modules, and extension names in distribution"""
-
-        for pkg in self.packages or ():
-            yield pkg
-
-        for module in self.py_modules or ():
-            yield module
-
-        for ext in self.ext_modules or ():
-            if isinstance(ext, tuple):
-                name, buildinfo = ext
-            else:
-                name = ext.name
-            if name.endswith('module'):
-                name = name[:-6]
-            yield name
-
-    def handle_display_options(self, option_order):
-        """If there were any non-global "display-only" options
-        (--help-commands or the metadata display options) on the command
-        line, display the requested info and return true; else return
-        false.
-        """
-        import sys
-
-        if self.help_commands:
-            return _Distribution.handle_display_options(self, option_order)
-
-        # Stdout may be StringIO (e.g. in tests)
-        if not isinstance(sys.stdout, io.TextIOWrapper):
-            return _Distribution.handle_display_options(self, option_order)
-
-        # Don't wrap stdout if utf-8 is already the encoding. Provides
-        #  workaround for #334.
-        if sys.stdout.encoding.lower() in ('utf-8', 'utf8'):
-            return _Distribution.handle_display_options(self, option_order)
-
-        # Print metadata in UTF-8 no matter the platform
-        encoding = sys.stdout.encoding
-        sys.stdout.reconfigure(encoding='utf-8')
-        try:
-            return _Distribution.handle_display_options(self, option_order)
-        finally:
-            sys.stdout.reconfigure(encoding=encoding)
-
-    def run_command(self, command):
-        self.set_defaults()
-        # Postpone defaults until all explicit configuration is considered
-        # (setup() args, config files, command line and plugins)
-
-        super().run_command(command)
-
-
-class DistDeprecationWarning(SetuptoolsDeprecationWarning):
-    """Class for warning about deprecations in dist in
-    setuptools. Not ignored by default, unlike DeprecationWarning."""
diff --git a/venv/lib/python3.11/site-packages/setuptools/errors.py b/venv/lib/python3.11/site-packages/setuptools/errors.py
deleted file mode 100755
index ec7fb3b..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/errors.py
+++ /dev/null
@@ -1,58 +0,0 @@
-"""setuptools.errors
-
-Provides exceptions used by setuptools modules.
-"""
-
-from distutils import errors as _distutils_errors
-
-
-# Re-export errors from distutils to facilitate the migration to PEP632
-
-ByteCompileError = _distutils_errors.DistutilsByteCompileError
-CCompilerError = _distutils_errors.CCompilerError
-ClassError = _distutils_errors.DistutilsClassError
-CompileError = _distutils_errors.CompileError
-ExecError = _distutils_errors.DistutilsExecError
-FileError = _distutils_errors.DistutilsFileError
-InternalError = _distutils_errors.DistutilsInternalError
-LibError = _distutils_errors.LibError
-LinkError = _distutils_errors.LinkError
-ModuleError = _distutils_errors.DistutilsModuleError
-OptionError = _distutils_errors.DistutilsOptionError
-PlatformError = _distutils_errors.DistutilsPlatformError
-PreprocessError = _distutils_errors.PreprocessError
-SetupError = _distutils_errors.DistutilsSetupError
-TemplateError = _distutils_errors.DistutilsTemplateError
-UnknownFileError = _distutils_errors.UnknownFileError
-
-# The root error class in the hierarchy
-BaseError = _distutils_errors.DistutilsError
-
-
-class RemovedCommandError(BaseError, RuntimeError):
-    """Error used for commands that have been removed in setuptools.
-
-    Since ``setuptools`` is built on ``distutils``, simply removing a command
-    from ``setuptools`` will make the behavior fall back to ``distutils``; this
-    error is raised if a command exists in ``distutils`` but has been actively
-    removed in ``setuptools``.
-    """
-
-
-class PackageDiscoveryError(BaseError, RuntimeError):
-    """Impossible to perform automatic discovery of packages and/or modules.
-
-    The current project layout or given discovery options can lead to problems when
-    scanning the project directory.
-
-    Setuptools might also refuse to complete auto-discovery if an error prone condition
-    is detected (e.g. when a project is organised as a flat-layout but contains
-    multiple directories that can be taken as top-level packages inside a single
-    distribution [*]_). In these situations the users are encouraged to be explicit
-    about which packages to include or to make the discovery parameters more specific.
-
-    .. [*] Since multi-package distributions are uncommon it is very likely that the
-       developers did not intend for all the directories to be packaged, and are just
-       leaving auxiliary code in the repository top-level, such as maintenance-related
-       scripts.
-    """
diff --git a/venv/lib/python3.11/site-packages/setuptools/extension.py b/venv/lib/python3.11/site-packages/setuptools/extension.py
deleted file mode 100755
index 58c023f..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/extension.py
+++ /dev/null
@@ -1,148 +0,0 @@
-import re
-import functools
-import distutils.core
-import distutils.errors
-import distutils.extension
-
-from .monkey import get_unpatched
-
-
-def _have_cython():
-    """
-    Return True if Cython can be imported.
-    """
-    cython_impl = 'Cython.Distutils.build_ext'
-    try:
-        # from (cython_impl) import build_ext
-        __import__(cython_impl, fromlist=['build_ext']).build_ext
-        return True
-    except Exception:
-        pass
-    return False
-
-
-# for compatibility
-have_pyrex = _have_cython
-
-_Extension = get_unpatched(distutils.core.Extension)
-
-
-class Extension(_Extension):
-    """
-    Describes a single extension module.
-
-    This means that all source files will be compiled into a single binary file
-    ``.`` (with ```` derived from ``name`` and
-    ```` defined by one of the values in
-    ``importlib.machinery.EXTENSION_SUFFIXES``).
-
-    In the case ``.pyx`` files are passed as ``sources and`` ``Cython`` is **not**
-    installed in the build environment, ``setuptools`` may also try to look for the
-    equivalent ``.cpp`` or ``.c`` files.
-
-    :arg str name:
-      the full name of the extension, including any packages -- ie.
-      *not* a filename or pathname, but Python dotted name
-
-    :arg list[str] sources:
-      list of source filenames, relative to the distribution root
-      (where the setup script lives), in Unix form (slash-separated)
-      for portability.  Source files may be C, C++, SWIG (.i),
-      platform-specific resource files, or whatever else is recognized
-      by the "build_ext" command as source for a Python extension.
-
-    :keyword list[str] include_dirs:
-      list of directories to search for C/C++ header files (in Unix
-      form for portability)
-
-    :keyword list[tuple[str, str|None]] define_macros:
-      list of macros to define; each macro is defined using a 2-tuple:
-      the first item corresponding to the name of the macro and the second
-      item either a string with its value or None to
-      define it without a particular value (equivalent of "#define
-      FOO" in source or -DFOO on Unix C compiler command line)
-
-    :keyword list[str] undef_macros:
-      list of macros to undefine explicitly
-
-    :keyword list[str] library_dirs:
-      list of directories to search for C/C++ libraries at link time
-
-    :keyword list[str] libraries:
-      list of library names (not filenames or paths) to link against
-
-    :keyword list[str] runtime_library_dirs:
-      list of directories to search for C/C++ libraries at run time
-      (for shared extensions, this is when the extension is loaded).
-      Setting this will cause an exception during build on Windows
-      platforms.
-
-    :keyword list[str] extra_objects:
-      list of extra files to link with (eg. object files not implied
-      by 'sources', static library that must be explicitly specified,
-      binary resource files, etc.)
-
-    :keyword list[str] extra_compile_args:
-      any extra platform- and compiler-specific information to use
-      when compiling the source files in 'sources'.  For platforms and
-      compilers where "command line" makes sense, this is typically a
-      list of command-line arguments, but for other platforms it could
-      be anything.
-
-    :keyword list[str] extra_link_args:
-      any extra platform- and compiler-specific information to use
-      when linking object files together to create the extension (or
-      to create a new static Python interpreter).  Similar
-      interpretation as for 'extra_compile_args'.
-
-    :keyword list[str] export_symbols:
-      list of symbols to be exported from a shared extension.  Not
-      used on all platforms, and not generally necessary for Python
-      extensions, which typically export exactly one symbol: "init" +
-      extension_name.
-
-    :keyword list[str] swig_opts:
-      any extra options to pass to SWIG if a source file has the .i
-      extension.
-
-    :keyword list[str] depends:
-      list of files that the extension depends on
-
-    :keyword str language:
-      extension language (i.e. "c", "c++", "objc"). Will be detected
-      from the source extensions if not provided.
-
-    :keyword bool optional:
-      specifies that a build failure in the extension should not abort the
-      build process, but simply not install the failing extension.
-
-    :keyword bool py_limited_api:
-      opt-in flag for the usage of :doc:`Python's limited API `.
-
-    :raises setuptools.errors.PlatformError: if 'runtime_library_dirs' is
-      specified on Windows. (since v63)
-    """
-
-    def __init__(self, name, sources, *args, **kw):
-        # The *args is needed for compatibility as calls may use positional
-        # arguments. py_limited_api may be set only via keyword.
-        self.py_limited_api = kw.pop("py_limited_api", False)
-        super().__init__(name, sources, *args, **kw)
-
-    def _convert_pyx_sources_to_lang(self):
-        """
-        Replace sources with .pyx extensions to sources with the target
-        language extension. This mechanism allows language authors to supply
-        pre-converted sources but to prefer the .pyx sources.
-        """
-        if _have_cython():
-            # the build has Cython, so allow it to compile the .pyx files
-            return
-        lang = self.language or ''
-        target_ext = '.cpp' if lang.lower() == 'c++' else '.c'
-        sub = functools.partial(re.sub, '.pyx$', target_ext)
-        self.sources = list(map(sub, self.sources))
-
-
-class Library(Extension):
-    """Just like a regular Extension, but built as a library instead"""
diff --git a/venv/lib/python3.11/site-packages/setuptools/extern/__init__.py b/venv/lib/python3.11/site-packages/setuptools/extern/__init__.py
deleted file mode 100755
index d3a6dc9..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/extern/__init__.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import importlib.util
-import sys
-
-
-class VendorImporter:
-    """
-    A PEP 302 meta path importer for finding optionally-vendored
-    or otherwise naturally-installed packages from root_name.
-    """
-
-    def __init__(self, root_name, vendored_names=(), vendor_pkg=None):
-        self.root_name = root_name
-        self.vendored_names = set(vendored_names)
-        self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor')
-
-    @property
-    def search_path(self):
-        """
-        Search first the vendor package then as a natural package.
-        """
-        yield self.vendor_pkg + '.'
-        yield ''
-
-    def _module_matches_namespace(self, fullname):
-        """Figure out if the target module is vendored."""
-        root, base, target = fullname.partition(self.root_name + '.')
-        return not root and any(map(target.startswith, self.vendored_names))
-
-    def load_module(self, fullname):
-        """
-        Iterate over the search path to locate and load fullname.
-        """
-        root, base, target = fullname.partition(self.root_name + '.')
-        for prefix in self.search_path:
-            try:
-                extant = prefix + target
-                __import__(extant)
-                mod = sys.modules[extant]
-                sys.modules[fullname] = mod
-                return mod
-            except ImportError:
-                pass
-        else:
-            raise ImportError(
-                "The '{target}' package is required; "
-                "normally this is bundled with this package so if you get "
-                "this warning, consult the packager of your "
-                "distribution.".format(**locals())
-            )
-
-    def create_module(self, spec):
-        return self.load_module(spec.name)
-
-    def exec_module(self, module):
-        pass
-
-    def find_spec(self, fullname, path=None, target=None):
-        """Return a module spec for vendored names."""
-        return (
-            importlib.util.spec_from_loader(fullname, self)
-            if self._module_matches_namespace(fullname) else None
-        )
-
-    def install(self):
-        """
-        Install this importer into sys.meta_path if not already present.
-        """
-        if self not in sys.meta_path:
-            sys.meta_path.append(self)
-
-
-names = (
-    'packaging', 'pyparsing', 'ordered_set', 'more_itertools', 'importlib_metadata',
-    'zipp', 'importlib_resources', 'jaraco', 'typing_extensions', 'tomli',
-)
-VendorImporter(__name__, names, 'setuptools._vendor').install()
diff --git a/venv/lib/python3.11/site-packages/setuptools/extern/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/extern/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index f49085545f24e0830b84e3c5fe1c064b34bf736e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4395
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

diff --git a/venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe b/venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe
deleted file mode 100755
index 5730f11d5c09df7758cfa1b1dfb5ced4bf2ce55c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 137728
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%0Ax*H)YN%7KBxJojF;|-
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
z
zuc4jxwz7KJ_rCH-tFJ@z@NXc!Qxa$m*N_NRtT_d&`a7duuH`>P
zd%}h`&|B{GYny6$%@oA-ep8*S_YbNQ*wMBx)7fGDgK2FaWZ0dLJaOehDVhGlqZp`r
z7Zz^Qt{~7!1nOpo+s>!!UDMjSGVG3o1-MTD`U{)X0)7~njK(aO!mRqVS*o4ZX4diz
z7)@AzBH#*!OwC!#-^rCEBXGL5j{ilBGXRTvrZEnIJKR9see4J
z?c)sQ$RrZUz7CZ}&@|&(WWQ6oZG7`cz^_)daDP69Az2FAzJQhYnWChD$L)$+G%bx
z&7w9mR1|a&sE6y@t-J-J@>a|Gc{fUJ9G}Xg6OuprJK#0?Jp<5bfq@`8o;q|BAqcJM
zjQ48!rGWu;JZ~b>4p%t2&K3ny&6
z)6|T!KS#l1EVxey4i&6w$J3D-fJnmY;zyL&4M}ieC4Y4zD_DwoiJ30
z5_=SJD^>f%DnzwDB3tkBl@`9nM7`62cB()9jX5~Dm1WqE>OH3SAe#W)`7_C8+pfMB
zJFd=-^{P|*4uT0K)k$y3)D9UFllj~KNTvgXauGr@LJse7Q7R@RDA(z2H9$+ML+eE&
zl=voVrX{czY;0=zrsg&^7y3DBQcnlbCHkTK6wlSv)Ot^a>WupS(t25KWYtdJD_Ul0
zy-WLUG9529T3YX>gnVr^CFHB&()t2Q@MyPDf=8_?tuNH(m)6hH=0j$@t^Sg!YDQJ1
zuYFT*)BGE?V&5z3C3>UFt~~e`G$NV?B%)>wUwRqg;i@z=IXRJXAM6bDgMFlKS|1}*
zTJt0-&ot@>P~uYMKt_iv`@icGQ&50s{!#;tR+P0W?sZB=UJS
z28Qw#@F%T&Xsr_aIZ!Op21>PA8)rgy4p7O3{6Pz%JAtoM$hIO)F4a7n)$
z761{^!~%XE(hSewuU#=}f4+5c{H|(n(tWZhp^o;Mq!<
zRjo5}SyjYX;$XSHob{6zO6oY4v*QvB236~|OfFpmxC~b5@TKpZgpU&#G7W#1xq3O3
z<3MV!e|?(f)~nX1p%Pni43kl^-$5TcR@NVMSZL^H&E-&ixCRksAc
zLU`VdHD75rv;+qczU;=DL2Y_V&_vjEBUm9@4-7a;8wVN=CKo8r`Ay}yo6Te;LW2km
zCg&ma6+&MnuR~}6p@HNqtG1-l;zB9z8^>xc|3Wh`P+C9Ga0W~Xtd-{^<+-e)w&b4$
z@#5nT;nQH;igvjVF^ojjTuW_pKostir4{9NA29mEyNid}uN|4TxhrlC)WdXd>FZ
z?h-VBx_toZ4Q;2-s*De{^r4;Sf;^URlfi%h+fm{Ob0O76slOabjS9;G-(|(y5k&(3
zek#h$5I=h*8r>7(VIL+i{Pd0V+%%S+M@0Bp@q8Q%5#q(@z7U^EjPS`!G$(+(`k}%-
z#O*6nN~f#>J!8|-`3^7o1-QI(ZAuFGL9cj-g!Tk8}ZggIXanNhBaH*
z%$w8Ym-akCd{i@ElJ?9)6rRw2KnzPg>MHL
zWA%sB4CVRi!%2H|Ot>Z(icp)l{Aa9616{Nh!pveS`i2Ma03DLWEO3U&EX$~V4~xO)
zi_s8B{5_ln-a`((@w7x)Y?Ng>9x2X(W=@XB{D&Y@N&83*@i)+~?fi2zqnK&lp^`u!hZ&&FuC{jXb#dH{4o*tBfc6Xo9PY^qOa0PMpSJ{ZCzqsyow}p
zf%MA>yy
z&-gy^>=Dmb#gmKYQSodQ&%=1~zFyPB`l*;#0}pG&_qGPaB!9U}cE=Aq(N(&^msURe%fvtfy@-U04P7ip72!ds&zS{&BQP
zfb0S1(?^*E(%8XXe_@jn|0by6J>q*uiPa<2GTum>1O`T;OFUo1v-y$F@r)f;V$*<6
zxxSwOBxBbhyp$c;NNYJb+cR(3rm@O_gUW%XWqQ=+o~LhwQWXHG_$SW
z5jNrvBb%>H`Q9&KJunO7*TYN%sn3?(GrjM9l7u$cB1!?on^i
zxm~?p=dyZfRh62Dm=dqUXFWmia`&ynVMq6Z;jpdSi|}><(*!Z>E*$=p)}4=V)0bCj
zv$1@#`k8GT@C_RK2^%GGo{Z!or=xEdC3Sy{6c(r8w_3+22VPE8$VUwk?|v1ZjJ?#d
z?luIe*vr0NEPYiH|0;?VH0b^(Q6Pm!7br@3K$LQ`y0q!bh+5I~B~(@{BERM
z?U4}bzJtJg>$C~wsYFPs)mz=A_+;Vl>b`0??CGA4aEpE3_1cuC2W)e-iRD9CL7-ID
zLCiMic?H0A0^lhkGFc%~0KX@IHA?JFdf%(WUZeMSFj1hlro{Hsd$SVTOYdb$?3Z{O
zdx;woaT2be^4!6ovG*{7T!u=A;%kW$=Y`c7EJ1>o*h`$ppM(Z)v6oxb##)uwlhE!L
zK|BbE?rM}zjMBeG`2mMsRATo-#`XSMNL
zPiK55szNTw;(m*0{!-DMiCyRLQJA!hU8fN=;!ohIB&twBXPo+q?3dk7A=(!wGR*;f
zmH4Ab9Mw+-q9dQRF(aRtkO%#|sinU_GzQmLfG(6X%$CM}s#}Tu+JSZPpq9P+VJHV9
zPKiuBJL5!5YDD)oz~~%Qe-}8Rt@jtTDY45@HnsU*=;L2kq0UjBUo;Smkm)WFrzQsz
zaZ(FGek(>;EF>{BP3w%4xKbs_@hyu6ngw8|fTKh!qlHy>F)CtYnXuY`0oli@9KP4p
zxmNRteU+CaBSCFY-H#O=Jk~#|5j}R|7;01ZpAg)=bGW@hevqcf-LE5A?_aO{-~#Ga
zVjtqE_ur%Jcu}N(Q~CZ}jI(RqYcK--f`
z*$u-u^BYl7987l&tm;-akLp~@;>4P3jf|vh1&xdm!gT*1BCt>!eya-TOo@qvzBZ|e
zQ2iNDWtptbp?AvNZz7_NZTj+?+C3IKAuc7urGmA#W*FkVeLpeU9(>ulfC;|b-cb+0
z5TB6^X%XtM(`pIQ=fw7l3m7PqEu?nW_-d^ex*@!pOr$qxsd${!Og_Ogsu`H35A(O_T{B-&NY!RG*-ckbdHk+HO0|vjjb;+l<6Mq$Ue>zCnpS
z2ekn9jv3VFG&VekjGbcGz8tU@^*K}|I^kYGwg>=6O-KB9C~8h~{7t+%<45rXFG$@q
z7euEagA%`$O73*@wt3Wii!!}!nDQtuEgDEVNO&H@L}t+dCE6duOzQXu&}83R+a_*t
z_&PR>?K`O-m-^lvXQA4JXT_&C#wmJUf{F~PzJ;U$!y{?@r5_;)a
ze{z;kSR(>#DXe7X%}ph+4-@QPELf`|eLpD~P<#ctkO^UZ+OJ**V<{Lc%j&ADlKD^D
zh9X7D?5ESzvDO!l)qQ}Km>9K-c6Fh+qFvOf78^LViKdv`C4?Z?Mm>D}Ux7K>T~>yb3k%G<(9(Q-eiF;
zW^X3gPV@i@BfZ3523R;XaoaM4t4g?fQVe|xA*Ok~9;8Dmc9>rVFv`@;FdHt*cs>|&PpyPe0UP`2eD=g
zvFfgbQ|!MPHa(pX@+5W&jIJDok-l1%npPJ!4WXp3E&+NLPGjwF!I|Z_iN$Cc<=?U^
znZZOzzo$!rJI}YV`NpupW2zzj{GeLXVuu9W`n0TN!|A}^<;Os!&SP2^>!5w2kEXSK
zlwqH1ZHplztSactN=M`gEK3rV&LEFnX(6w~j-W+mrHrb}^}uPE_qw+H$a{*Nr4ow8
zzFGz?FS2RJF{5dTqbb?YQR&zY>tcGecNr|O?N!1;-1-;v**su^4QMcbISfGyV8u(}
zHrJScDG^rhPt&Lre=8-P)A48e6~K=WdCcfqdgpaqO6I^4`F
zK}}d6kG*)cjinU7J8j5RgJojK+lx)wDSSUVPHfMn%&-B(Q)XB@^Sg$Yn#i#yh~@O~
zVsRFx43?7=Ef)2sPGY2yYNLx2@%IoSZ-cY2)IzclGvc!#BZ>GNJRx94d^Q3p^_h5&
z!jF)M8oNlT7}k16tTxu}c%&amYj-5hh}SOCB5QZV4~f@Pt>X1d63xedAT%NiI1<&4
zPEnH$n$emj7>RQLVK)z0v#L&k)I^8W+9{AF*2UBSh?;rJK)tBMPMUdlAe0b@qx*u0
zz--_|=gQGEUJdhoI6@_ud5iH05LI|VzDc?VJ|^iFrVO)~h{mtX2Rs^&JPJgM^)vaFePM&_EvDU)I+oE9Fs07GIqHqX
z11^%P9Ja(^f5Yo6;XnHbcrS5cpTmkjM)3ePJsfM5_ylButt7FO8?^&$xs!Gcs?X>b
z2Gv#YpGi2Dv&9d&6BQ4+j6e@0KF|+?vzxumV=x1vQd_)ri+|f97U*XuQLFZPQzNv0
zA%k>}M&Ys)3L$~QjeLSY;hfdNb|6kIP96bux0l|%;oDvCM=09?jfL4?gx*}APLf3?
zdW9{Oqqf`4JW7W@2etzEbQtSkrV7NztT#^ri)SK{5ncM`jbVKA(V8A
zqm5NETDO0WB>jd|L}{&4iQSGss@PZfoA}gSfE3HzR_E;{tLUXvReu=XF_)L7-vPGW
zI1T&ug(LuD|W&H7y!uIhCFTlmu0not*lf@
z%PpJ;soA9gr~1Dvt?jQ$qirwINSJ_!P(z8X|80r;trDZo$YvUmPe56~N*V7}HN7l`
zUbJiFQ3s!dfm&=5g!m1pD2!1O-JKPJcN0a2?d;iL6=5p90XQYcAZI!V9BvPRgvII=
zWVx{*aQ%P2W9=~sEz*<6$Ha^)DE+C
zm#>U`NgC@|U)x7%!fC|bQJSw-Fsaw?)Kw+OUnVmHjbnB*a9TIrTV@F`=E$%dDJoE{
zNHOPT@UOs6VaxZVAY)PTUsB>f>;z*ISlRduY1A6QU9eATGOKj5!%ZL9;a7P+P4oXu
zhQz9+kmfozzo;Lh`0P4(oZbabsc?{gTtRZ;^mW2kS?P?m-mmCgUm2CoWTw8v>Cs;?
zS0SUm)`78mC2JotUs5$NFlJ#(0K^R^uLEPJpG_u$FQLQ_~`{8sIac%$yfJ|br?mbEn9!Zyl#plAg(29qyxaq993=Nu)WqY^=ggyWgg5_M&Y
zpdmD4((h4i*n9jYW9dMOmd~&%XK$OXUQ@bM*2V_;Erb~neJY5aoK)H1r@w}B5jB_~LP
z2GvBz@Gwye!c#g`n=Ob@$5oF-2yJ2=AEdmT4d;TyC9{qB$;>+bA$=O^jVu&HK4E_b
zWIKwTm7;yh4(lJs-b$e-^uex8
z_YNtpTlEe_{|I}9wEOK#Uk`1z=?18z#e^6*kkn=swo*x(4YhC;wXpuQ?+@x&e6FkI
z8K=b5&i4oHt`OV^Qc7$M*n^!!;^NY>CiIo+4e=k6IRnWQ{b0wsmK&RX%S`$|=X#ookhCNZGc?
zMGp@>=Fr1Wk03o((_?+&r6#oIX6-0LNq?%hiiHo%0Lbwe>-T3`g2EIsFYSshpOGWKvb0B0J;;R3Pr9Ne=4_JFJCASN1ch-~a<)#uLsJH92a?)!t@
ziGq7585s9aau52IEp^!s7afJ`bq(Jt%A&4Fp#vW95D%=z4hro*uT^HX!3zQ!R7%dI
z%{YlkWf*Ybj#f5>UUqM5dusBp-*XyMDxo5XAHRVjECJKc!11LP6L%wU4tUl+zKk7)
z-tcbWELAvkSWx|4Lu$xv}(&QQafl&5^VedHR?41qOhCL(SzYfG{apR7rXi
zehd6DB<&$TH((+Lff_Licu&>&&Z=;Xa&GeQ02a#831Q&@0{)cwt77%-W*x#g6dew3
zZ&xR^NH?~t(2;R}5E$jTfD_!&veX^B!!|{mD)!dLfiakI7!4&)nwbF?Q56J6xBCB<2Ts%>w%swm
z5p;*KBsC>VeZc1WcEMA_>6oUa+}=pE|FnRHTlYl^yFJg$z<7}J3wq`~P0uM$(zEyp
zdX_zo=h_{4hs7)BMe&;QsCcD6EMAxH6tAmx;PvNY
z?pKA-Fd&Lp!bN`fM?ZqJfYZweK*9>n#u>pxsO*bYa7Ws&dJ+>Tb%xFz>O`IAsLm=O
zQ2QL1+O_W+C!P+B$?f~bQkVu*9G$TNH?NtfET{|e3vWV$wJOgaW^Kk+2kj|ub+&!r
z%5F<+b^ZM3KYxLSLd)A|w*O+oYkHMGSoBW;P+hf!CE(DpM0
z5b}`~H#WHA9D{t&+~_d#B52-Al#k5v7eFU(YjZ4}1Rw7A4d+_op8>QZP6-}Zt*%b&
z`Wy+$bBC4Z?7qXBCKR>#gNcW8=zG+2J1;>KfMPkenBcs6613dtOvDF}1+@iHGXVyL
zyW9I-&s!VRgnTfUyT5WT@?XTEPx7$YC8f{O>dh`&23to
zF~!xgBb|y(j-~lg9wm7w2?aIp$RKhh<&KyLNYvB=$&f|G&iHAR^HX5#J#vKzvqvZ;
z5zD1q_M?eAJ^F=7o19IHb5YANYaSx^JC#C#K4-ABlVk?97?-pKri`J`C^lj@Tbt2mo!F*JPJ?y@BF^sVe{vm+d
zqdEL61~0Kn00=xne8s}G?|LjIF2RCpJ-QOp0mYg#shJ`Ey|aMdO+dz?2ouoA2GDf?
z9U76r98&W8OgoJV_Ce35rr%IF@VKibjibJerNfk0;jX6-4r)_7(zBJ1RbB^Yju~&e}L^~@^yQUlTv1@
zBA9`54bp31Vp;A`Vs+FFo;0-R!Oux1PR36uu}UPq&R(Gd?_QH
z-I&v|IKQB|xp^Xe=(awPG&MqF<&%bKZr+(s-#&t279BQ>_IM%5!-)So5yF^4AhqV(
zL(&Wq!DjXrC3Eh!|EY
z7vSS$K1aFuPf!CESr0vX5x~160L22pe2&WF2S?JMN02hMS{W-)vY$P42(hb(MT7jG
z0Kgu46=5+oFX{|(T_hbv62&x8SSw;YiXi4Zi37hwjAfQJW6M;XSo$borC~ii8Pgl{
z23`)Za5%9Q4#YA!CT!oYBo>+6HO(c(p3ZS!CvGTNzSBX%-rEqrFFu3
z0Co?&&;<_o%rvUkg%%s5cxToQ5N>rh48y<;K;Ii;b9{a3
ztU9BFw-Hxj#G4%AwBo~BI7~y{qtquD^1>whtP>}mT4}6p>h;5OwHsqC9ZqIF)>vD)
z9`m%V7;6i79wo0|ml|-tf?lQpw*fhjoj*v*f!0om%5|)ayzKeCsC3kNR>)f$KpTZ#
z(oS2Gu8>(A12ijc0u{}-(1z)|n~*@Jn~B)-r;p}a=23i*SyMmcD|z_=^+VW1hTN%f
z(vZ(5bO4ecS%Xg)sAi!w$^tEC9))hiq5*bPOw_*ztWpE_|GlaQ{!Z2H$A+rj`9D={
z=EZ=LI3$p&*UY0PvmQ`%vRUl96ePQckb_@ts@ZwX1kkaveV8H>K#_cc^bsVyzH^9H
z=5C@AQ7jit-+@eej-XrjZy-qM+$X4WAH<%?*C+=za1i?FCX6GUl`D33`!UI0WNdYV
zc!d@**%TtCdBS*zs2`zLnixwFCz2Rj*LOTbOR4gXhi*l@yt6VwDin(KJ|WcL2{ELQ
z01xS2_@d%yBd;a^VFhp+mFvhrvzs^vVRPd;PL|GLdruy6@N~4G9q0j96kkkAf_QJX
z2+%UYGU1xVL=^aR|05&-o+3oyB@x=T#j51j9Ez_8cDG*jM$lQ1uh>l_uohmV!0kO(LP#4N@EEUEoXInA56`O0t{sKJlZJrhT*oyhB*gICN!iv3O#j32>
zek-=3jJlF4`2{6_TwNHotTB0O1lr;fG+}riY+8d}9p6U4L%mdI_0qplMx>#0CAM`P
z^3JT|XEDzY`-GsY?(L>fDo!{8YcSNAFr^I_G8MT({BkOn2e5fU5+J&7BR1$EhzL7*
z)C!{q|C&MXejRWO7HlQ95-6}@;>JkpheGE@o~8F5C;HEPEAq66kR&1Ugosejns4c4
z1cAIHP*Ykbt&Ao)n-mt{*6AhKP?jY%94~Hblx12JK-Y@>_8|Ya
z@ic!yo#WtT9ZhQv^f%X^?+AQJXI8yOn(O;J0_UZLCI
zvK2;A{g4N$!BrACM+=}HS^&Y8>{gx+49pBTn;Or7&0)~d?^^%W(6Xq8yvIX)Ll=!e
z*wS={pMFrA$mhcL+bNOhSZs5^_4yh!1ui~0e3JMy1D}!~Vl@W`hY4^|f7+$QzK1ln
zMAo|oja+PzpfJ7bbNw(p+ns=bCHrT>9ey@n*N$Ez=Xur1SBo$?&gYQTNOpk^Xaw}_
zR6l~)D4|tHof2!J(sAHyexk~T(_~BXi~4W&UBF?rtyAjg)El2yL=?b=>p-$vKkPxR
zwAFGyjIrd9F_|1PCa^X*UbAC3yDeO=Q^&Sbr?DL#6@K`&wKcp2YIo*AFcyszm!j5|
zYPnfXPJl+OgQ-YV_ZoaNtm<&qO3g~q3GRleK3%mOhj1-}V-2>KW!mcyelxy;ubQEC
z)hx0P>gL3T&+t(6O=xD+&fle0>-{z*HrGlxLJ6P*
z6xe^eG3%&($pfjV<2y?PZeXVz>$Lmt-X}S6iyKo8lmZ5udmZUzmo0=mihCbW!DW$U
zC?|3ujnvSR;S!V~*Z7@Q8ITD0$oqlgyp1Ix{w_Jpf9A7yMC~ukowZPk+<`)h4#N-~
zx`B|O;c=|D*FvM(Dgs8t-bfH|@N`=*_|`ds>J=6Y_VcmpvIB$y(5+twa-`bh^4O%v
zERS{8j64{(^7QTCPawj{E9(rUYit}h7g@Mp(B+rD%YhBM7<1yhjko^
zmY)OsH;9v_@%1SW(nOfOU-XAWxkK-FG;FHl#i#~n`^z0+U;l=xeZq~Ye?uDUw0FXS
zq=3~1_=XRtBH%J1u?Slf4StbYpGsA)ZM%?$#y!g4gc&=$hmLyDlC={t181roA^xKH
zK*znnonf-!iY8+`hF#XfJ0bma#_17&frO%jJp_&EKzcMEXZ^8tMkn$yLF%Dl`Yw>4
z?>r1>nzNv;ej>%FDeTauQzHP|`F8+mk%?fR2YJXB3A>$Dv}_6O>pJI`4$z|xdtn_L
z6oykV;-p@u!#CLQh0w8~eVm}^@jpS;!SMOKAImQEat9glJ8{GzLpNtNa1>+tdtj3z
zb%M&K;`9!1SUAt#w!K80p86b@7Gy)H)|OV~D-R!J2Zb++b^AohUj#H{RrBnJmFE|_
zYeUNO-_7tI$E`+ke!O?%WY*}!{;KbMLl#>m+u!kBXc%*o-a5Rq4TZF7J(
zuYC{P;2|#eZ$@ns1XCPM;#jMHR0+Iqo+R;gfNhVIEl0M?$&$E-bVmD-o(%ETU_qK5
zT9z0VTCrP2XVN;7yg+nn}yeXlfp_N`W@{h;sg2D!9UbKq>XwL38e
zq{ncRI$BE>X#GOE<|NlX;M7fa82thi>H7$PRKC9C24uAi5c_&!R{iJ)Q_
zaOio=e%|+XW8t@sIN8<}`Wl?tU}fU-6#9IV{SQFMcVf#QS^WTZz_zX_`#$!*w5-m`
zH6-xKm1R4J;@c^{qzuMH>wApi^UHoT6pvH<>axU8{6UIOE&IVx{2_|xmi>_8nJB*n
zadYDu>~fw68(Y`FEdh`-aY0k5DhzSZlrYqH+z^mR0xLDTKk@=9OZhIIN2I@h;?I4VwyW0G+f1n&T$xSJly
z)#j!Z>;$g|Bg4t3LuMJtJ6XHV6?LA@Gt{CgEVf(T88SN!jZ-e9VBAUm#{oibH$9RQ
z4p5tS(<3?N0JVBIJyKhjK|TR(Falj++}F_91H2Y(BM>`j-*@0pxZq2!_fd
z?y@N3(^
z%P&G^^+@ezF-7zQ!m|l?sHj(CaaV|o+_Jn!u--yr&%?AHVFkK)fvVRhFEUM$v!Pjt!3mawm
z$cOr0u}Y{--h>0H$iPmPH_a~#tJg+twfrpT3RoIRmxOAAyzy!<5uD&a$ss{`>32d<
zFhttVlHvaaQ((lOBmugVkdySwv9Nm*6o6ntcZQ)%Aof&0-zuOeDA7Fov^5QaM?$T)
zHDqM6KVt{HldRJaBw5WOT@a8R#&`%%)BG8l3pXwW2L5XXF21XzDf>J#6V3{9OGa}V
ze3hInQ%(rcr%lZo5J{5?QF>~1I}h!B`QF5u~Rs2ipwChpEX_Z;6|?t
zS=vuglB44$6TCJcp=C;}8)#79sg8MBT1I8^?2_b%;sY6R>Fg;G#63WSpv$!3ShV*@
zGOco9)BF|cdBXNG>;YmXNOw+PuhiC5G6Ta+Pcp~b3eTUw0Nvgf7&z7qU(Rtii^|hh
z+=K=l(Y~OzfCbd00!JAr+&V8yU4-lV%5dg32;iCgT~aG(WKK&4nrAi6#7b?brO6!r
zd36tj-g!*n>Ku>RA*;8K@h7Y
zXIh3Wy??VdCYrWv4}HK5RiXqes^Z%LMDA8rR&n*l%Sd9KYfGo8xqkmz7~juZuRpWm
zXHXlQLW(+TkM;Y5b-30gaL#-SE+?SMHSnB!6a5C_AU3@g%m04N%g+IdY#Zd^Il#kc
zJNa;7VgM`BFHjt7Pp*J_y$X}Q_Mn;fG$r-;&ML76&=B|Mj3IB23-stM>hK3q7yl4)
z3c&~3PMC6^L=NGYg!)2t{NIa&T&F&eW9ZP*o&*eo19&q+r=wu++=r}t$W0CCrI8Bt
z?;&^5lp@9Mtk@yd@97tUQ(O1al8^lV4HFH{2Y0GD@pd(<@8}+KbV#noom6OT-m8SZ
zHsICz&Ah`1dwVQ1AiWQXI3})uYbChAId7oH+XLUP%mcTfl2|s9s?}qu+GD(o?7bga`z(b7AVKfwQ9bd&7(*ohyh+`4}Ub+Og
zv~|&8Yi1q(z`|cSP+@cEU4GcPtrj1);c|rZ&7h1mZVgY->F%t)Hmt1SgWY1&+h`wk
ziIt#zPP^Pv%D*f1Vm5JwRO$jLT-;(^AH~_i0pz?cc3Lg`8R!Yedb}i4O-sI(SZGo$
zMQ!bgg@ePPuZBYdsgTgG=p#sh=EN=;YjpX}YHr_!jV{m#ESP4%jjCI$Fh$&sGdARG
zV{Y3xncoc?+o-#V&cN^r^5AYFTt<{n8}c7wSq7U?=`yzxe;l~sE+qF0w9H+L-P`LS
zyb5Z{uB#34r~ixcI=Kr)c1o~lY7N}$NT3DGrK4abA)Kgo*3{O8qP9e}yQbEtcfuZK=8>=>
zqZ=+=N_-_{sg~iAwcoHMUl`H~|DeR_&;rTZH|c#rd1w{h)U0FwDVo)N8{&f24QDbFm0TU4)q%80Ig4cVPW_N8w!k%Rwl;KX1G`F?VBP#ecb2HVzT!58yi4SA`b?HokcpJnUbfZl{PF
zk>oRLejvmQH=%*0+DR7r7CLCtbRWUtdQMc0GX~zneB53WmY7JsxgPxBf|Zod2bsaC
z^#TUXFw*vsD8s3eZn3<={BD8y-F)-Avv^(#5HmvD4qVGVp>f@NoD6p6G0b_;>7TGK
zSQ~alR?VS_5WXJ4chmd`;}eKP*Ud!gqJH>H{=^E&IvG)+-cV%M^_&01SS0H0MKv$grs5Or#
ze{;CeD&O0U=GE4*vNezey^K^nxg<}=whvsAzk~U#Wx3i9o(+e0lk$hTOUuO;4{qj4
zl2>04XBKhf3p<6i#H3_&!u-@$Y5C=joC$cF{3W!jqt2D3>B5^fj~M$Vm|SQkqX41q
z2T%b2Y3>2D36oLt^mS3MHXxT;nz5fClr6_(g
z&5ZNmC;~14*6HL!T?_*!%vVHtjCz-|@_{NWfYVq9UHf&K-&hC=^N&yg7CXr8M9E-I
zy78zABU=W%n&G@W?8Qu0LFxuGkGjMv)ARK*Kbna$O|6T+L`^#69$NTe%8totm!w@g
zstZths1|A@RqXFjEbE6;4?L#pWi+}9BOlnJ@if*Y@t06S%G-H%h(Gyfd?E*y<6uV~
z#6AVi5o+s34s={NLIlf5uA;m&lJFu6NR3z>mHe*2h>?FG+|6B3U|-OciP^-Shp#}#vXgWHA5YNa6U!+q
zq};yuH@J$N+-9bU!#^pzU+qcXRI%2RJ6N!&X5ogfS!cW}_M>(lIwZ
zfe*Ebf@|4$_;a(+fU&e6F5DR2dJoz(we3sCE&7)WHrk^L?qs(*e7DNlO|*U1q<`tz
zFp0fyeZ{_t!7Obi5STtGS&+D;Yxv9K`^c{aAF<4kr-vQzf@8HZTke1_
zmA(3$ai@cpRCwMl!x0N;(N4*zTI>7u4{b*MIVBEz6z)~*XZ8JU7aY+A;K^H8`rhA|
z#@@HXm?m-|yYDTeyybfrCsN?||6PagyRzmxAaK6m*)Wm4a^kbTx2CJWcd^}}O(&$T
zOD1is$|nkYqPH#_KxLQx{SSvHo)AToTevB1O*7qscSN~{T$U_eed
zkFhYIW!is2{v~+Ic>0#e+UgdNtGQYkY->h?AtOhv79Yn
zC|3L;L^vY(C8_NL#a`w7Z<;&Q)?kGqzKblWva^D+h~g})^-+JanYz>}7pa3)3H#&j%?M%nM&-lef!)5j
zxF+{ot!{W}P%Xn+lGGUvThXOjoAq?c<+5_^5yIE&whQ>kp@q=!7ai>|DzP=9c19f$
z$s>&8F1nuZB+A21Ac`DkZgdS-L#<8zL|-DCxMORp!%Qc{SfvY7W`--&hwRbd0Jad8
zc=lZv7M)4Ey|on+;3sDoV)i>|hh75n`-
zH-jEcA%g)`CS%Vo^jhM_(t0R?r8p(9shquB^hR5^6FWQ$^{ReTZ$6`7g^<`efS2LI
z`*Ubd|3D8#gO1K7jsQi{X>oV6_6pY4m`A6R=Sku=CoWqz7RrfR5Ri?94t>qPR0wyK
z7ypI$rKPgGC^KCCKePnH(pwNhEInLUcsSYH
zMK#c96Wcyf*vntjXy@2%131BRv+s+&8T)^0jzv~DGRt=!UY=RF%PA!+PSEVc;+x04jyWuz`9C8z0a
zP;et3AKyt09HrxKlTn%hWp|r{ZIg}rF;RCFy>6=>AcKtZ{igs;$2D+d$8_A5SbQzE
zWQCGl#p=%`3N9G+E+|OKU+*%)vT>_}G|H_qp1!cG)wL|ngccc3S|rnlI+%#ZR
zT-V<{52V9tuLLh8L3{Ji5gV__imv8s%5AodpfBay=|iYK@SFKaA)n!
z`gu>Nt}$DG-8}J`UfpjdbHH}`%ci&Y#3wXN=Lo&`4(0{54(6M=w14Jc_S@PRz1T~Rl^A0wq2=ksVQv3&T--P-z
znVBn^D-8S%Dw>y7pTWRCJv%uY(qn<`5JRE`J$=%kf*e{lfB-uER!3^0(2sg#_74u@
zeg`UK|3HdCiDBCf3TcQlZ;=fE)DVDCBd73MX>n%uU>mry8C=>pv#Bv#(y|5XL25qF
z^05&n9mv|!TtSltfaHuYXx0NX=SsY2p}M3?Oo~o?mUROZ8H~u;#u#JqSQ2{ZLaoPs
zjN}?g*Fmh$vE0P{He)`F%a{13&^QZnW3DA83tFarDJ79wHRQxiju9p&yOE5s7iX5S
zPAT9u2VnQ0f2q4R-q|na&DrhAn{dUUuHF#hhY!*=#Yui>7P*An_97irPU5O2oo*Uy
zOh-vz=E?#LyJLd@1MDHwJ>lqR{3b&uuKRc$
zRa&(RM0m(TfwmKzbj_mbq{47k@OqTc9^%A+hT{dTmTLg5;Yh9^SeHWDVf^
zPG5p0ObJX>BS$}QtpRL@Mtm;(zl^;l;yDM;Qq3i-!QHSe;4YHOc?FQc!u3kLQijC|
zsD%F~sDR}K4dDj>ip4gzraN(+OJc5dkxPd4`v&&TmSu%$r;c7Q_Rd1_&ATqgv*|(_
z?NHdXIT(ccj?t#VW&9LM1V(fCO9+gvYLQh{cRA|8$m
z-~lI6RXK*E5J9AvdGFyn+a;(a3c&7Xd>(S*x&q~)n?QFXUV&&!oZ5%W|Ki_-47X%6
z(Q0oier1I=N8(f&F4phVH{(93yq4hH=B4MFtN%i`>qOJ&mZjva%7L~Zf16w=u@t|N
zC8*A#SM1f;Df0UcD-S(|f&m-%BOMFxd07fk6SCe7GO?X$W$1$etD()gv9Vi~;F
zCn%}JBUFzlG%bavdIc_e2^!)%?=Kt;>=SrU%PeegG`3XKr#yK6E3D-&$9I<7GTy?n
z`3_|+%QY&LlI~o5@E#!+04sw(UjlbAOA19tfaBt{6O-buYH*haS#ZIU;3SqHLg-Hs
zuSrFMHxltGM10k*4W;Z6`f7@B}+rAq7FL4k^cPF$PXBT7m8RsSpzmmpDjw
z(ki70#|jhi*+>t9d8k}VN=CZ*CV?+O*aWS7?aGcDMH*FIBw7N4g!15Gl-=#Y7fUc8
z@=E*|8dge8sz&-qlL!y}Da!v>O{!#%h_6;(D$kEwxNxnGW=+sVv(lnD%hwwDe!ni-
zoR)g6HC%rGcEK}))V{s{`}Tc9qC{HC`gjazkX!(kNl;e$`2}+?sVj5N5W~RbMG#Yeilh*{Kq7N-
z`TBlJleBgEegUIi6-{4RDkK!Ye(|3$(WdsYeuJPfC%GUcy$8s6o4ht97ee3rVQ>{3
z*i>?fSUVT;29du2q~QO6pzaa7^iC!aDH2SyYB^>J-q%+0le@$TI#;BJhU*x>X_1dz
zx5<3Im6y*H#lbF0#fZf#2J+6~4Y=t%4*)nya{)$p3vFvi*Ad5XiK~d{2YC_&;{G)_
z^N738ShjLt@wE>91DpC%ke8C8!RXHHy%lqCamNHAt94P%)%{coTzgL^C-6sytKd%{
zXq3?0V#s7l7}AWv0d&MKAn8;p*_K`XXxr1skZRj_e%o+C)TVz&PM8vp$=Ak8g~#pgOEkaztzB*z)dvpU#TW*zC*i%^otfUrgsgxN5v5AXO1A$2ZMX_kg%wV(7t+Gz<}TVG4u+y55@fqQ~6UsY}D@M)fS$(ouQTV5b`>jrzVexEzt|w)aI#N
zy*R^HVsFpgJqzGszw-<~`_IG)*zc4z>|D6(fMAI483X=4!x@xnA5Z%tk@9F=du4^mXSwa*9zdvm_ucS4CD1|OA7qubHlHmx|ZnXXEN7wgnS
z;0*lz@p~IMQ+O2fS>f%E3)S)CGy@y{NI!rx@H7_Z?IdD!#rd6>sbX_x)DhIFP=QW{8&p4&QuZtn=V
zZZ64JWj}sasaHP&)^HcKRrvz$Mw{OVxOWpg+%}ZhFHktf{@9bmBIHp*J5%CknLM~!
zDg$THjev(0pF!ntz^E@IzYsSTJS0hu-vSnn7@Eg&KT%>oK*H8?Yd@n8?Q0LdAhvwJ6fe`RYRwH-s~!y=QFLVp5(V+N``2PuwrW)S-D;7ncuuNm@@yQl^5
zq{4{+04@|hEdqVZ!7$Z_Giqz;*Q^}1waE+%5ds8dJ=VAn`)kNLqK&-#SD1*x6dLXh
zi>|>AN)PEo(K~LOaHQYF8ty96%N`FY>%bYTCBzzVI`a7f9wl}PErhQVybREN)Ngz~
zK(XBinxh53W5rw$6x7C7i=e;-u05IF-tOm-duy5A-?ga(-DGv@1pdNwP-OsaOTX{T
z6jbRHRG||$U!zJtr~(%S^;t9)hal$sQ0PuX&ztZJw0smo9EP4mYn}Lg
zE^>m6i=>XkJzX#^h#3U`@gu{ROkxZINommdMu`JO2f|PrvQbQc$+@G%oE*SJV!9|q$nP8I
z6q4UgyoLO71cdzNgDEnF{N|6yuZQHrRF!-bZb3l^*8N6734
zE>CLSUJ?$0JlMN{egkf}CFo+la0=L)c$Q$
zUfysYQH_xMymQ19{rHMwSr7e+IHEIg&za%wfAmLxqx*k|M0C99esJQ&eLrE4S_+%)
zUwg>Vbb$Q-w?hbVkqe)I`pk_o&lPVc&k%1HAN&tWck^EH&gY-e`+EMdh#!v9UY=kcH7tsnB68~yxYkyOEVh<6o_iT7f@
zMZAMt74JLvI`Lk{*NFEDzCyfL^E-aqJUeD)>x5{UW_hw!w-dlJ9
z-h{$)P2e(~OR3MrC}3XE}-^0h*?;$R@I?@Z;n!79b&OJ9~sxztK=`_fmWQpQ^;`M&hksT7-)Qs7Hp
zlS=su&r1?|-{HaPr;z-S7Q8-#O6UW^C%za^;g}z92r4(tvF!fmr5a
zJS;8b)P|e0exUHohGYxhZ`mP@AX0KDZ5H&@jzzaO0|%#HqT8=uV2JGLdyRwY6Rw{P
zZfILze29pq3yoW+h-X>*`ylx9UblY0a`M9B*I1homJT+iV-t39e{gq<^GEivs4|2<
zxIctH(uR%w)Tfph=Ogy9)$eh8aj!dan?uoa!GU_A&X^QuR$}#!sT!$NiInD|WsypK
z@cl@oUX5VR2hjPJdRQURhZNc?IBxwa}Ch{Aa>SxA)w3SZ@#Yhsy4
zP|l_8>llZfjds`wlS(vm=`-E#+XE-j-OE!V~k5Uu8(XsT{F^SjbV5Wo>62o
zT<|wAW1Dc?Ktd9tk(*OB#{DS-|bmL}j7PX|FWyW+mHw#8tcSev`A9oJxVHI)r
zIzJC}fBtuzsb`lhHyq2B7q(vsO*?GTbSPF)F~!QACEpi5d@MBfo5$}?)3ya#pOeb^
z+wDFs;M#2aFzVB}Ee+c~O(*3$?mBTD{FwqQ1;$A8#-k^weojo|>{!yRpA+kEvH4q7
z>MwSu&baIjt3t*2TVnmKu~LS|yF+cW!eGx;N{A6zzSehtC5^Ypb04q^cm{Y9*a18Q
z+y?|QzjnMK^RDB#Ca#Hl0`~-N2W|)MN!*jTow%L2@I~+HYO)IpN3(UXHo2uY>8
z0LRzUv=IOkf7x;r-b;<6pRL-5ePmunw+PJ<3EQM!11~D2E8GcVdpcp@Cm%l6MZUG)
zAeYeTH)!c(9!V?GCugianJ9g-g|ZMr0&lyA=VyR6pmDZs%%S=@HvfC7_1;&l_b*XN
zOWDF4X9zb&)&27-M#UiQDHLcXkO|BK76Uf}
z#lTvCwjM!SkHAgBO~M_5i$(9Rxo{B{{aPX}0;*qg;5u;axG3t6?i;I(wvpa_zz*P-
zl6ItTX4`0isJ>9|)HbRgs2gD{zg~S8nQXY9Z@mqK)Iy6ygSF6p0HGslrCqpCm`1G2
z;9Z;(^RWclWeyq46nhzTuGJW9#yt`t)dX4tuLo}cfojU>0>2U&dF`0O*a&!`g`0xV
z_4k;kA7(QOzN}0Egl%J6RIw(gU$yQ}!0lkN%H_SXAtlK|yb2Nn4zyTm#DsuFp&Ma7
zD86p=D&kt?qCiXFwf2KdgFYlWA0Z&oE$t3yk?7jCs|_Kz@3TpCaH_7c61cce0^hR|
zfE^y#9lXh7R=MOj)kDYw_3Jrdm_JacpQ{0d!b{qMmzevB9VT=h;!((XN0kPz2uUxI
znxI8Eu%ykLM9zxn_0N)pg_>Bl_LQ`Z`7HfVfMfuoFEsK%|J+1JYkHCh$OH%TVsAA&K4fHf7Uk66I`ltZsj&7R0VDxhlW0=Fkw-#@dXy@
zu!@b7A95+hI%W^S*JI9mhC12D9vA;dB$?1_9`icO^Puv)C+vBd<@uEIyf5rI5YK`~
z9^#E!3@LfgO5S6Bgp7W{BM;)gUH*W%EJztC!Sp#EGnYuAsq%&%{n?U&=mI&VUx|R@
z1a*oS)|At^uneK~6R^KLq1Q>g-zjw58~y8YXd<^3OxZ5wBHd(iksOFkOUX!ORB!u+=f$A>*d;LXqo()}ik#PvqOcQxo7xa^`
z@U5Mxjg)?i`Azae-;PKbp!Cpg?s<&Vxbtd;>g7S8Gt!{6CPg@Gm!dqdbrnApUK0RyqDO0h8WWLVO``+2=Y<3G|DjLB=$9ia`_xPL_ArhHO^tYf=jil8$%&$eMWkI
zi4vc`?|vp2)R?@>G_6q1mZ(4el)V47>MBBZ*W`WXWm}cJzboLGuqfaeyGU%~LYr}X
zO59&AF>v!?iHD2!50OdOri9fKdp%8iV}
z+*$}E{;UCe_Hu1u!_T<4aItl7A@gSrbFQo>^01tT;L}p!%(riK?L1{NizEOZ!g>MFyY+=aimhXD~B5Pl#LWVaj*8TN+T5|=FWEG;N3xQQDI
zp@R`>{}80hh1PPy9JfV?0WL60S@XFHgl;qAN^|vty=6Q;f{xDws;%i1O)wTw7-IVo
z7Oj+;A$lT+eC&q({2jXq%NZwf8%HrWFxKvW_Qw=GX5+;|faYRmnZsj>B|O3~3NX%n
z_ddS!0S!0TV{e-=9M^d1oM3D1$5$Es{5eUnLBt*=8a6zktU`~x^G5O%`pcH<)x%il
zT`4@k75PH#$H`DPvxY#6hn&+GKXV<{Jf_V9jV=?aCN2TCS58VA02|^dqCPIZ-x?;7#1{bN-}o
zi0uuSK2r4nwDHiU9o!Ay5o65qx5euH>!5ZZySBDJwVVjmf6aLFMYs^BvXWw2H3q!~
z(;%lS6m;T)pvO`cGg}L5FC9yR#x_hBf8BPvu&Y-G!c+(*MZzTa`h*7T?%V$yJG&R<
zlsGYzZp4?Y8_s}3d(e-V;|z>mx-JBb`a7IgHZbhZcV4;YyWqYN+&KEYvg11nH-1#U
zgCkE6_Zj?-0}fug&mf<5UXj$nXS>6m`@EvcaNhGuIE?^Ftplon5?}?e6z~Aq066a7
z;k+W51wvBk9|O+-FN#kDC;q>7UP*pP@>S=Rw(p(yyfTGPa-t#dwoIN&fNenJjB(EM
ziiG}r=M|N1B&}|&{TYjGTJnR>t)#{$@V%5uk7VPX)tx)}9i~;_$vBro~X_@fGK`p*c(6Shm
z_ccfy4kG%9JhMigIdnL{Oju?TtP=+pgkUA)nQwrAeEPsq(87sB6bdBfn??76cEAp|
zFgA55t4gq}O8mn|j^XANy!bhC48jd_s9~TBmfYvWp%H)+$2)KWtZ>$eqk?x*}%En;RExS~IXSp9J;Iv|J~YrNURrg*tQC773oWE%2dA{FNFz}RpRg_uvaG0X<4
z)KO#ha9-1rjzt~`h)KCbm8#yvWnIKul`Kc%2BF2HVwY^#;84=0h8L9xUmS)sI5efu
zrMsq&67AV?*ESC6u?BQ53x=+at{vtpUy=Tn>%hjPRv@fb>>NZei@|TH*Pe_fyaRH>
z+qn}v>wgrKRZayp#0=C6%HTf}vvC}PLL1zZe+v)J`OV#n=)i?}W&PEaUEz{$-9>27
zp&VDLisExmUlyYe57bJ0b^X`NPKqF`ALem;0ng^WuokSF$I*omA&wcc<->L*C)w^$
z#@105(>pikRtXe*PBn`NCWH?v<}230wAUWEut~0FW8dub!7=*+d&g-odQ$iK5(3Qy
z_h7xtK6cMla=P5A1>046G*w|;{F2`5r2AUC14SawNdSxguK5Tff1wp(ReX7WYCr5Ogjhy&`?wYGR
z=ANe%{=|N?Z*Zu2VNWTB^VlE?Ocdog(hMR#lw^kPwpNPcxZNv7g4Sid)
z6wVlH{)&i*#y*M@7L64NAM;8{S4rUpV*{F;2Dw!$>r^WrA`-cQ)8U#`$0fv
znZuaInX8j&uMF()eo2pcLnnx>(zYf-IaoN1od1%^SY&iYDsf*+$~R27Y08`qCv9kw
zOjU%BzDgnXV4bl>PIk|Hi{z}OM`r1#lo2###z@=|#HAWZB~MBt)U+%SQ46WK
zB&rYRMQY-2Nega9LlI`8$l&K}0|k3jgm`SaHx-?&M0K8
zpVK~(`KfGoUd_k~D_z%%ni5q-x@~s`2G{LYmD*i>aUc7g{$0pyv;}|H{B9h!nN)WL
zUiKfmwE0-SaEG;II_xp|W(#Pq)Xsjc&7=7)dXaWM%_h<lRvOXO
z85-I}-KDi;2ThPg+FW5{1GBi~x37s}lTPVLNDgi}h!h;*XoQB5g8>Z+<530+()tZK
zFJd{Zq2?7VEIGFRYp3
zk*$D3t&n7nnB$*kl5`ZzPCdQxrn<9=cb(gmIV~)raJ6}nWV089VtQEacB93s}thilfElNyKiX5FB
zh20b=d=UdqBPF8|xe|g0#4%;}rNMjB4)Fa%gu-8S<#aM?jA+JXZZks&=UkaMtsY8^M%zQqUB);D>DSY`Fu^Sbnz
z9EH?R_5+6qyE$#m!}kwpE@*%Aj0mNMed8m(d-3J$gc?6^mj*7%!t#ONljFiJRIp#u
zw`n$PCsp?OyU0~523dloHJmcFbU
zP~8$~Hm(%6$A0)&fb!Z@qM~U}s(4aSiKMN|60DmM&JR=xyNS9Y5{cTQLKM`#N~?$Q
zo0C4SFd!5($($SLEhu>i$`o5mG-d%t7uwW*Kd}{0RewR9?YS|sW`dc}C;Hbv9UcDh
ziZCuU5_E%s?J)f;3)E6_$qeH*!BiRx(LTW&J?5NP%1SGDICsWdK2z~QIB`xW$E7>K
z;_T?p{nv?5AA`?EQ&$y+s*d;QL_}$vSwe}zd#92F?PyRHRFw)|o?;~GN9$@_QpL50
zmld|RlMRz5f)(wwup+itb$P<(DYKQ(5NRdz6g_+d$jKvuobFKwFjsu#0fOAh6Kav3!dXq
z?80KUg~bXBPJ0m=Vx*8_SeLKkt19#q93Pg=6hqVamD`4n}uFnm#d
z-PMxyNw@NAd()E6GTWks!eGk_RjC4-b#F+Uj1@sg>J}2h;?As2y}xs3&Y9*m$AIQu
z%CF^|W3A_kzLm?mJYc_`1BZ|K{dD@z{%NOMXcprWjyJ~Zm&45;17{F6_KbIZ{bu}e
zZEWm2Gg^7t!&A$QHqPbkF~*_E`)9Q2{lOhWAz$q2Hv-K!375J1@D*NnHdIKnx(>RWaAK)m75saoPQOP!}E<
ze1oA{77AS_p%^*SP=cQ4F^^FR8A&yRA*$-stIIql@yG$)hLVY~J-k8+UUo_X?2-UM
z371>VH8VBt}wcFL?3AnC^RvY2N?V43;m0q+?)mX(uQ
zq0UY|3&z$*Xj!~joxy-y8^^P}1W>JPEimlCNvW@I9L4Elk$Dq-frAANOOk>YK&1}V
zyv^VeArC9o6YOa
ztq(}POI+yjj9uDpkXY(L=UuCDxd^z?US;MKty&
zqGQGZ=N%wsAuIB+;7gXkrXY{5TxbhO8@?u2qF;d{xFy6G{I!TRZ+&ZHnkB3Jp~xyD
zt~uP1+KQa@_)|34UWyzgXZ`3-1_)l!IBlC{*+^9KIJfK|Swu41)K-aUUX`gVK
zj-MbS2)iEdE)9a7U)gwlRQ}V#`Cnu{{t@|iL4fAIVq0
zSiD|Q1yX!hHJmt9k~u!L34tz=Iv!Bbg~%oQ*tDag5`PK7=eUZUS9p}s(3~%va&`GH@`wk7UTQ#F4tl7D>yozE_0YEh!wNxgDVXT
z^lP-oqmXtastbojFsL^IEfeDeUu*7+J$*!Qsh)S%Q^CX+qM#iF>Sf01?38#!8=LKE
z{uIqPotIW-_m~Bn)v%J~8DuZ1tiSmtofaH~-8AOB(pWEA+eHby5gd&=z^}3FcG=(Id)dkFi2JZ*0m)g_4diCv&o6S-8O*OjcG)lN*C_|DKe>
zPUqJ9SW6KAxSHWn5Kcn>eM6EJ-?)%Z7=huFBnRnrPXof{k`og8l=P{IV&b^VyoD|m
z-KGT_7GW-We$$j+A=;cs!xfMT>ZV1t5G~P=q!3VqaOJgQPSccUuom4x2BMF(tjvz2
zf+TKk!b_0IJ^GU1d{xf38J4LZ*TkOwL(`mC)S}%vjX1L;p3^S`7*Cl!95*8p*SX~a
zK8Oz2#Ag}?i^>ipZHB2zN*k?1rwGJWr9UgJAPqSn#-g-1&3$uTp7|uwx8k2~e(-8|
zjOha{LEEVit?4$=cF;Pp#g=t~yHuy&7{34Xp)vawvNKLlJEP(B=bXgCWlaP(%s0=F
zg*1uI$-c`BN`@FXpiQ$*wwKU`;wzKQ@?{&$m4=l;${>=7EF$sgij8i%C|{sscAoiz
zCwZ{SeHl{%nV_`31>ORATngM8mTc+X_hl7PSLVJ^ta6nbg~kN)I2DYZ@a0y8qvt3E
z(GfB`Dbz_0IEfzfF1o0o05xVi51q=qcBEauB(2dke2I4vFvme2^slp8n#QjKhFSgw`}{Rtuy`-1-Rmi_v|u&`}#z>)mGp5{Ng
z@&+6UB>Xyb_UuLkUQbVc0qM*${trU_j?meh>y_ZW%a&VZz8-;Dihlhk
zmctry)1J_{gP^dEB9
zbgEKdd%5{4AsUj*U*LobqX^v@l7L#!+7}W_G4Jv}Magf>wu>%_A?96HDh7^~U9ha~
zFZAc8wI1j)Tuw_`c9Ao9xU*#o~1#2$fy~hb
z7ztQga~5kD9qc(0cw7QlgM=I}A%{uGA(4=TV)Kwt;}f_zV{%Gzc>?jFDg8o2uT)Eu
zbIVs`dx28+g7eNQ9=Z4K{OYaZ7axNjI_?0U(rTSsL~kVdf_q;?z6`5@+={GCNigDS
z9jKw%ROkZ%zM_bzwPMM@T4?
zpg-GU8yJXh%n70CCN4NGweY0TPknd@d&?n?V)W6GSER#T%G*x(49X+gK{n4};01>U
z;;q`JNga^`YK)=m+{({7DIGu^om-`bf;kJ7;l{=RTlTN(m(hL)FB}B0bjwk*)4u6K
zGWQL-(YbR#TJ5uKkd!ptY`oC9^MLbL4f4t7EMbB`R_1o$S?AUO1Az8v_gik@;>r8D
zjrPrE+b$Ann0HZfu!T`Eh*7c1|JlO=CNn9yoKHJe`Oh#iUgw>sfx2^5!+?y8G*}?6
z_NOEe7QdR$V!2~fQ+BLMb)bJ2w^Uta35sVg!)OcP{8=ufj?_RwBTMIb2g*%qpe%_D
zlnJZ+HJu6izo0T?RfA0iOQ#GLc{szvxIlbMX20nQx@(%G7g<#wxK9KNUw~JOGJa;
z`4oF7p>eKfv|6V0K4b9dW-TpVGvZRR+H`wuPN-Hau-PW=d5%f_#k@9=3S)C-4ChR7p
z^M{nV#Lmohz!!j#fXi>D8QW88Iu)kh5gZj>&Vxh4tA8+&2dS1^qwZi%Jx9XWe|uJl
z2C2=;l>MeuJ(>OgO4v%5&JrRFhh1XK(pci1Thr*n)~pkFYr(5|Af6T+&jVkz;K*50
za@{#gL!*hlB6YWOtJ8`gnUY^CYavftTQN{K&;h;<-kX!eG8oSn34`Ii3+i%C@?@{e
zp}H}eKc@rT@(}8DTmPDqJKT})jv(5DPmrA!e0+yXkGEpE%twyVxcx*v_o;+
zj6SZ;+bN@2q7#d_=ZH8ZFzwSKNYl&3-*^SK!zr=?8iA}P5C{!_6uMu
z>r%`F28JjbfdyC%C}10`-5(>`Vn6kr&rO-JV{6^D^*Nu^dOyjo&q0H7Em@svX50TM
zBZC%-)o(A0<g9vVZ
z{UbHk*={a@gmH<%S=hXvoobr-5CezT7;c&ouct1DHajH58i8tvh((V#~ACbJv(=lGD=vyeyU=ORe5lh28~WP4z*#s_HE3Q}BM8M~WU^k|;Ko%bPN1fzwP=H$50VDt;~T
zZJjAKCpNvsAQzoIVY3-B9b}NljBRvWn{&4I*rsHm9G)|TV5@MtUAvCO*S@_e;Xpk?
zW1kqKnE?(2yNJ}+AP33XYaQ-DjkTl%URHx?gIZM9bWh^&vQmaIb7&mz%1Q&t6CnXv
zvM7BI7WVDcY7U<}ANN`6{PLSLYx{j46K-1IrKoBu#Y7GEL16{B+`URV18z`Bin5yu
zcd$*kd?H~6t})W=&lhW}wl@B|%cZ*&3ChQw%~oBOW^LB8Wi}xm)W9N12xL4We7g%|
zDAgQIJ*&?&pCx|7^dO3_Qj9hoIq{=N9AzCB5w4u$y@XgWIcTq?Hi#~K=PjzUhhXLa
zieqi+3l|D27#8qI(@UDFbXGylf4{A}j5i1a`1fF9g7T@gM&TCb2DU({2Atd@YU!sY
z(EiOO>@84LxMNf!ya%JxG;pD+VmqRn-8Dq1MTAU;>YI}5{bFXWZooNo>R1u454oWxAviCN5S+ge9!p*~nCs4tt5Z_aw3
zUK9hH9~#y9=G+J5jk~Kti~4sN2x6f~mBhJ4W^suQ=Nh8UZF{8LqW3?HzWf9-Bvq!K
zd_B_K=j+|p*QT|xNOA-dAlBJaThMRb!B!k9o0Mmkh`k2EhOT6wazPNGPy1H++{A5
zL^^FXodxC^4ranbMx##W#M8D8u!s|vieB!Mp=7G&>zm3>D;0{}X%>P$s#-Yxt54eN
zYEHHhvu1B_l<6i_s==KPhI0eEWv40heyc9>RxXWQ<0wcGd$`gBH{l`5L!iBM4-L4`
zsL~Ff??Jbqrdokmiu0%py6FY|g#aZ7%
z!)!tn!gohXnZXk5o;iXw&YO+}HKnba?BjwJ)QdmAXri*(wdfLrIGi
zVFf75tu}tV%dFEx3vE<+~hpHUppdnPU9AUdD@*%~N+pf$wDXN9d35AqN
z0X;L0SW32h`1ugPPsHd#n3gJHv68V0+cdzxPr`#7Z?0xl(=9nvufwsYXb==`ySgkxc2S3+5<85gM*j%_T5~2
zAU0^$7TGri2ljla9bLOssQpH~I^q=WkuDgg?GiogWF0O$h%{@j+8+M2s`t|C
zcG1#cLSSGqtXL&^-AzC)AueaJeC7qGEEdC|2s7xejTeE1Yy?-e8;KmnVnEmE^x$;!
zJERBQ(2opeX(F(S>`hIn%;+4*DG^L#ken^
zsFBQQR=0^>EanSTn;ftK5L
z#X(?L)sS_-`SdQ~;@>JA&+K}U)q9JJFsUClBnPryY|6GbZAiv4c<06xx$Ydsxxq7R
zc7=8~dhDlm!*i}5%yJeVjH@5!=j4>tnGS;}#pv8{fJCMjhV&~*Y4UI75aB;-tFZ^p
z25n`w<(OPmxx^uT#6tPCx~40(S=MBCG;fhgpooLJIeJ7QjoiH>cuX}6`ly9
z63$^a;>GVZQA2%Hn68du-KX
zSRGa3Bn>%jXfb=VEVdzQU!arL$}xq%T6m(NaPP99%VS>q4aQxoU2IAQ;!#3moM5wQ
zFkUndFj5fHrGNV2I|dAt;WVYYJmyUGC=Dlr>1vxs#X4xY6AYVQfZ
zH@J;W8{%UE{ZvV}i!DkDmtmf`3&vddZ7QV>O_ST==AWew6nqq{pLTC7gHUP_sM&`?
zr)h#Rd_eJMw=ZGnA=3?ZF`*I3y4o|d^h@*1B=SQ-_c+!CVpL8|Q?PwwP#P0%W$&{}&bHEhk=%U><{ln2%<%(NFhdFH0)R7dsT
zI(t^AJ_=oD4x>miDi|EWX&z360WA`1Zr@l<-Ld|-jSlP}PD?-cY!_4vqJACP_iVNErc=6xh!R
zvrzm*aX}7R947zkP3G;{-2w|?%zUi*duj%~Z!b1qY@SqV`^VY#0zq
zpK;jOvphOOkp_q$lb_~TDs07nLbQs)z)`yV9$+pg!HyHACUvt^ev0%|7|UvXMfEqC
zIJc}OaJbaU7PTmMhkGqrNRbr2l=?@v$M=`1u@zlBh8L2;<47hCMywNdl;YJMnsX{M
zb|mstU3y02#Z-#x6kWlkaBvCr+f@VDDEF@ld@zRqt5U06zC`|Bu(sbSTh)-@G@dW=
zCG$6F?HBO5BskXjwD90#PotijVI&!nM9}7Z`hcVXCmyaPU;1NA)+#}F0kROd
zZoD8;hWwr~SV2`0vQ-hXRS~jP5wcYgvQ-hXKUWc?DlZwMS21h)(;3dKLD0$Qwqg*<
zxnTG%E=Om}2PDQV4WaLLGo&M(G={jWmA&p}i3F#}Z_-DY?cN{y^Ajj!Ld^XAn8vKc
zPk3vMnI5kTgFiOV+J!78v!L(q!M|`%9C!&h4x9o8fh3LvW&(?W5}*p$3~U1)2A%?1
zfY*TIKo{WZA|8+iECYPNX5eeU1Hj|JuYlKpHsAzs7D)U=(~^MkKr)a9z;KHvf1
zDd0um9iR)i2=dQZ;96iFa5LZo?gZ`w9tU;;Ex-}r1keRs09olWUg#w?c)ws(Pibv`U{;wSF!6__8Rd$10tst=6iwm0G3d)4cqfq!nxB{L{1v
zT7_n)=PM*xZ9;`nUT!@KBcPu&p-Z#%)B44_>{(e^aq^p*ta(&m_jJ$Fc!zdfa&o>0
zQjFUz`@7~?QL=)crmd@5$In3sh^!6=j)Q;ls_ht^PA3EWVq$IfxPI}D{s{vT2M%(&
z248UDkf9e{oHXo`;Uh+ly3{@TvN2=FjlX=t6a$y26IyKZ{QjMSO4
zzWAlI^y@P+vu4l9o_oWM^K#}d@GM-EyBG_ZOAG$#rke|wEniV|%gSQ!s#{A+%Wf-Q
zT~S$eyRTX|)~sE({>xw4P_uE9BI{;VNSAslODlA*k22k;Wifu{^LL&$S-X}N%j9XE
zDsQH@ci7qG)w6wGuZElJ)$@wV4fQ-H>N&l1war>+@Cm+?qC!&Rslj
zL2j<)Bd=QS-1&2&UbV~xIq7rf_xLQDmOOdNz=ZS)cTrVUdFjd`y_6wSQdI3;UBs{~
z!e7_DtE+SwvgMUU4BZm1JHs8xyS(%kUy*OUyOcWneBPCM`T9u-o^o$dwU>cip%<+r
zCNZK?zr5OAZB$iN`uO54TJ2s%;a6AsyrjY7YE^Lw$~Spn!d33{o?;lJos&Cv
zUewIdOG>NVMb*{b)wh(dcNZJJ(u!N%6(qGria|w6D@yg!qVm!&tK<_FOL*ppRM<;Q
z_btY)yt~&|8oubVPIAxH-2`1-S*^RvOKU#Ktv1SacjYSg%A)de$&8kgGF`Q@
za&?uO;uEf3S?;^Sy~?OqsoGS{@S>hVRaEOfW2H{z`L8}^mY3%gl~$;_OTDj^daLPO
zQEA*-;;ybLTFFX5a0WmT(>bcaqTB15KJC?AcdylXixyk$t(Q>f%8HfVNuR$xBp)eT
zvgDCLN>aX_42r|wubnR6jS98uFmifAxJ$f6RaR+9=i2K&qmFA!qavz)>xnn*yz#2_
z;?IaTRpM0{jJ7qUKHVrP@97}vNtJ<=i#c(gwqIUZA;a#)xz3cu4_^xUQfN%
zddfVguB5w)y=zKWdV9i#+sM1Fih0APAT84~GgUiZquR$H$8ea{47*ajggv2HM!{`;
z!=Jxh!jX!L^dgEd(CYH2X{jc?&wIP!t(L;bC|?v_VCX`URaRH7(%pHbs+JiOCw8~TJZsTodD0S?50fTM(q^)E-|AyE
zt0-bcHY#qbs9am|Mfxz@gjupik4{Kn6O~{y+!C1|CzV~0(baDx&%#KT-@Q@KO+2g3
z5Px(|bU!05+5NmN>KW!*w?DG^-Ot~MdhS)#gb)Bk#huhV+|#b}@JUvvtawVr>m5R*U8zes%d|M>pb
zKGpwjG%Ef-9sx0R-Tx3U{#?IE4~n}vrsrR5%;)=Kdc|G=+r_|I3{o=`5W=h=FSiIGWATesQ2W$PVZt#4=y+}ZTCySCl^^>5ts&3nIf
z-~A7K`@!#g_j?a*fB2C{AA9`!JAUxPAN}~BpZLj>KmC`VJ@xaQPe1eQbHDiI^S}D_
zuIAl)_Wq`&b>IF2FTD7#FTH&5&~FdF^6G1^A9>@=w~qeq_kUGk6IwC9E8RK#-14xVpO%wzb#d|4Jn-}6Xj(eJnV55&Iy!6fE7x>C
zFW|H!-nrf?j-*zAbmLZ|TGzB2jB=I64dBX>R(h4MRA>@8MZT3KxU;>t_zVuJ^6iGA
z3iU`nlD~
zXta3eR92|3xklJ6(j~4&JdN-g;UtX4ca1}Sn8uRN(X?`HuC5L};=iQY>sxS38Rvw#
zJ%?nWc<^mrQMI1V8FLLJhbp5=`C0E)GFlEarJ`HC*H^Af*OugFEt-7oq|AAcAIOue
zDFFqcJQRx>TJ1xXsW}ZmJJ1}o3XMY>(NwgUG#tN-1@jjySv*#o#Fr{jxOxbuAhpb9pK?62tatqAe$8HI;A
z*M0W)UvKXHy>EX$_08Vj`=+0B-)Db6zPY*O}qIFnS_5Aagx&7B5%Fj|K+XxZM>C5F>|~XULQoJ42xox
zq5I0S)RYTwi{6wf3ajBWBKHi+p_
ziDnm76qkcZd?cynR2CcM-q{ds=R><8^qX3iQ0_B)kc=S;=CbQT6xXzqvGcq|YrLQG
z|4UCQR>Jw3HqoA2?ggi~ES4OkAnC=$5RJiu;$otiDOD0TqjL3XN;I#ug6wBX47Pr#
zlU1_Wr)wQjdMjmEKGGUrw89iyo^Y)s6{*4E^;KTv-ZQ=BURtqF1+KF%j!^NsTkwY}
ze*@BeMFjcKvh7PMN>mFKXRTWavPJDlTro2)wNsY!ets=>Zgr*?TKcVCpNHy7*S#w_
z2#%siU~uYUv!Qb;CWrR0dbSuEH>;9(q{`ZFV&_T^2!YdEJhuWCm{9UGtvT8sEF|Ke
zD{<2^JeoE{T4q63jy$(f8aODW#cIre0cl^fFD|bpfW=ptDQ{tJ%9rH1o8vM|-c%7!
zO4~=3{)wpeTCB*hbHQ=GWzVOr)fm!F#m<9{7$y-inx3P~VctXE9!ak#&aEn~usZd|
z7|AfJhr*ew3m2n0UE3vje)@wp?>sT`wJrAi(qeB$Ns(`HWsXpcuV1fwwcY1Vhtc||
z>IZAqXj+jy&!Ua17AUYSG`zm`9H%-;Y#{a!bEV=`yv9^2%y&c)H$cjh66wl&(DxRhtEd
zUS;SqdhhKODqrg-GcQ-~p7ZO&tDIzty+F9MtE-B9-tOAw_4c9EN2H8V<0!AlS1Jse
zbnV8hMf0=faV{t>=g?GPTLgPS($%zAtvJOCR$1@kr7gmpEAtpkL`ts;p)+7_G2o}s
zX8-&9|FZ>li2^!);#w4{a5-IJH_Ab&!om
zNmFB|{B7`Sfa6oBRs`+F{GJhhXJJ=y7KQzD!!FCSO1}VC
z@@5%U>8!?e11z-K2*3wOS*0FQo?1Z4To-mX@cVXLDc_@j
z5#wK(q(2=Cz0y
z?uEEF;|fkQ7IzqK*E?z2CAfQWhvVLfE4V^2?kL<$+)HuW{w+;&VYjlEwB!#0!o0J0S}N3%mk(bQ-EaPN?-yo7H|V2fFxiD-~ti>JJ9)O`UEfm
z3Ezf$1ULxn1%3%U2|Nls1Uv|A12zCvK!1BrpG%)kqCT1Q`JGq%b=VaC$ryH_z)OO!z2Uq0lAnGi8F(51;AS1Uf?O~U+= 14 and version > best_version:
-                    best_version, best_dir = version, vc_dir
-    return best_version, best_dir
-
-
-def _msvc14_find_vc2017():
-    """Python 3.8 "distutils/_msvccompiler.py" backport
-
-    Returns "15, path" based on the result of invoking vswhere.exe
-    If no install is found, returns "None, None"
-
-    The version is returned to avoid unnecessarily changing the function
-    result. It may be ignored when the path is not None.
-
-    If vswhere.exe is not available, by definition, VS 2017 is not
-    installed.
-    """
-    root = environ.get("ProgramFiles(x86)") or environ.get("ProgramFiles")
-    if not root:
-        return None, None
-
-    try:
-        path = subprocess.check_output([
-            join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
-            "-latest",
-            "-prerelease",
-            "-requiresAny",
-            "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
-            "-requires", "Microsoft.VisualStudio.Workload.WDExpress",
-            "-property", "installationPath",
-            "-products", "*",
-        ]).decode(encoding="mbcs", errors="strict").strip()
-    except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
-        return None, None
-
-    path = join(path, "VC", "Auxiliary", "Build")
-    if isdir(path):
-        return 15, path
-
-    return None, None
-
-
-PLAT_SPEC_TO_RUNTIME = {
-    'x86': 'x86',
-    'x86_amd64': 'x64',
-    'x86_arm': 'arm',
-    'x86_arm64': 'arm64'
-}
-
-
-def _msvc14_find_vcvarsall(plat_spec):
-    """Python 3.8 "distutils/_msvccompiler.py" backport"""
-    _, best_dir = _msvc14_find_vc2017()
-    vcruntime = None
-
-    if plat_spec in PLAT_SPEC_TO_RUNTIME:
-        vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec]
-    else:
-        vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
-
-    if best_dir:
-        vcredist = join(best_dir, "..", "..", "redist", "MSVC", "**",
-                        vcruntime_plat, "Microsoft.VC14*.CRT",
-                        "vcruntime140.dll")
-        try:
-            import glob
-            vcruntime = glob.glob(vcredist, recursive=True)[-1]
-        except (ImportError, OSError, LookupError):
-            vcruntime = None
-
-    if not best_dir:
-        best_version, best_dir = _msvc14_find_vc2015()
-        if best_version:
-            vcruntime = join(best_dir, 'redist', vcruntime_plat,
-                             "Microsoft.VC140.CRT", "vcruntime140.dll")
-
-    if not best_dir:
-        return None, None
-
-    vcvarsall = join(best_dir, "vcvarsall.bat")
-    if not isfile(vcvarsall):
-        return None, None
-
-    if not vcruntime or not isfile(vcruntime):
-        vcruntime = None
-
-    return vcvarsall, vcruntime
-
-
-def _msvc14_get_vc_env(plat_spec):
-    """Python 3.8 "distutils/_msvccompiler.py" backport"""
-    if "DISTUTILS_USE_SDK" in environ:
-        return {
-            key.lower(): value
-            for key, value in environ.items()
-        }
-
-    vcvarsall, vcruntime = _msvc14_find_vcvarsall(plat_spec)
-    if not vcvarsall:
-        raise distutils.errors.DistutilsPlatformError(
-            "Unable to find vcvarsall.bat"
-        )
-
-    try:
-        out = subprocess.check_output(
-            'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
-            stderr=subprocess.STDOUT,
-        ).decode('utf-16le', errors='replace')
-    except subprocess.CalledProcessError as exc:
-        raise distutils.errors.DistutilsPlatformError(
-            "Error executing {}".format(exc.cmd)
-        ) from exc
-
-    env = {
-        key.lower(): value
-        for key, _, value in
-        (line.partition('=') for line in out.splitlines())
-        if key and value
-    }
-
-    if vcruntime:
-        env['py_vcruntime_redist'] = vcruntime
-    return env
-
-
-def msvc14_get_vc_env(plat_spec):
-    """
-    Patched "distutils._msvccompiler._get_vc_env" for support extra
-    Microsoft Visual C++ 14.X compilers.
-
-    Set environment without use of "vcvarsall.bat".
-
-    Parameters
-    ----------
-    plat_spec: str
-        Target architecture.
-
-    Return
-    ------
-    dict
-        environment
-    """
-
-    # Always use backport from CPython 3.8
-    try:
-        return _msvc14_get_vc_env(plat_spec)
-    except distutils.errors.DistutilsPlatformError as exc:
-        _augment_exception(exc, 14.0)
-        raise
-
-
-def msvc14_gen_lib_options(*args, **kwargs):
-    """
-    Patched "distutils._msvccompiler.gen_lib_options" for fix
-    compatibility between "numpy.distutils" and "distutils._msvccompiler"
-    (for Numpy < 1.11.2)
-    """
-    if "numpy.distutils" in sys.modules:
-        import numpy as np
-        if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'):
-            return np.distutils.ccompiler.gen_lib_options(*args, **kwargs)
-    return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs)
-
-
-def _augment_exception(exc, version, arch=''):
-    """
-    Add details to the exception message to help guide the user
-    as to what action will resolve it.
-    """
-    # Error if MSVC++ directory not found or environment not set
-    message = exc.args[0]
-
-    if "vcvarsall" in message.lower() or "visual c" in message.lower():
-        # Special error message if MSVC++ not installed
-        tmpl = 'Microsoft Visual C++ {version:0.1f} or greater is required.'
-        message = tmpl.format(**locals())
-        msdownload = 'www.microsoft.com/download/details.aspx?id=%d'
-        if version == 9.0:
-            if arch.lower().find('ia64') > -1:
-                # For VC++ 9.0, if IA64 support is needed, redirect user
-                # to Windows SDK 7.0.
-                # Note: No download link available from Microsoft.
-                message += ' Get it with "Microsoft Windows SDK 7.0"'
-            else:
-                # For VC++ 9.0 redirect user to Vc++ for Python 2.7 :
-                # This redirection link is maintained by Microsoft.
-                # Contact vspython@microsoft.com if it needs updating.
-                message += ' Get it from http://aka.ms/vcpython27'
-        elif version == 10.0:
-            # For VC++ 10.0 Redirect user to Windows SDK 7.1
-            message += ' Get it with "Microsoft Windows SDK 7.1": '
-            message += msdownload % 8279
-        elif version >= 14.0:
-            # For VC++ 14.X Redirect user to latest Visual C++ Build Tools
-            message += (' Get it with "Microsoft C++ Build Tools": '
-                        r'https://visualstudio.microsoft.com'
-                        r'/visual-cpp-build-tools/')
-
-    exc.args = (message, )
-
-
-class PlatformInfo:
-    """
-    Current and Target Architectures information.
-
-    Parameters
-    ----------
-    arch: str
-        Target architecture.
-    """
-    current_cpu = environ.get('processor_architecture', '').lower()
-
-    def __init__(self, arch):
-        self.arch = arch.lower().replace('x64', 'amd64')
-
-    @property
-    def target_cpu(self):
-        """
-        Return Target CPU architecture.
-
-        Return
-        ------
-        str
-            Target CPU
-        """
-        return self.arch[self.arch.find('_') + 1:]
-
-    def target_is_x86(self):
-        """
-        Return True if target CPU is x86 32 bits..
-
-        Return
-        ------
-        bool
-            CPU is x86 32 bits
-        """
-        return self.target_cpu == 'x86'
-
-    def current_is_x86(self):
-        """
-        Return True if current CPU is x86 32 bits..
-
-        Return
-        ------
-        bool
-            CPU is x86 32 bits
-        """
-        return self.current_cpu == 'x86'
-
-    def current_dir(self, hidex86=False, x64=False):
-        """
-        Current platform specific subfolder.
-
-        Parameters
-        ----------
-        hidex86: bool
-            return '' and not '\x86' if architecture is x86.
-        x64: bool
-            return '\x64' and not '\amd64' if architecture is amd64.
-
-        Return
-        ------
-        str
-            subfolder: '\target', or '' (see hidex86 parameter)
-        """
-        return (
-            '' if (self.current_cpu == 'x86' and hidex86) else
-            r'\x64' if (self.current_cpu == 'amd64' and x64) else
-            r'\%s' % self.current_cpu
-        )
-
-    def target_dir(self, hidex86=False, x64=False):
-        r"""
-        Target platform specific subfolder.
-
-        Parameters
-        ----------
-        hidex86: bool
-            return '' and not '\x86' if architecture is x86.
-        x64: bool
-            return '\x64' and not '\amd64' if architecture is amd64.
-
-        Return
-        ------
-        str
-            subfolder: '\current', or '' (see hidex86 parameter)
-        """
-        return (
-            '' if (self.target_cpu == 'x86' and hidex86) else
-            r'\x64' if (self.target_cpu == 'amd64' and x64) else
-            r'\%s' % self.target_cpu
-        )
-
-    def cross_dir(self, forcex86=False):
-        r"""
-        Cross platform specific subfolder.
-
-        Parameters
-        ----------
-        forcex86: bool
-            Use 'x86' as current architecture even if current architecture is
-            not x86.
-
-        Return
-        ------
-        str
-            subfolder: '' if target architecture is current architecture,
-            '\current_target' if not.
-        """
-        current = 'x86' if forcex86 else self.current_cpu
-        return (
-            '' if self.target_cpu == current else
-            self.target_dir().replace('\\', '\\%s_' % current)
-        )
-
-
-class RegistryInfo:
-    """
-    Microsoft Visual Studio related registry information.
-
-    Parameters
-    ----------
-    platform_info: PlatformInfo
-        "PlatformInfo" instance.
-    """
-    HKEYS = (winreg.HKEY_USERS,
-             winreg.HKEY_CURRENT_USER,
-             winreg.HKEY_LOCAL_MACHINE,
-             winreg.HKEY_CLASSES_ROOT)
-
-    def __init__(self, platform_info):
-        self.pi = platform_info
-
-    @property
-    def visualstudio(self):
-        """
-        Microsoft Visual Studio root registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return 'VisualStudio'
-
-    @property
-    def sxs(self):
-        """
-        Microsoft Visual Studio SxS registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.visualstudio, 'SxS')
-
-    @property
-    def vc(self):
-        """
-        Microsoft Visual C++ VC7 registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.sxs, 'VC7')
-
-    @property
-    def vs(self):
-        """
-        Microsoft Visual Studio VS7 registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.sxs, 'VS7')
-
-    @property
-    def vc_for_python(self):
-        """
-        Microsoft Visual C++ for Python registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return r'DevDiv\VCForPython'
-
-    @property
-    def microsoft_sdk(self):
-        """
-        Microsoft SDK registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return 'Microsoft SDKs'
-
-    @property
-    def windows_sdk(self):
-        """
-        Microsoft Windows/Platform SDK registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.microsoft_sdk, 'Windows')
-
-    @property
-    def netfx_sdk(self):
-        """
-        Microsoft .NET Framework SDK registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.microsoft_sdk, 'NETFXSDK')
-
-    @property
-    def windows_kits_roots(self):
-        """
-        Microsoft Windows Kits Roots registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return r'Windows Kits\Installed Roots'
-
-    def microsoft(self, key, x86=False):
-        """
-        Return key in Microsoft software registry.
-
-        Parameters
-        ----------
-        key: str
-            Registry key path where look.
-        x86: str
-            Force x86 software registry.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node'
-        return join('Software', node64, 'Microsoft', key)
-
-    def lookup(self, key, name):
-        """
-        Look for values in registry in Microsoft software registry.
-
-        Parameters
-        ----------
-        key: str
-            Registry key path where look.
-        name: str
-            Value name to find.
-
-        Return
-        ------
-        str
-            value
-        """
-        key_read = winreg.KEY_READ
-        openkey = winreg.OpenKey
-        closekey = winreg.CloseKey
-        ms = self.microsoft
-        for hkey in self.HKEYS:
-            bkey = None
-            try:
-                bkey = openkey(hkey, ms(key), 0, key_read)
-            except (OSError, IOError):
-                if not self.pi.current_is_x86():
-                    try:
-                        bkey = openkey(hkey, ms(key, True), 0, key_read)
-                    except (OSError, IOError):
-                        continue
-                else:
-                    continue
-            try:
-                return winreg.QueryValueEx(bkey, name)[0]
-            except (OSError, IOError):
-                pass
-            finally:
-                if bkey:
-                    closekey(bkey)
-
-
-class SystemInfo:
-    """
-    Microsoft Windows and Visual Studio related system information.
-
-    Parameters
-    ----------
-    registry_info: RegistryInfo
-        "RegistryInfo" instance.
-    vc_ver: float
-        Required Microsoft Visual C++ version.
-    """
-
-    # Variables and properties in this class use originals CamelCase variables
-    # names from Microsoft source files for more easy comparison.
-    WinDir = environ.get('WinDir', '')
-    ProgramFiles = environ.get('ProgramFiles', '')
-    ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles)
-
-    def __init__(self, registry_info, vc_ver=None):
-        self.ri = registry_info
-        self.pi = self.ri.pi
-
-        self.known_vs_paths = self.find_programdata_vs_vers()
-
-        # Except for VS15+, VC version is aligned with VS version
-        self.vs_ver = self.vc_ver = (
-            vc_ver or self._find_latest_available_vs_ver())
-
-    def _find_latest_available_vs_ver(self):
-        """
-        Find the latest VC version
-
-        Return
-        ------
-        float
-            version
-        """
-        reg_vc_vers = self.find_reg_vs_vers()
-
-        if not (reg_vc_vers or self.known_vs_paths):
-            raise distutils.errors.DistutilsPlatformError(
-                'No Microsoft Visual C++ version found')
-
-        vc_vers = set(reg_vc_vers)
-        vc_vers.update(self.known_vs_paths)
-        return sorted(vc_vers)[-1]
-
-    def find_reg_vs_vers(self):
-        """
-        Find Microsoft Visual Studio versions available in registry.
-
-        Return
-        ------
-        list of float
-            Versions
-        """
-        ms = self.ri.microsoft
-        vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs)
-        vs_vers = []
-        for hkey, key in itertools.product(self.ri.HKEYS, vckeys):
-            try:
-                bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ)
-            except (OSError, IOError):
-                continue
-            with bkey:
-                subkeys, values, _ = winreg.QueryInfoKey(bkey)
-                for i in range(values):
-                    with contextlib.suppress(ValueError):
-                        ver = float(winreg.EnumValue(bkey, i)[0])
-                        if ver not in vs_vers:
-                            vs_vers.append(ver)
-                for i in range(subkeys):
-                    with contextlib.suppress(ValueError):
-                        ver = float(winreg.EnumKey(bkey, i))
-                        if ver not in vs_vers:
-                            vs_vers.append(ver)
-        return sorted(vs_vers)
-
-    def find_programdata_vs_vers(self):
-        r"""
-        Find Visual studio 2017+ versions from information in
-        "C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances".
-
-        Return
-        ------
-        dict
-            float version as key, path as value.
-        """
-        vs_versions = {}
-        instances_dir = \
-            r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances'
-
-        try:
-            hashed_names = listdir(instances_dir)
-
-        except (OSError, IOError):
-            # Directory not exists with all Visual Studio versions
-            return vs_versions
-
-        for name in hashed_names:
-            try:
-                # Get VS installation path from "state.json" file
-                state_path = join(instances_dir, name, 'state.json')
-                with open(state_path, 'rt', encoding='utf-8') as state_file:
-                    state = json.load(state_file)
-                vs_path = state['installationPath']
-
-                # Raises OSError if this VS installation does not contain VC
-                listdir(join(vs_path, r'VC\Tools\MSVC'))
-
-                # Store version and path
-                vs_versions[self._as_float_version(
-                    state['installationVersion'])] = vs_path
-
-            except (OSError, IOError, KeyError):
-                # Skip if "state.json" file is missing or bad format
-                continue
-
-        return vs_versions
-
-    @staticmethod
-    def _as_float_version(version):
-        """
-        Return a string version as a simplified float version (major.minor)
-
-        Parameters
-        ----------
-        version: str
-            Version.
-
-        Return
-        ------
-        float
-            version
-        """
-        return float('.'.join(version.split('.')[:2]))
-
-    @property
-    def VSInstallDir(self):
-        """
-        Microsoft Visual Studio directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Default path
-        default = join(self.ProgramFilesx86,
-                       'Microsoft Visual Studio %0.1f' % self.vs_ver)
-
-        # Try to get path from registry, if fail use default path
-        return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default
-
-    @property
-    def VCInstallDir(self):
-        """
-        Microsoft Visual C++ directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        path = self._guess_vc() or self._guess_vc_legacy()
-
-        if not isdir(path):
-            msg = 'Microsoft Visual C++ directory not found'
-            raise distutils.errors.DistutilsPlatformError(msg)
-
-        return path
-
-    def _guess_vc(self):
-        """
-        Locate Visual C++ for VS2017+.
-
-        Return
-        ------
-        str
-            path
-        """
-        if self.vs_ver <= 14.0:
-            return ''
-
-        try:
-            # First search in known VS paths
-            vs_dir = self.known_vs_paths[self.vs_ver]
-        except KeyError:
-            # Else, search with path from registry
-            vs_dir = self.VSInstallDir
-
-        guess_vc = join(vs_dir, r'VC\Tools\MSVC')
-
-        # Subdir with VC exact version as name
-        try:
-            # Update the VC version with real one instead of VS version
-            vc_ver = listdir(guess_vc)[-1]
-            self.vc_ver = self._as_float_version(vc_ver)
-            return join(guess_vc, vc_ver)
-        except (OSError, IOError, IndexError):
-            return ''
-
-    def _guess_vc_legacy(self):
-        """
-        Locate Visual C++ for versions prior to 2017.
-
-        Return
-        ------
-        str
-            path
-        """
-        default = join(self.ProgramFilesx86,
-                       r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver)
-
-        # Try to get "VC++ for Python" path from registry as default path
-        reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver)
-        python_vc = self.ri.lookup(reg_path, 'installdir')
-        default_vc = join(python_vc, 'VC') if python_vc else default
-
-        # Try to get path from registry, if fail use default path
-        return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc
-
-    @property
-    def WindowsSdkVersion(self):
-        """
-        Microsoft Windows SDK versions for specified MSVC++ version.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        if self.vs_ver <= 9.0:
-            return '7.0', '6.1', '6.0a'
-        elif self.vs_ver == 10.0:
-            return '7.1', '7.0a'
-        elif self.vs_ver == 11.0:
-            return '8.0', '8.0a'
-        elif self.vs_ver == 12.0:
-            return '8.1', '8.1a'
-        elif self.vs_ver >= 14.0:
-            return '10.0', '8.1'
-
-    @property
-    def WindowsSdkLastVersion(self):
-        """
-        Microsoft Windows SDK last version.
-
-        Return
-        ------
-        str
-            version
-        """
-        return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib'))
-
-    @property  # noqa: C901
-    def WindowsSdkDir(self):  # noqa: C901  # is too complex (12)  # FIXME
-        """
-        Microsoft Windows SDK directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        sdkdir = ''
-        for ver in self.WindowsSdkVersion:
-            # Try to get it from registry
-            loc = join(self.ri.windows_sdk, 'v%s' % ver)
-            sdkdir = self.ri.lookup(loc, 'installationfolder')
-            if sdkdir:
-                break
-        if not sdkdir or not isdir(sdkdir):
-            # Try to get "VC++ for Python" version from registry
-            path = join(self.ri.vc_for_python, '%0.1f' % self.vc_ver)
-            install_base = self.ri.lookup(path, 'installdir')
-            if install_base:
-                sdkdir = join(install_base, 'WinSDK')
-        if not sdkdir or not isdir(sdkdir):
-            # If fail, use default new path
-            for ver in self.WindowsSdkVersion:
-                intver = ver[:ver.rfind('.')]
-                path = r'Microsoft SDKs\Windows Kits\%s' % intver
-                d = join(self.ProgramFiles, path)
-                if isdir(d):
-                    sdkdir = d
-        if not sdkdir or not isdir(sdkdir):
-            # If fail, use default old path
-            for ver in self.WindowsSdkVersion:
-                path = r'Microsoft SDKs\Windows\v%s' % ver
-                d = join(self.ProgramFiles, path)
-                if isdir(d):
-                    sdkdir = d
-        if not sdkdir:
-            # If fail, use Platform SDK
-            sdkdir = join(self.VCInstallDir, 'PlatformSDK')
-        return sdkdir
-
-    @property
-    def WindowsSDKExecutablePath(self):
-        """
-        Microsoft Windows SDK executable directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Find WinSDK NetFx Tools registry dir name
-        if self.vs_ver <= 11.0:
-            netfxver = 35
-            arch = ''
-        else:
-            netfxver = 40
-            hidex86 = True if self.vs_ver <= 12.0 else False
-            arch = self.pi.current_dir(x64=True, hidex86=hidex86)
-        fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-'))
-
-        # list all possibles registry paths
-        regpaths = []
-        if self.vs_ver >= 14.0:
-            for ver in self.NetFxSdkVersion:
-                regpaths += [join(self.ri.netfx_sdk, ver, fx)]
-
-        for ver in self.WindowsSdkVersion:
-            regpaths += [join(self.ri.windows_sdk, 'v%sA' % ver, fx)]
-
-        # Return installation folder from the more recent path
-        for path in regpaths:
-            execpath = self.ri.lookup(path, 'installationfolder')
-            if execpath:
-                return execpath
-
-    @property
-    def FSharpInstallDir(self):
-        """
-        Microsoft Visual F# directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        path = join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver)
-        return self.ri.lookup(path, 'productdir') or ''
-
-    @property
-    def UniversalCRTSdkDir(self):
-        """
-        Microsoft Universal CRT SDK directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Set Kit Roots versions for specified MSVC++ version
-        vers = ('10', '81') if self.vs_ver >= 14.0 else ()
-
-        # Find path of the more recent Kit
-        for ver in vers:
-            sdkdir = self.ri.lookup(self.ri.windows_kits_roots,
-                                    'kitsroot%s' % ver)
-            if sdkdir:
-                return sdkdir or ''
-
-    @property
-    def UniversalCRTSdkLastVersion(self):
-        """
-        Microsoft Universal C Runtime SDK last version.
-
-        Return
-        ------
-        str
-            version
-        """
-        return self._use_last_dir_name(join(self.UniversalCRTSdkDir, 'lib'))
-
-    @property
-    def NetFxSdkVersion(self):
-        """
-        Microsoft .NET Framework SDK versions.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        # Set FxSdk versions for specified VS version
-        return (('4.7.2', '4.7.1', '4.7',
-                 '4.6.2', '4.6.1', '4.6',
-                 '4.5.2', '4.5.1', '4.5')
-                if self.vs_ver >= 14.0 else ())
-
-    @property
-    def NetFxSdkDir(self):
-        """
-        Microsoft .NET Framework SDK directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        sdkdir = ''
-        for ver in self.NetFxSdkVersion:
-            loc = join(self.ri.netfx_sdk, ver)
-            sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder')
-            if sdkdir:
-                break
-        return sdkdir
-
-    @property
-    def FrameworkDir32(self):
-        """
-        Microsoft .NET Framework 32bit directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Default path
-        guess_fw = join(self.WinDir, r'Microsoft.NET\Framework')
-
-        # Try to get path from registry, if fail use default path
-        return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw
-
-    @property
-    def FrameworkDir64(self):
-        """
-        Microsoft .NET Framework 64bit directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Default path
-        guess_fw = join(self.WinDir, r'Microsoft.NET\Framework64')
-
-        # Try to get path from registry, if fail use default path
-        return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw
-
-    @property
-    def FrameworkVersion32(self):
-        """
-        Microsoft .NET Framework 32bit versions.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        return self._find_dot_net_versions(32)
-
-    @property
-    def FrameworkVersion64(self):
-        """
-        Microsoft .NET Framework 64bit versions.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        return self._find_dot_net_versions(64)
-
-    def _find_dot_net_versions(self, bits):
-        """
-        Find Microsoft .NET Framework versions.
-
-        Parameters
-        ----------
-        bits: int
-            Platform number of bits: 32 or 64.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        # Find actual .NET version in registry
-        reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits)
-        dot_net_dir = getattr(self, 'FrameworkDir%d' % bits)
-        ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or ''
-
-        # Set .NET versions for specified MSVC++ version
-        if self.vs_ver >= 12.0:
-            return ver, 'v4.0'
-        elif self.vs_ver >= 10.0:
-            return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5'
-        elif self.vs_ver == 9.0:
-            return 'v3.5', 'v2.0.50727'
-        elif self.vs_ver == 8.0:
-            return 'v3.0', 'v2.0.50727'
-
-    @staticmethod
-    def _use_last_dir_name(path, prefix=''):
-        """
-        Return name of the last dir in path or '' if no dir found.
-
-        Parameters
-        ----------
-        path: str
-            Use dirs in this path
-        prefix: str
-            Use only dirs starting by this prefix
-
-        Return
-        ------
-        str
-            name
-        """
-        matching_dirs = (
-            dir_name
-            for dir_name in reversed(listdir(path))
-            if isdir(join(path, dir_name)) and
-            dir_name.startswith(prefix)
-        )
-        return next(matching_dirs, None) or ''
-
-
-class EnvironmentInfo:
-    """
-    Return environment variables for specified Microsoft Visual C++ version
-    and platform : Lib, Include, Path and libpath.
-
-    This function is compatible with Microsoft Visual C++ 9.0 to 14.X.
-
-    Script created by analysing Microsoft environment configuration files like
-    "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ...
-
-    Parameters
-    ----------
-    arch: str
-        Target architecture.
-    vc_ver: float
-        Required Microsoft Visual C++ version. If not set, autodetect the last
-        version.
-    vc_min_ver: float
-        Minimum Microsoft Visual C++ version.
-    """
-
-    # Variables and properties in this class use originals CamelCase variables
-    # names from Microsoft source files for more easy comparison.
-
-    def __init__(self, arch, vc_ver=None, vc_min_ver=0):
-        self.pi = PlatformInfo(arch)
-        self.ri = RegistryInfo(self.pi)
-        self.si = SystemInfo(self.ri, vc_ver)
-
-        if self.vc_ver < vc_min_ver:
-            err = 'No suitable Microsoft Visual C++ version found'
-            raise distutils.errors.DistutilsPlatformError(err)
-
-    @property
-    def vs_ver(self):
-        """
-        Microsoft Visual Studio.
-
-        Return
-        ------
-        float
-            version
-        """
-        return self.si.vs_ver
-
-    @property
-    def vc_ver(self):
-        """
-        Microsoft Visual C++ version.
-
-        Return
-        ------
-        float
-            version
-        """
-        return self.si.vc_ver
-
-    @property
-    def VSTools(self):
-        """
-        Microsoft Visual Studio Tools.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        paths = [r'Common7\IDE', r'Common7\Tools']
-
-        if self.vs_ver >= 14.0:
-            arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
-            paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow']
-            paths += [r'Team Tools\Performance Tools']
-            paths += [r'Team Tools\Performance Tools%s' % arch_subdir]
-
-        return [join(self.si.VSInstallDir, path) for path in paths]
-
-    @property
-    def VCIncludes(self):
-        """
-        Microsoft Visual C++ & Microsoft Foundation Class Includes.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        return [join(self.si.VCInstallDir, 'Include'),
-                join(self.si.VCInstallDir, r'ATLMFC\Include')]
-
-    @property
-    def VCLibraries(self):
-        """
-        Microsoft Visual C++ & Microsoft Foundation Class Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver >= 15.0:
-            arch_subdir = self.pi.target_dir(x64=True)
-        else:
-            arch_subdir = self.pi.target_dir(hidex86=True)
-        paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir]
-
-        if self.vs_ver >= 14.0:
-            paths += [r'Lib\store%s' % arch_subdir]
-
-        return [join(self.si.VCInstallDir, path) for path in paths]
-
-    @property
-    def VCStoreRefs(self):
-        """
-        Microsoft Visual C++ store references Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0:
-            return []
-        return [join(self.si.VCInstallDir, r'Lib\store\references')]
-
-    @property
-    def VCTools(self):
-        """
-        Microsoft Visual C++ Tools.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        si = self.si
-        tools = [join(si.VCInstallDir, 'VCPackages')]
-
-        forcex86 = True if self.vs_ver <= 10.0 else False
-        arch_subdir = self.pi.cross_dir(forcex86)
-        if arch_subdir:
-            tools += [join(si.VCInstallDir, 'Bin%s' % arch_subdir)]
-
-        if self.vs_ver == 14.0:
-            path = 'Bin%s' % self.pi.current_dir(hidex86=True)
-            tools += [join(si.VCInstallDir, path)]
-
-        elif self.vs_ver >= 15.0:
-            host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else
-                        r'bin\HostX64%s')
-            tools += [join(
-                si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))]
-
-            if self.pi.current_cpu != self.pi.target_cpu:
-                tools += [join(
-                    si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))]
-
-        else:
-            tools += [join(si.VCInstallDir, 'Bin')]
-
-        return tools
-
-    @property
-    def OSLibraries(self):
-        """
-        Microsoft Windows SDK Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver <= 10.0:
-            arch_subdir = self.pi.target_dir(hidex86=True, x64=True)
-            return [join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)]
-
-        else:
-            arch_subdir = self.pi.target_dir(x64=True)
-            lib = join(self.si.WindowsSdkDir, 'lib')
-            libver = self._sdk_subdir
-            return [join(lib, '%sum%s' % (libver, arch_subdir))]
-
-    @property
-    def OSIncludes(self):
-        """
-        Microsoft Windows SDK Include.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        include = join(self.si.WindowsSdkDir, 'include')
-
-        if self.vs_ver <= 10.0:
-            return [include, join(include, 'gl')]
-
-        else:
-            if self.vs_ver >= 14.0:
-                sdkver = self._sdk_subdir
-            else:
-                sdkver = ''
-            return [join(include, '%sshared' % sdkver),
-                    join(include, '%sum' % sdkver),
-                    join(include, '%swinrt' % sdkver)]
-
-    @property
-    def OSLibpath(self):
-        """
-        Microsoft Windows SDK Libraries Paths.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        ref = join(self.si.WindowsSdkDir, 'References')
-        libpath = []
-
-        if self.vs_ver <= 9.0:
-            libpath += self.OSLibraries
-
-        if self.vs_ver >= 11.0:
-            libpath += [join(ref, r'CommonConfiguration\Neutral')]
-
-        if self.vs_ver >= 14.0:
-            libpath += [
-                ref,
-                join(self.si.WindowsSdkDir, 'UnionMetadata'),
-                join(
-                    ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'),
-                join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'),
-                join(
-                    ref, 'Windows.Networking.Connectivity.WwanContract',
-                    '1.0.0.0'),
-                join(
-                    self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs',
-                    '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration',
-                    'neutral'),
-            ]
-        return libpath
-
-    @property
-    def SdkTools(self):
-        """
-        Microsoft Windows SDK Tools.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        return list(self._sdk_tools())
-
-    def _sdk_tools(self):
-        """
-        Microsoft Windows SDK Tools paths generator.
-
-        Return
-        ------
-        generator of str
-            paths
-        """
-        if self.vs_ver < 15.0:
-            bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86'
-            yield join(self.si.WindowsSdkDir, bin_dir)
-
-        if not self.pi.current_is_x86():
-            arch_subdir = self.pi.current_dir(x64=True)
-            path = 'Bin%s' % arch_subdir
-            yield join(self.si.WindowsSdkDir, path)
-
-        if self.vs_ver in (10.0, 11.0):
-            if self.pi.target_is_x86():
-                arch_subdir = ''
-            else:
-                arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
-            path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir
-            yield join(self.si.WindowsSdkDir, path)
-
-        elif self.vs_ver >= 15.0:
-            path = join(self.si.WindowsSdkDir, 'Bin')
-            arch_subdir = self.pi.current_dir(x64=True)
-            sdkver = self.si.WindowsSdkLastVersion
-            yield join(path, '%s%s' % (sdkver, arch_subdir))
-
-        if self.si.WindowsSDKExecutablePath:
-            yield self.si.WindowsSDKExecutablePath
-
-    @property
-    def _sdk_subdir(self):
-        """
-        Microsoft Windows SDK version subdir.
-
-        Return
-        ------
-        str
-            subdir
-        """
-        ucrtver = self.si.WindowsSdkLastVersion
-        return ('%s\\' % ucrtver) if ucrtver else ''
-
-    @property
-    def SdkSetup(self):
-        """
-        Microsoft Windows SDK Setup.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver > 9.0:
-            return []
-
-        return [join(self.si.WindowsSdkDir, 'Setup')]
-
-    @property
-    def FxTools(self):
-        """
-        Microsoft .NET Framework Tools.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        pi = self.pi
-        si = self.si
-
-        if self.vs_ver <= 10.0:
-            include32 = True
-            include64 = not pi.target_is_x86() and not pi.current_is_x86()
-        else:
-            include32 = pi.target_is_x86() or pi.current_is_x86()
-            include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64'
-
-        tools = []
-        if include32:
-            tools += [join(si.FrameworkDir32, ver)
-                      for ver in si.FrameworkVersion32]
-        if include64:
-            tools += [join(si.FrameworkDir64, ver)
-                      for ver in si.FrameworkVersion64]
-        return tools
-
-    @property
-    def NetFxSDKLibraries(self):
-        """
-        Microsoft .Net Framework SDK Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:
-            return []
-
-        arch_subdir = self.pi.target_dir(x64=True)
-        return [join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)]
-
-    @property
-    def NetFxSDKIncludes(self):
-        """
-        Microsoft .Net Framework SDK Includes.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:
-            return []
-
-        return [join(self.si.NetFxSdkDir, r'include\um')]
-
-    @property
-    def VsTDb(self):
-        """
-        Microsoft Visual Studio Team System Database.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        return [join(self.si.VSInstallDir, r'VSTSDB\Deploy')]
-
-    @property
-    def MSBuild(self):
-        """
-        Microsoft Build Engine.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 12.0:
-            return []
-        elif self.vs_ver < 15.0:
-            base_path = self.si.ProgramFilesx86
-            arch_subdir = self.pi.current_dir(hidex86=True)
-        else:
-            base_path = self.si.VSInstallDir
-            arch_subdir = ''
-
-        path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir)
-        build = [join(base_path, path)]
-
-        if self.vs_ver >= 15.0:
-            # Add Roslyn C# & Visual Basic Compiler
-            build += [join(base_path, path, 'Roslyn')]
-
-        return build
-
-    @property
-    def HTMLHelpWorkshop(self):
-        """
-        Microsoft HTML Help Workshop.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 11.0:
-            return []
-
-        return [join(self.si.ProgramFilesx86, 'HTML Help Workshop')]
-
-    @property
-    def UCRTLibraries(self):
-        """
-        Microsoft Universal C Runtime SDK Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0:
-            return []
-
-        arch_subdir = self.pi.target_dir(x64=True)
-        lib = join(self.si.UniversalCRTSdkDir, 'lib')
-        ucrtver = self._ucrt_subdir
-        return [join(lib, '%sucrt%s' % (ucrtver, arch_subdir))]
-
-    @property
-    def UCRTIncludes(self):
-        """
-        Microsoft Universal C Runtime SDK Include.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0:
-            return []
-
-        include = join(self.si.UniversalCRTSdkDir, 'include')
-        return [join(include, '%sucrt' % self._ucrt_subdir)]
-
-    @property
-    def _ucrt_subdir(self):
-        """
-        Microsoft Universal C Runtime SDK version subdir.
-
-        Return
-        ------
-        str
-            subdir
-        """
-        ucrtver = self.si.UniversalCRTSdkLastVersion
-        return ('%s\\' % ucrtver) if ucrtver else ''
-
-    @property
-    def FSharp(self):
-        """
-        Microsoft Visual F#.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if 11.0 > self.vs_ver > 12.0:
-            return []
-
-        return [self.si.FSharpInstallDir]
-
-    @property
-    def VCRuntimeRedist(self):
-        """
-        Microsoft Visual C++ runtime redistributable dll.
-
-        Return
-        ------
-        str
-            path
-        """
-        vcruntime = 'vcruntime%d0.dll' % self.vc_ver
-        arch_subdir = self.pi.target_dir(x64=True).strip('\\')
-
-        # Installation prefixes candidates
-        prefixes = []
-        tools_path = self.si.VCInstallDir
-        redist_path = dirname(tools_path.replace(r'\Tools', r'\Redist'))
-        if isdir(redist_path):
-            # Redist version may not be exactly the same as tools
-            redist_path = join(redist_path, listdir(redist_path)[-1])
-            prefixes += [redist_path, join(redist_path, 'onecore')]
-
-        prefixes += [join(tools_path, 'redist')]  # VS14 legacy path
-
-        # CRT directory
-        crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10),
-                    # Sometime store in directory with VS version instead of VC
-                    'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10))
-
-        # vcruntime path
-        for prefix, crt_dir in itertools.product(prefixes, crt_dirs):
-            path = join(prefix, arch_subdir, crt_dir, vcruntime)
-            if isfile(path):
-                return path
-
-    def return_env(self, exists=True):
-        """
-        Return environment dict.
-
-        Parameters
-        ----------
-        exists: bool
-            It True, only return existing paths.
-
-        Return
-        ------
-        dict
-            environment
-        """
-        env = dict(
-            include=self._build_paths('include',
-                                      [self.VCIncludes,
-                                       self.OSIncludes,
-                                       self.UCRTIncludes,
-                                       self.NetFxSDKIncludes],
-                                      exists),
-            lib=self._build_paths('lib',
-                                  [self.VCLibraries,
-                                   self.OSLibraries,
-                                   self.FxTools,
-                                   self.UCRTLibraries,
-                                   self.NetFxSDKLibraries],
-                                  exists),
-            libpath=self._build_paths('libpath',
-                                      [self.VCLibraries,
-                                       self.FxTools,
-                                       self.VCStoreRefs,
-                                       self.OSLibpath],
-                                      exists),
-            path=self._build_paths('path',
-                                   [self.VCTools,
-                                    self.VSTools,
-                                    self.VsTDb,
-                                    self.SdkTools,
-                                    self.SdkSetup,
-                                    self.FxTools,
-                                    self.MSBuild,
-                                    self.HTMLHelpWorkshop,
-                                    self.FSharp],
-                                   exists),
-        )
-        if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist):
-            env['py_vcruntime_redist'] = self.VCRuntimeRedist
-        return env
-
-    def _build_paths(self, name, spec_path_lists, exists):
-        """
-        Given an environment variable name and specified paths,
-        return a pathsep-separated string of paths containing
-        unique, extant, directories from those paths and from
-        the environment variable. Raise an error if no paths
-        are resolved.
-
-        Parameters
-        ----------
-        name: str
-            Environment variable name
-        spec_path_lists: list of str
-            Paths
-        exists: bool
-            It True, only return existing paths.
-
-        Return
-        ------
-        str
-            Pathsep-separated paths
-        """
-        # flatten spec_path_lists
-        spec_paths = itertools.chain.from_iterable(spec_path_lists)
-        env_paths = environ.get(name, '').split(pathsep)
-        paths = itertools.chain(spec_paths, env_paths)
-        extant_paths = list(filter(isdir, paths)) if exists else paths
-        if not extant_paths:
-            msg = "%s environment variable is empty" % name.upper()
-            raise distutils.errors.DistutilsPlatformError(msg)
-        unique_paths = unique_everseen(extant_paths)
-        return pathsep.join(unique_paths)
diff --git a/venv/lib/python3.11/site-packages/setuptools/namespaces.py b/venv/lib/python3.11/site-packages/setuptools/namespaces.py
deleted file mode 100755
index 44939e1..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/namespaces.py
+++ /dev/null
@@ -1,107 +0,0 @@
-import os
-from distutils import log
-import itertools
-
-
-flatten = itertools.chain.from_iterable
-
-
-class Installer:
-
-    nspkg_ext = '-nspkg.pth'
-
-    def install_namespaces(self):
-        nsp = self._get_all_ns_packages()
-        if not nsp:
-            return
-        filename, ext = os.path.splitext(self._get_target())
-        filename += self.nspkg_ext
-        self.outputs.append(filename)
-        log.info("Installing %s", filename)
-        lines = map(self._gen_nspkg_line, nsp)
-
-        if self.dry_run:
-            # always generate the lines, even in dry run
-            list(lines)
-            return
-
-        with open(filename, 'wt') as f:
-            f.writelines(lines)
-
-    def uninstall_namespaces(self):
-        filename, ext = os.path.splitext(self._get_target())
-        filename += self.nspkg_ext
-        if not os.path.exists(filename):
-            return
-        log.info("Removing %s", filename)
-        os.remove(filename)
-
-    def _get_target(self):
-        return self.target
-
-    _nspkg_tmpl = (
-        "import sys, types, os",
-        "has_mfs = sys.version_info > (3, 5)",
-        "p = os.path.join(%(root)s, *%(pth)r)",
-        "importlib = has_mfs and __import__('importlib.util')",
-        "has_mfs and __import__('importlib.machinery')",
-        (
-            "m = has_mfs and "
-            "sys.modules.setdefault(%(pkg)r, "
-            "importlib.util.module_from_spec("
-            "importlib.machinery.PathFinder.find_spec(%(pkg)r, "
-            "[os.path.dirname(p)])))"
-        ),
-        (
-            "m = m or "
-            "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))"
-        ),
-        "mp = (m or []) and m.__dict__.setdefault('__path__',[])",
-        "(p not in mp) and mp.append(p)",
-    )
-    "lines for the namespace installer"
-
-    _nspkg_tmpl_multi = (
-        'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
-    )
-    "additional line(s) when a parent package is indicated"
-
-    def _get_root(self):
-        return "sys._getframe(1).f_locals['sitedir']"
-
-    def _gen_nspkg_line(self, pkg):
-        pth = tuple(pkg.split('.'))
-        root = self._get_root()
-        tmpl_lines = self._nspkg_tmpl
-        parent, sep, child = pkg.rpartition('.')
-        if parent:
-            tmpl_lines += self._nspkg_tmpl_multi
-        return ';'.join(tmpl_lines) % locals() + '\n'
-
-    def _get_all_ns_packages(self):
-        """Return sorted list of all package namespaces"""
-        pkgs = self.distribution.namespace_packages or []
-        return sorted(flatten(map(self._pkg_names, pkgs)))
-
-    @staticmethod
-    def _pkg_names(pkg):
-        """
-        Given a namespace package, yield the components of that
-        package.
-
-        >>> names = Installer._pkg_names('a.b.c')
-        >>> set(names) == set(['a', 'a.b', 'a.b.c'])
-        True
-        """
-        parts = pkg.split('.')
-        while parts:
-            yield '.'.join(parts)
-            parts.pop()
-
-
-class DevelopInstaller(Installer):
-    def _get_root(self):
-        return repr(str(self.egg_path))
-
-    def _get_target(self):
-        return self.egg_link
diff --git a/venv/lib/python3.11/site-packages/setuptools/package_index.py b/venv/lib/python3.11/site-packages/setuptools/package_index.py
deleted file mode 100755
index 89f59ac..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/package_index.py
+++ /dev/null
@@ -1,1181 +0,0 @@
-"""PyPI and direct package downloading."""
-
-import sys
-import subprocess
-import os
-import re
-import io
-import shutil
-import socket
-import base64
-import hashlib
-import itertools
-import warnings
-import configparser
-import html
-import http.client
-import urllib.parse
-import urllib.request
-import urllib.error
-from functools import wraps
-
-import setuptools
-from pkg_resources import (
-    CHECKOUT_DIST,
-    Distribution,
-    BINARY_DIST,
-    normalize_path,
-    SOURCE_DIST,
-    Environment,
-    find_distributions,
-    safe_name,
-    safe_version,
-    to_filename,
-    Requirement,
-    DEVELOP_DIST,
-    EGG_DIST,
-    parse_version,
-)
-from distutils import log
-from distutils.errors import DistutilsError
-from fnmatch import translate
-from setuptools.wheel import Wheel
-from setuptools.extern.more_itertools import unique_everseen
-
-
-EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.+!]+)$')
-HREF = re.compile(r"""href\s*=\s*['"]?([^'"> ]+)""", re.I)
-PYPI_MD5 = re.compile(
-    r'([^<]+)\n\s+\(md5\)'
-)
-URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):', re.I).match
-EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split()
-
-__all__ = [
-    'PackageIndex',
-    'distros_for_url',
-    'parse_bdist_wininst',
-    'interpret_distro_name',
-]
-
-_SOCKET_TIMEOUT = 15
-
-_tmpl = "setuptools/{setuptools.__version__} Python-urllib/{py_major}"
-user_agent = _tmpl.format(
-    py_major='{}.{}'.format(*sys.version_info), setuptools=setuptools
-)
-
-
-def parse_requirement_arg(spec):
-    try:
-        return Requirement.parse(spec)
-    except ValueError as e:
-        raise DistutilsError(
-            "Not a URL, existing file, or requirement spec: %r" % (spec,)
-        ) from e
-
-
-def parse_bdist_wininst(name):
-    """Return (base,pyversion) or (None,None) for possible .exe name"""
-
-    lower = name.lower()
-    base, py_ver, plat = None, None, None
-
-    if lower.endswith('.exe'):
-        if lower.endswith('.win32.exe'):
-            base = name[:-10]
-            plat = 'win32'
-        elif lower.startswith('.win32-py', -16):
-            py_ver = name[-7:-4]
-            base = name[:-16]
-            plat = 'win32'
-        elif lower.endswith('.win-amd64.exe'):
-            base = name[:-14]
-            plat = 'win-amd64'
-        elif lower.startswith('.win-amd64-py', -20):
-            py_ver = name[-7:-4]
-            base = name[:-20]
-            plat = 'win-amd64'
-    return base, py_ver, plat
-
-
-def egg_info_for_url(url):
-    parts = urllib.parse.urlparse(url)
-    scheme, server, path, parameters, query, fragment = parts
-    base = urllib.parse.unquote(path.split('/')[-1])
-    if server == 'sourceforge.net' and base == 'download':  # XXX Yuck
-        base = urllib.parse.unquote(path.split('/')[-2])
-    if '#' in base:
-        base, fragment = base.split('#', 1)
-    return base, fragment
-
-
-def distros_for_url(url, metadata=None):
-    """Yield egg or source distribution objects that might be found at a URL"""
-    base, fragment = egg_info_for_url(url)
-    for dist in distros_for_location(url, base, metadata):
-        yield dist
-    if fragment:
-        match = EGG_FRAGMENT.match(fragment)
-        if match:
-            for dist in interpret_distro_name(
-                url, match.group(1), metadata, precedence=CHECKOUT_DIST
-            ):
-                yield dist
-
-
-def distros_for_location(location, basename, metadata=None):
-    """Yield egg or source distribution objects based on basename"""
-    if basename.endswith('.egg.zip'):
-        basename = basename[:-4]  # strip the .zip
-    if basename.endswith('.egg') and '-' in basename:
-        # only one, unambiguous interpretation
-        return [Distribution.from_location(location, basename, metadata)]
-    if basename.endswith('.whl') and '-' in basename:
-        wheel = Wheel(basename)
-        if not wheel.is_compatible():
-            return []
-        return [
-            Distribution(
-                location=location,
-                project_name=wheel.project_name,
-                version=wheel.version,
-                # Increase priority over eggs.
-                precedence=EGG_DIST + 1,
-            )
-        ]
-    if basename.endswith('.exe'):
-        win_base, py_ver, platform = parse_bdist_wininst(basename)
-        if win_base is not None:
-            return interpret_distro_name(
-                location, win_base, metadata, py_ver, BINARY_DIST, platform
-            )
-    # Try source distro extensions (.zip, .tgz, etc.)
-    #
-    for ext in EXTENSIONS:
-        if basename.endswith(ext):
-            basename = basename[: -len(ext)]
-            return interpret_distro_name(location, basename, metadata)
-    return []  # no extension matched
-
-
-def distros_for_filename(filename, metadata=None):
-    """Yield possible egg or source distribution objects based on a filename"""
-    return distros_for_location(
-        normalize_path(filename), os.path.basename(filename), metadata
-    )
-
-
-def interpret_distro_name(
-    location, basename, metadata, py_version=None, precedence=SOURCE_DIST, platform=None
-):
-    """Generate the interpretation of a source distro name
-
-    Note: if `location` is a filesystem filename, you should call
-    ``pkg_resources.normalize_path()`` on it before passing it to this
-    routine!
-    """
-
-    parts = basename.split('-')
-    if not py_version and any(re.match(r'py\d\.\d$', p) for p in parts[2:]):
-        # it is a bdist_dumb, not an sdist -- bail out
-        return
-
-    # find the pivot (p) that splits the name from the version.
-    # infer the version as the first item that has a digit.
-    for p in range(len(parts)):
-        if parts[p][:1].isdigit():
-            break
-    else:
-        p = len(parts)
-
-    yield Distribution(
-        location,
-        metadata,
-        '-'.join(parts[:p]),
-        '-'.join(parts[p:]),
-        py_version=py_version,
-        precedence=precedence,
-        platform=platform
-    )
-
-
-def unique_values(func):
-    """
-    Wrap a function returning an iterable such that the resulting iterable
-    only ever yields unique items.
-    """
-
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        return unique_everseen(func(*args, **kwargs))
-
-    return wrapper
-
-
-REL = re.compile(r"""<([^>]*\srel\s{0,10}=\s{0,10}['"]?([^'" >]+)[^>]*)>""", re.I)
-"""
-Regex for an HTML tag with 'rel="val"' attributes.
-"""
-
-
-@unique_values
-def find_external_links(url, page):
-    """Find rel="homepage" and rel="download" links in `page`, yielding URLs"""
-
-    for match in REL.finditer(page):
-        tag, rel = match.groups()
-        rels = set(map(str.strip, rel.lower().split(',')))
-        if 'homepage' in rels or 'download' in rels:
-            for match in HREF.finditer(tag):
-                yield urllib.parse.urljoin(url, htmldecode(match.group(1)))
-
-    for tag in ("Home Page", "Download URL"):
-        pos = page.find(tag)
-        if pos != -1:
-            match = HREF.search(page, pos)
-            if match:
-                yield urllib.parse.urljoin(url, htmldecode(match.group(1)))
-
-
-class ContentChecker:
-    """
-    A null content checker that defines the interface for checking content
-    """
-
-    def feed(self, block):
-        """
-        Feed a block of data to the hash.
-        """
-        return
-
-    def is_valid(self):
-        """
-        Check the hash. Return False if validation fails.
-        """
-        return True
-
-    def report(self, reporter, template):
-        """
-        Call reporter with information about the checker (hash name)
-        substituted into the template.
-        """
-        return
-
-
-class HashChecker(ContentChecker):
-    pattern = re.compile(
-        r'(?Psha1|sha224|sha384|sha256|sha512|md5)='
-        r'(?P[a-f0-9]+)'
-    )
-
-    def __init__(self, hash_name, expected):
-        self.hash_name = hash_name
-        self.hash = hashlib.new(hash_name)
-        self.expected = expected
-
-    @classmethod
-    def from_url(cls, url):
-        "Construct a (possibly null) ContentChecker from a URL"
-        fragment = urllib.parse.urlparse(url)[-1]
-        if not fragment:
-            return ContentChecker()
-        match = cls.pattern.search(fragment)
-        if not match:
-            return ContentChecker()
-        return cls(**match.groupdict())
-
-    def feed(self, block):
-        self.hash.update(block)
-
-    def is_valid(self):
-        return self.hash.hexdigest() == self.expected
-
-    def report(self, reporter, template):
-        msg = template % self.hash_name
-        return reporter(msg)
-
-
-class PackageIndex(Environment):
-    """A distribution index that scans web pages for download URLs"""
-
-    def __init__(
-        self,
-        index_url="https://pypi.org/simple/",
-        hosts=('*',),
-        ca_bundle=None,
-        verify_ssl=True,
-        *args,
-        **kw
-    ):
-        super().__init__(*args, **kw)
-        self.index_url = index_url + "/"[: not index_url.endswith('/')]
-        self.scanned_urls = {}
-        self.fetched_urls = {}
-        self.package_pages = {}
-        self.allows = re.compile('|'.join(map(translate, hosts))).match
-        self.to_scan = []
-        self.opener = urllib.request.urlopen
-
-    def add(self, dist):
-        # ignore invalid versions
-        try:
-            parse_version(dist.version)
-        except Exception:
-            return
-        return super().add(dist)
-
-    # FIXME: 'PackageIndex.process_url' is too complex (14)
-    def process_url(self, url, retrieve=False):  # noqa: C901
-        """Evaluate a URL as a possible download, and maybe retrieve it"""
-        if url in self.scanned_urls and not retrieve:
-            return
-        self.scanned_urls[url] = True
-        if not URL_SCHEME(url):
-            self.process_filename(url)
-            return
-        else:
-            dists = list(distros_for_url(url))
-            if dists:
-                if not self.url_ok(url):
-                    return
-                self.debug("Found link: %s", url)
-
-        if dists or not retrieve or url in self.fetched_urls:
-            list(map(self.add, dists))
-            return  # don't need the actual page
-
-        if not self.url_ok(url):
-            self.fetched_urls[url] = True
-            return
-
-        self.info("Reading %s", url)
-        self.fetched_urls[url] = True  # prevent multiple fetch attempts
-        tmpl = "Download error on %s: %%s -- Some packages may not be found!"
-        f = self.open_url(url, tmpl % url)
-        if f is None:
-            return
-        if isinstance(f, urllib.error.HTTPError) and f.code == 401:
-            self.info("Authentication error: %s" % f.msg)
-        self.fetched_urls[f.url] = True
-        if 'html' not in f.headers.get('content-type', '').lower():
-            f.close()  # not html, we can't process it
-            return
-
-        base = f.url  # handle redirects
-        page = f.read()
-        if not isinstance(page, str):
-            # In Python 3 and got bytes but want str.
-            if isinstance(f, urllib.error.HTTPError):
-                # Errors have no charset, assume latin1:
-                charset = 'latin-1'
-            else:
-                charset = f.headers.get_param('charset') or 'latin-1'
-            page = page.decode(charset, "ignore")
-        f.close()
-        for match in HREF.finditer(page):
-            link = urllib.parse.urljoin(base, htmldecode(match.group(1)))
-            self.process_url(link)
-        if url.startswith(self.index_url) and getattr(f, 'code', None) != 404:
-            page = self.process_index(url, page)
-
-    def process_filename(self, fn, nested=False):
-        # process filenames or directories
-        if not os.path.exists(fn):
-            self.warn("Not found: %s", fn)
-            return
-
-        if os.path.isdir(fn) and not nested:
-            path = os.path.realpath(fn)
-            for item in os.listdir(path):
-                self.process_filename(os.path.join(path, item), True)
-
-        dists = distros_for_filename(fn)
-        if dists:
-            self.debug("Found: %s", fn)
-            list(map(self.add, dists))
-
-    def url_ok(self, url, fatal=False):
-        s = URL_SCHEME(url)
-        is_file = s and s.group(1).lower() == 'file'
-        if is_file or self.allows(urllib.parse.urlparse(url)[1]):
-            return True
-        msg = (
-            "\nNote: Bypassing %s (disallowed host; see "
-            "http://bit.ly/2hrImnY for details).\n"
-        )
-        if fatal:
-            raise DistutilsError(msg % url)
-        else:
-            self.warn(msg, url)
-
-    def scan_egg_links(self, search_path):
-        dirs = filter(os.path.isdir, search_path)
-        egg_links = (
-            (path, entry)
-            for path in dirs
-            for entry in os.listdir(path)
-            if entry.endswith('.egg-link')
-        )
-        list(itertools.starmap(self.scan_egg_link, egg_links))
-
-    def scan_egg_link(self, path, entry):
-        with open(os.path.join(path, entry)) as raw_lines:
-            # filter non-empty lines
-            lines = list(filter(None, map(str.strip, raw_lines)))
-
-        if len(lines) != 2:
-            # format is not recognized; punt
-            return
-
-        egg_path, setup_path = lines
-
-        for dist in find_distributions(os.path.join(path, egg_path)):
-            dist.location = os.path.join(path, *lines)
-            dist.precedence = SOURCE_DIST
-            self.add(dist)
-
-    def _scan(self, link):
-        # Process a URL to see if it's for a package page
-        NO_MATCH_SENTINEL = None, None
-        if not link.startswith(self.index_url):
-            return NO_MATCH_SENTINEL
-
-        parts = list(map(urllib.parse.unquote, link[len(self.index_url) :].split('/')))
-        if len(parts) != 2 or '#' in parts[1]:
-            return NO_MATCH_SENTINEL
-
-        # it's a package page, sanitize and index it
-        pkg = safe_name(parts[0])
-        ver = safe_version(parts[1])
-        self.package_pages.setdefault(pkg.lower(), {})[link] = True
-        return to_filename(pkg), to_filename(ver)
-
-    def process_index(self, url, page):
-        """Process the contents of a PyPI page"""
-
-        # process an index page into the package-page index
-        for match in HREF.finditer(page):
-            try:
-                self._scan(urllib.parse.urljoin(url, htmldecode(match.group(1))))
-            except ValueError:
-                pass
-
-        pkg, ver = self._scan(url)  # ensure this page is in the page index
-        if not pkg:
-            return ""  # no sense double-scanning non-package pages
-
-        # process individual package page
-        for new_url in find_external_links(url, page):
-            # Process the found URL
-            base, frag = egg_info_for_url(new_url)
-            if base.endswith('.py') and not frag:
-                if ver:
-                    new_url += '#egg=%s-%s' % (pkg, ver)
-                else:
-                    self.need_version_info(url)
-            self.scan_url(new_url)
-
-        return PYPI_MD5.sub(
-            lambda m: '%s' % m.group(1, 3, 2), page
-        )
-
-    def need_version_info(self, url):
-        self.scan_all(
-            "Page at %s links to .py file(s) without version info; an index "
-            "scan is required.",
-            url,
-        )
-
-    def scan_all(self, msg=None, *args):
-        if self.index_url not in self.fetched_urls:
-            if msg:
-                self.warn(msg, *args)
-            self.info("Scanning index of all packages (this may take a while)")
-        self.scan_url(self.index_url)
-
-    def find_packages(self, requirement):
-        self.scan_url(self.index_url + requirement.unsafe_name + '/')
-
-        if not self.package_pages.get(requirement.key):
-            # Fall back to safe version of the name
-            self.scan_url(self.index_url + requirement.project_name + '/')
-
-        if not self.package_pages.get(requirement.key):
-            # We couldn't find the target package, so search the index page too
-            self.not_found_in_index(requirement)
-
-        for url in list(self.package_pages.get(requirement.key, ())):
-            # scan each page that might be related to the desired package
-            self.scan_url(url)
-
-    def obtain(self, requirement, installer=None):
-        self.prescan()
-        self.find_packages(requirement)
-        for dist in self[requirement.key]:
-            if dist in requirement:
-                return dist
-            self.debug("%s does not match %s", requirement, dist)
-        return super(PackageIndex, self).obtain(requirement, installer)
-
-    def check_hash(self, checker, filename, tfp):
-        """
-        checker is a ContentChecker
-        """
-        checker.report(self.debug, "Validating %%s checksum for %s" % filename)
-        if not checker.is_valid():
-            tfp.close()
-            os.unlink(filename)
-            raise DistutilsError(
-                "%s validation failed for %s; "
-                "possible download problem?"
-                % (checker.hash.name, os.path.basename(filename))
-            )
-
-    def add_find_links(self, urls):
-        """Add `urls` to the list that will be prescanned for searches"""
-        for url in urls:
-            if (
-                self.to_scan is None  # if we have already "gone online"
-                or not URL_SCHEME(url)  # or it's a local file/directory
-                or url.startswith('file:')
-                or list(distros_for_url(url))  # or a direct package link
-            ):
-                # then go ahead and process it now
-                self.scan_url(url)
-            else:
-                # otherwise, defer retrieval till later
-                self.to_scan.append(url)
-
-    def prescan(self):
-        """Scan urls scheduled for prescanning (e.g. --find-links)"""
-        if self.to_scan:
-            list(map(self.scan_url, self.to_scan))
-        self.to_scan = None  # from now on, go ahead and process immediately
-
-    def not_found_in_index(self, requirement):
-        if self[requirement.key]:  # we've seen at least one distro
-            meth, msg = self.info, "Couldn't retrieve index page for %r"
-        else:  # no distros seen for this name, might be misspelled
-            meth, msg = (
-                self.warn,
-                "Couldn't find index page for %r (maybe misspelled?)",
-            )
-        meth(msg, requirement.unsafe_name)
-        self.scan_all()
-
-    def download(self, spec, tmpdir):
-        """Locate and/or download `spec` to `tmpdir`, returning a local path
-
-        `spec` may be a ``Requirement`` object, or a string containing a URL,
-        an existing local filename, or a project/version requirement spec
-        (i.e. the string form of a ``Requirement`` object).  If it is the URL
-        of a .py file with an unambiguous ``#egg=name-version`` tag (i.e., one
-        that escapes ``-`` as ``_`` throughout), a trivial ``setup.py`` is
-        automatically created alongside the downloaded file.
-
-        If `spec` is a ``Requirement`` object or a string containing a
-        project/version requirement spec, this method returns the location of
-        a matching distribution (possibly after downloading it to `tmpdir`).
-        If `spec` is a locally existing file or directory name, it is simply
-        returned unchanged.  If `spec` is a URL, it is downloaded to a subpath
-        of `tmpdir`, and the local filename is returned.  Various errors may be
-        raised if a problem occurs during downloading.
-        """
-        if not isinstance(spec, Requirement):
-            scheme = URL_SCHEME(spec)
-            if scheme:
-                # It's a url, download it to tmpdir
-                found = self._download_url(spec, tmpdir)
-                base, fragment = egg_info_for_url(spec)
-                if base.endswith('.py'):
-                    found = self.gen_setup(found, fragment, tmpdir)
-                return found
-            elif os.path.exists(spec):
-                # Existing file or directory, just return it
-                return spec
-            else:
-                spec = parse_requirement_arg(spec)
-        return getattr(self.fetch_distribution(spec, tmpdir), 'location', None)
-
-    def fetch_distribution(  # noqa: C901  # is too complex (14)  # FIXME
-        self,
-        requirement,
-        tmpdir,
-        force_scan=False,
-        source=False,
-        develop_ok=False,
-        local_index=None,
-    ):
-        """Obtain a distribution suitable for fulfilling `requirement`
-
-        `requirement` must be a ``pkg_resources.Requirement`` instance.
-        If necessary, or if the `force_scan` flag is set, the requirement is
-        searched for in the (online) package index as well as the locally
-        installed packages.  If a distribution matching `requirement` is found,
-        the returned distribution's ``location`` is the value you would have
-        gotten from calling the ``download()`` method with the matching
-        distribution's URL or filename.  If no matching distribution is found,
-        ``None`` is returned.
-
-        If the `source` flag is set, only source distributions and source
-        checkout links will be considered.  Unless the `develop_ok` flag is
-        set, development and system eggs (i.e., those using the ``.egg-info``
-        format) will be ignored.
-        """
-        # process a Requirement
-        self.info("Searching for %s", requirement)
-        skipped = {}
-        dist = None
-
-        def find(req, env=None):
-            if env is None:
-                env = self
-            # Find a matching distribution; may be called more than once
-
-            for dist in env[req.key]:
-
-                if dist.precedence == DEVELOP_DIST and not develop_ok:
-                    if dist not in skipped:
-                        self.warn(
-                            "Skipping development or system egg: %s",
-                            dist,
-                        )
-                        skipped[dist] = 1
-                    continue
-
-                test = dist in req and (dist.precedence <= SOURCE_DIST or not source)
-                if test:
-                    loc = self.download(dist.location, tmpdir)
-                    dist.download_location = loc
-                    if os.path.exists(dist.download_location):
-                        return dist
-
-        if force_scan:
-            self.prescan()
-            self.find_packages(requirement)
-            dist = find(requirement)
-
-        if not dist and local_index is not None:
-            dist = find(requirement, local_index)
-
-        if dist is None:
-            if self.to_scan is not None:
-                self.prescan()
-            dist = find(requirement)
-
-        if dist is None and not force_scan:
-            self.find_packages(requirement)
-            dist = find(requirement)
-
-        if dist is None:
-            self.warn(
-                "No local packages or working download links found for %s%s",
-                (source and "a source distribution of " or ""),
-                requirement,
-            )
-        else:
-            self.info("Best match: %s", dist)
-            return dist.clone(location=dist.download_location)
-
-    def fetch(self, requirement, tmpdir, force_scan=False, source=False):
-        """Obtain a file suitable for fulfilling `requirement`
-
-        DEPRECATED; use the ``fetch_distribution()`` method now instead.  For
-        backward compatibility, this routine is identical but returns the
-        ``location`` of the downloaded distribution instead of a distribution
-        object.
-        """
-        dist = self.fetch_distribution(requirement, tmpdir, force_scan, source)
-        if dist is not None:
-            return dist.location
-        return None
-
-    def gen_setup(self, filename, fragment, tmpdir):
-        match = EGG_FRAGMENT.match(fragment)
-        dists = (
-            match
-            and [
-                d
-                for d in interpret_distro_name(filename, match.group(1), None)
-                if d.version
-            ]
-            or []
-        )
-
-        if len(dists) == 1:  # unambiguous ``#egg`` fragment
-            basename = os.path.basename(filename)
-
-            # Make sure the file has been downloaded to the temp dir.
-            if os.path.dirname(filename) != tmpdir:
-                dst = os.path.join(tmpdir, basename)
-                if not (os.path.exists(dst) and os.path.samefile(filename, dst)):
-                    shutil.copy2(filename, dst)
-                    filename = dst
-
-            with open(os.path.join(tmpdir, 'setup.py'), 'w') as file:
-                file.write(
-                    "from setuptools import setup\n"
-                    "setup(name=%r, version=%r, py_modules=[%r])\n"
-                    % (
-                        dists[0].project_name,
-                        dists[0].version,
-                        os.path.splitext(basename)[0],
-                    )
-                )
-            return filename
-
-        elif match:
-            raise DistutilsError(
-                "Can't unambiguously interpret project/version identifier %r; "
-                "any dashes in the name or version should be escaped using "
-                "underscores. %r" % (fragment, dists)
-            )
-        else:
-            raise DistutilsError(
-                "Can't process plain .py files without an '#egg=name-version'"
-                " suffix to enable automatic setup script generation."
-            )
-
-    dl_blocksize = 8192
-
-    def _download_to(self, url, filename):
-        self.info("Downloading %s", url)
-        # Download the file
-        fp = None
-        try:
-            checker = HashChecker.from_url(url)
-            fp = self.open_url(url)
-            if isinstance(fp, urllib.error.HTTPError):
-                raise DistutilsError(
-                    "Can't download %s: %s %s" % (url, fp.code, fp.msg)
-                )
-            headers = fp.info()
-            blocknum = 0
-            bs = self.dl_blocksize
-            size = -1
-            if "content-length" in headers:
-                # Some servers return multiple Content-Length headers :(
-                sizes = headers.get_all('Content-Length')
-                size = max(map(int, sizes))
-                self.reporthook(url, filename, blocknum, bs, size)
-            with open(filename, 'wb') as tfp:
-                while True:
-                    block = fp.read(bs)
-                    if block:
-                        checker.feed(block)
-                        tfp.write(block)
-                        blocknum += 1
-                        self.reporthook(url, filename, blocknum, bs, size)
-                    else:
-                        break
-                self.check_hash(checker, filename, tfp)
-            return headers
-        finally:
-            if fp:
-                fp.close()
-
-    def reporthook(self, url, filename, blocknum, blksize, size):
-        pass  # no-op
-
-    # FIXME:
-    def open_url(self, url, warning=None):  # noqa: C901  # is too complex (12)
-        if url.startswith('file:'):
-            return local_open(url)
-        try:
-            return open_with_auth(url, self.opener)
-        except (ValueError, http.client.InvalidURL) as v:
-            msg = ' '.join([str(arg) for arg in v.args])
-            if warning:
-                self.warn(warning, msg)
-            else:
-                raise DistutilsError('%s %s' % (url, msg)) from v
-        except urllib.error.HTTPError as v:
-            return v
-        except urllib.error.URLError as v:
-            if warning:
-                self.warn(warning, v.reason)
-            else:
-                raise DistutilsError(
-                    "Download error for %s: %s" % (url, v.reason)
-                ) from v
-        except http.client.BadStatusLine as v:
-            if warning:
-                self.warn(warning, v.line)
-            else:
-                raise DistutilsError(
-                    '%s returned a bad status line. The server might be '
-                    'down, %s' % (url, v.line)
-                ) from v
-        except (http.client.HTTPException, socket.error) as v:
-            if warning:
-                self.warn(warning, v)
-            else:
-                raise DistutilsError("Download error for %s: %s" % (url, v)) from v
-
-    def _download_url(self, url, tmpdir):
-        # Determine download filename
-        #
-        name, fragment = egg_info_for_url(url)
-        if name:
-            while '..' in name:
-                name = name.replace('..', '.').replace('\\', '_')
-        else:
-            name = "__downloaded__"  # default if URL has no path contents
-
-        if name.endswith('.egg.zip'):
-            name = name[:-4]  # strip the extra .zip before download
-
-        filename = os.path.join(tmpdir, name)
-
-        # ensure path resolves within the tmpdir
-        if not filename.startswith(str(tmpdir)):
-            raise ValueError(f"Invalid filename {filename}")
-
-        return self._download_vcs(url, filename) or self._download_other(url, filename)
-
-    @staticmethod
-    def _resolve_vcs(url):
-        """
-        >>> rvcs = PackageIndex._resolve_vcs
-        >>> rvcs('git+http://foo/bar')
-        'git'
-        >>> rvcs('hg+https://foo/bar')
-        'hg'
-        >>> rvcs('git:myhost')
-        'git'
-        >>> rvcs('hg:myhost')
-        >>> rvcs('http://foo/bar')
-        """
-        scheme = urllib.parse.urlsplit(url).scheme
-        pre, sep, post = scheme.partition('+')
-        # svn and git have their own protocol; hg does not
-        allowed = set(['svn', 'git'] + ['hg'] * bool(sep))
-        return next(iter({pre} & allowed), None)
-
-
-    def _download_vcs(self, url, spec_filename):
-        vcs = self._resolve_vcs(url)
-        if not vcs:
-            return
-        if vcs == 'svn':
-            return self._download_svn(url, spec_filename)
-
-        filename, _, _ = spec_filename.partition('#')
-        url, rev = self._vcs_split_rev_from_url(url)
-
-        self.info(f"Doing {vcs} clone from {url} to {filename}")
-        subprocess.check_call([vcs, 'clone', '--quiet', url, filename])
-
-        co_commands = dict(
-            git=[vcs, '-C', filename, 'checkout', '--quiet', rev],
-            hg=[vcs, '--cwd', filename, 'up', '-C', '-r', rev, '-q'],
-        )
-        if rev is not None:
-            self.info(f"Checking out {rev}")
-            subprocess.check_call(co_commands[vcs])
-
-        return filename
-
-    def _download_other(self, url, filename):
-        scheme = urllib.parse.urlsplit(url).scheme
-        if scheme == 'file':  # pragma: no cover
-            return urllib.request.url2pathname(urllib.parse.urlparse(url).path)
-        # raise error if not allowed
-        self.url_ok(url, True)
-        return self._attempt_download(url, filename)
-
-    def scan_url(self, url):
-        self.process_url(url, True)
-
-    def _attempt_download(self, url, filename):
-        headers = self._download_to(url, filename)
-        if 'html' in headers.get('content-type', '').lower():
-            return self._download_html(url, headers, filename)
-        else:
-            return filename
-
-    def _download_html(self, url, headers, filename):
-        file = open(filename)
-        for line in file:
-            if line.strip():
-                # Check for a subversion index page
-                if re.search(r'([^- ]+ - )?Revision \d+:', line):
-                    # it's a subversion index page:
-                    file.close()
-                    os.unlink(filename)
-                    return self._download_svn(url, filename)
-                break  # not an index page
-        file.close()
-        os.unlink(filename)
-        raise DistutilsError("Unexpected HTML page found at " + url)
-
-    def _download_svn(self, url, filename):
-        warnings.warn("SVN download support is deprecated", UserWarning)
-        url = url.split('#', 1)[0]  # remove any fragment for svn's sake
-        creds = ''
-        if url.lower().startswith('svn:') and '@' in url:
-            scheme, netloc, path, p, q, f = urllib.parse.urlparse(url)
-            if not netloc and path.startswith('//') and '/' in path[2:]:
-                netloc, path = path[2:].split('/', 1)
-                auth, host = _splituser(netloc)
-                if auth:
-                    if ':' in auth:
-                        user, pw = auth.split(':', 1)
-                        creds = " --username=%s --password=%s" % (user, pw)
-                    else:
-                        creds = " --username=" + auth
-                    netloc = host
-                    parts = scheme, netloc, url, p, q, f
-                    url = urllib.parse.urlunparse(parts)
-        self.info(f"Doing subversion checkout from {url} to {filename}")
-        subprocess.check_call(['svn', 'checkout', creds, '-q', url, filename])
-        return filename
-
-    @staticmethod
-    def _vcs_split_rev_from_url(url):
-        """
-        Given a possible VCS URL, return a clean URL and resolved revision if any.
-        >>> vsrfu = PackageIndex._vcs_split_rev_from_url
-        >>> vsrfu('git+https://github.com/pypa/setuptools@v69.0.0#egg-info=setuptools')
-        ('https://github.com/pypa/setuptools', 'v69.0.0')
-        >>> vsrfu('git+https://github.com/pypa/setuptools#egg-info=setuptools')
-        ('https://github.com/pypa/setuptools', None)
-        >>> vsrfu('http://foo/bar')
-        ('http://foo/bar', None)
-        """
-        parts = urllib.parse.urlsplit(url)
-
-        clean_scheme = parts.scheme.split('+', 1)[-1]
-
-        # Some fragment identification fails
-        no_fragment_path, _, _ = parts.path.partition('#')
-
-        pre, sep, post = no_fragment_path.rpartition('@')
-        clean_path, rev = (pre, post) if sep else (post, None)
-
-        resolved = parts._replace(
-            scheme=clean_scheme,
-            path=clean_path,
-            # discard the fragment
-            fragment='',
-        ).geturl()
-
-        return resolved, rev
-
-    def debug(self, msg, *args):
-        log.debug(msg, *args)
-
-    def info(self, msg, *args):
-        log.info(msg, *args)
-
-    def warn(self, msg, *args):
-        log.warn(msg, *args)
-
-
-# This pattern matches a character entity reference (a decimal numeric
-# references, a hexadecimal numeric reference, or a named reference).
-entity_sub = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub
-
-
-def decode_entity(match):
-    what = match.group(0)
-    return html.unescape(what)
-
-
-def htmldecode(text):
-    """
-    Decode HTML entities in the given text.
-
-    >>> htmldecode(
-    ...     'https://../package_name-0.1.2.tar.gz'
-    ...     '?tokena=A&tokenb=B">package_name-0.1.2.tar.gz')
-    'https://../package_name-0.1.2.tar.gz?tokena=A&tokenb=B">package_name-0.1.2.tar.gz'
-    """
-    return entity_sub(decode_entity, text)
-
-
-def socket_timeout(timeout=15):
-    def _socket_timeout(func):
-        def _socket_timeout(*args, **kwargs):
-            old_timeout = socket.getdefaulttimeout()
-            socket.setdefaulttimeout(timeout)
-            try:
-                return func(*args, **kwargs)
-            finally:
-                socket.setdefaulttimeout(old_timeout)
-
-        return _socket_timeout
-
-    return _socket_timeout
-
-
-def _encode_auth(auth):
-    """
-    Encode auth from a URL suitable for an HTTP header.
-    >>> str(_encode_auth('username%3Apassword'))
-    'dXNlcm5hbWU6cGFzc3dvcmQ='
-
-    Long auth strings should not cause a newline to be inserted.
-    >>> long_auth = 'username:' + 'password'*10
-    >>> chr(10) in str(_encode_auth(long_auth))
-    False
-    """
-    auth_s = urllib.parse.unquote(auth)
-    # convert to bytes
-    auth_bytes = auth_s.encode()
-    encoded_bytes = base64.b64encode(auth_bytes)
-    # convert back to a string
-    encoded = encoded_bytes.decode()
-    # strip the trailing carriage return
-    return encoded.replace('\n', '')
-
-
-class Credential:
-    """
-    A username/password pair. Use like a namedtuple.
-    """
-
-    def __init__(self, username, password):
-        self.username = username
-        self.password = password
-
-    def __iter__(self):
-        yield self.username
-        yield self.password
-
-    def __str__(self):
-        return '%(username)s:%(password)s' % vars(self)
-
-
-class PyPIConfig(configparser.RawConfigParser):
-    def __init__(self):
-        """
-        Load from ~/.pypirc
-        """
-        defaults = dict.fromkeys(['username', 'password', 'repository'], '')
-        super().__init__(defaults)
-
-        rc = os.path.join(os.path.expanduser('~'), '.pypirc')
-        if os.path.exists(rc):
-            self.read(rc)
-
-    @property
-    def creds_by_repository(self):
-        sections_with_repositories = [
-            section
-            for section in self.sections()
-            if self.get(section, 'repository').strip()
-        ]
-
-        return dict(map(self._get_repo_cred, sections_with_repositories))
-
-    def _get_repo_cred(self, section):
-        repo = self.get(section, 'repository').strip()
-        return repo, Credential(
-            self.get(section, 'username').strip(),
-            self.get(section, 'password').strip(),
-        )
-
-    def find_credential(self, url):
-        """
-        If the URL indicated appears to be a repository defined in this
-        config, return the credential for that repository.
-        """
-        for repository, cred in self.creds_by_repository.items():
-            if url.startswith(repository):
-                return cred
-
-
-def open_with_auth(url, opener=urllib.request.urlopen):
-    """Open a urllib2 request, handling HTTP authentication"""
-
-    parsed = urllib.parse.urlparse(url)
-    scheme, netloc, path, params, query, frag = parsed
-
-    # Double scheme does not raise on macOS as revealed by a
-    # failing test. We would expect "nonnumeric port". Refs #20.
-    if netloc.endswith(':'):
-        raise http.client.InvalidURL("nonnumeric port: ''")
-
-    if scheme in ('http', 'https'):
-        auth, address = _splituser(netloc)
-    else:
-        auth = None
-
-    if not auth:
-        cred = PyPIConfig().find_credential(url)
-        if cred:
-            auth = str(cred)
-            info = cred.username, url
-            log.info('Authenticating as %s for %s (from .pypirc)', *info)
-
-    if auth:
-        auth = "Basic " + _encode_auth(auth)
-        parts = scheme, address, path, params, query, frag
-        new_url = urllib.parse.urlunparse(parts)
-        request = urllib.request.Request(new_url)
-        request.add_header("Authorization", auth)
-    else:
-        request = urllib.request.Request(url)
-
-    request.add_header('User-Agent', user_agent)
-    fp = opener(request)
-
-    if auth:
-        # Put authentication info back into request URL if same host,
-        # so that links found on the page will work
-        s2, h2, path2, param2, query2, frag2 = urllib.parse.urlparse(fp.url)
-        if s2 == scheme and h2 == address:
-            parts = s2, netloc, path2, param2, query2, frag2
-            fp.url = urllib.parse.urlunparse(parts)
-
-    return fp
-
-
-# copy of urllib.parse._splituser from Python 3.8
-def _splituser(host):
-    """splituser('user[:passwd]@host[:port]')
-    --> 'user[:passwd]', 'host[:port]'."""
-    user, delim, host = host.rpartition('@')
-    return (user if delim else None), host
-
-
-# adding a timeout to avoid freezing package_index
-open_with_auth = socket_timeout(_SOCKET_TIMEOUT)(open_with_auth)
-
-
-def fix_sf_url(url):
-    return url  # backward compatibility
-
-
-def local_open(url):
-    """Read a local path, with special support for directories"""
-    scheme, server, path, param, query, frag = urllib.parse.urlparse(url)
-    filename = urllib.request.url2pathname(path)
-    if os.path.isfile(filename):
-        return urllib.request.urlopen(url)
-    elif path.endswith('/') and os.path.isdir(filename):
-        files = []
-        for f in os.listdir(filename):
-            filepath = os.path.join(filename, f)
-            if f == 'index.html':
-                with open(filepath, 'r') as fp:
-                    body = fp.read()
-                break
-            elif os.path.isdir(filepath):
-                f += '/'
-            files.append('<a href="{name}">{name}</a>'.format(name=f))
-        else:
-            tmpl = (
-                "<html><head><title>{url}" "{files}"
-            )
-            body = tmpl.format(url=url, files='\n'.join(files))
-        status, message = 200, "OK"
-    else:
-        status, message, body = 404, "Path not found", "Not found"
-
-    headers = {'content-type': 'text/html'}
-    body_stream = io.StringIO(body)
-    return urllib.error.HTTPError(url, status, message, headers, body_stream)
diff --git a/venv/lib/python3.11/site-packages/setuptools/py34compat.py b/venv/lib/python3.11/site-packages/setuptools/py34compat.py
deleted file mode 100755
index 3ad9172..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/py34compat.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import importlib
-
-try:
-    import importlib.util
-except ImportError:
-    pass
-
-
-try:
-    module_from_spec = importlib.util.module_from_spec
-except AttributeError:
-    def module_from_spec(spec):
-        return spec.loader.load_module(spec.name)
diff --git a/venv/lib/python3.11/site-packages/setuptools/sandbox.py b/venv/lib/python3.11/site-packages/setuptools/sandbox.py
deleted file mode 100755
index 034fc80..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/sandbox.py
+++ /dev/null
@@ -1,530 +0,0 @@
-import os
-import sys
-import tempfile
-import operator
-import functools
-import itertools
-import re
-import contextlib
-import pickle
-import textwrap
-import builtins
-
-import pkg_resources
-from distutils.errors import DistutilsError
-from pkg_resources import working_set
-
-if sys.platform.startswith('java'):
-    import org.python.modules.posix.PosixModule as _os
-else:
-    _os = sys.modules[os.name]
-try:
-    _file = file
-except NameError:
-    _file = None
-_open = open
-
-
-__all__ = [
-    "AbstractSandbox",
-    "DirectorySandbox",
-    "SandboxViolation",
-    "run_setup",
-]
-
-
-def _execfile(filename, globals, locals=None):
-    """
-    Python 3 implementation of execfile.
-    """
-    mode = 'rb'
-    with open(filename, mode) as stream:
-        script = stream.read()
-    if locals is None:
-        locals = globals
-    code = compile(script, filename, 'exec')
-    exec(code, globals, locals)
-
-
-@contextlib.contextmanager
-def save_argv(repl=None):
-    saved = sys.argv[:]
-    if repl is not None:
-        sys.argv[:] = repl
-    try:
-        yield saved
-    finally:
-        sys.argv[:] = saved
-
-
-@contextlib.contextmanager
-def save_path():
-    saved = sys.path[:]
-    try:
-        yield saved
-    finally:
-        sys.path[:] = saved
-
-
-@contextlib.contextmanager
-def override_temp(replacement):
-    """
-    Monkey-patch tempfile.tempdir with replacement, ensuring it exists
-    """
-    os.makedirs(replacement, exist_ok=True)
-
-    saved = tempfile.tempdir
-
-    tempfile.tempdir = replacement
-
-    try:
-        yield
-    finally:
-        tempfile.tempdir = saved
-
-
-@contextlib.contextmanager
-def pushd(target):
-    saved = os.getcwd()
-    os.chdir(target)
-    try:
-        yield saved
-    finally:
-        os.chdir(saved)
-
-
-class UnpickleableException(Exception):
-    """
-    An exception representing another Exception that could not be pickled.
-    """
-
-    @staticmethod
-    def dump(type, exc):
-        """
-        Always return a dumped (pickled) type and exc. If exc can't be pickled,
-        wrap it in UnpickleableException first.
-        """
-        try:
-            return pickle.dumps(type), pickle.dumps(exc)
-        except Exception:
-            # get UnpickleableException inside the sandbox
-            from setuptools.sandbox import UnpickleableException as cls
-
-            return cls.dump(cls, cls(repr(exc)))
-
-
-class ExceptionSaver:
-    """
-    A Context Manager that will save an exception, serialized, and restore it
-    later.
-    """
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, type, exc, tb):
-        if not exc:
-            return
-
-        # dump the exception
-        self._saved = UnpickleableException.dump(type, exc)
-        self._tb = tb
-
-        # suppress the exception
-        return True
-
-    def resume(self):
-        "restore and re-raise any exception"
-
-        if '_saved' not in vars(self):
-            return
-
-        type, exc = map(pickle.loads, self._saved)
-        raise exc.with_traceback(self._tb)
-
-
-@contextlib.contextmanager
-def save_modules():
-    """
-    Context in which imported modules are saved.
-
-    Translates exceptions internal to the context into the equivalent exception
-    outside the context.
-    """
-    saved = sys.modules.copy()
-    with ExceptionSaver() as saved_exc:
-        yield saved
-
-    sys.modules.update(saved)
-    # remove any modules imported since
-    del_modules = (
-        mod_name
-        for mod_name in sys.modules
-        if mod_name not in saved
-        # exclude any encodings modules. See #285
-        and not mod_name.startswith('encodings.')
-    )
-    _clear_modules(del_modules)
-
-    saved_exc.resume()
-
-
-def _clear_modules(module_names):
-    for mod_name in list(module_names):
-        del sys.modules[mod_name]
-
-
-@contextlib.contextmanager
-def save_pkg_resources_state():
-    saved = pkg_resources.__getstate__()
-    try:
-        yield saved
-    finally:
-        pkg_resources.__setstate__(saved)
-
-
-@contextlib.contextmanager
-def setup_context(setup_dir):
-    temp_dir = os.path.join(setup_dir, 'temp')
-    with save_pkg_resources_state():
-        with save_modules():
-            with save_path():
-                hide_setuptools()
-                with save_argv():
-                    with override_temp(temp_dir):
-                        with pushd(setup_dir):
-                            # ensure setuptools commands are available
-                            __import__('setuptools')
-                            yield
-
-
-_MODULES_TO_HIDE = {
-    'setuptools',
-    'distutils',
-    'pkg_resources',
-    'Cython',
-    '_distutils_hack',
-}
-
-
-def _needs_hiding(mod_name):
-    """
-    >>> _needs_hiding('setuptools')
-    True
-    >>> _needs_hiding('pkg_resources')
-    True
-    >>> _needs_hiding('setuptools_plugin')
-    False
-    >>> _needs_hiding('setuptools.__init__')
-    True
-    >>> _needs_hiding('distutils')
-    True
-    >>> _needs_hiding('os')
-    False
-    >>> _needs_hiding('Cython')
-    True
-    """
-    base_module = mod_name.split('.', 1)[0]
-    return base_module in _MODULES_TO_HIDE
-
-
-def hide_setuptools():
-    """
-    Remove references to setuptools' modules from sys.modules to allow the
-    invocation to import the most appropriate setuptools. This technique is
-    necessary to avoid issues such as #315 where setuptools upgrading itself
-    would fail to find a function declared in the metadata.
-    """
-    _distutils_hack = sys.modules.get('_distutils_hack', None)
-    if _distutils_hack is not None:
-        _distutils_hack.remove_shim()
-
-    modules = filter(_needs_hiding, sys.modules)
-    _clear_modules(modules)
-
-
-def run_setup(setup_script, args):
-    """Run a distutils setup script, sandboxed in its directory"""
-    setup_dir = os.path.abspath(os.path.dirname(setup_script))
-    with setup_context(setup_dir):
-        try:
-            sys.argv[:] = [setup_script] + list(args)
-            sys.path.insert(0, setup_dir)
-            # reset to include setup dir, w/clean callback list
-            working_set.__init__()
-            working_set.callbacks.append(lambda dist: dist.activate())
-
-            with DirectorySandbox(setup_dir):
-                ns = dict(__file__=setup_script, __name__='__main__')
-                _execfile(setup_script, ns)
-        except SystemExit as v:
-            if v.args and v.args[0]:
-                raise
-            # Normal exit, just return
-
-
-class AbstractSandbox:
-    """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts"""
-
-    _active = False
-
-    def __init__(self):
-        self._attrs = [
-            name
-            for name in dir(_os)
-            if not name.startswith('_') and hasattr(self, name)
-        ]
-
-    def _copy(self, source):
-        for name in self._attrs:
-            setattr(os, name, getattr(source, name))
-
-    def __enter__(self):
-        self._copy(self)
-        if _file:
-            builtins.file = self._file
-        builtins.open = self._open
-        self._active = True
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        self._active = False
-        if _file:
-            builtins.file = _file
-        builtins.open = _open
-        self._copy(_os)
-
-    def run(self, func):
-        """Run 'func' under os sandboxing"""
-        with self:
-            return func()
-
-    def _mk_dual_path_wrapper(name):
-        original = getattr(_os, name)
-
-        def wrap(self, src, dst, *args, **kw):
-            if self._active:
-                src, dst = self._remap_pair(name, src, dst, *args, **kw)
-            return original(src, dst, *args, **kw)
-
-        return wrap
-
-    for name in ["rename", "link", "symlink"]:
-        if hasattr(_os, name):
-            locals()[name] = _mk_dual_path_wrapper(name)
-
-    def _mk_single_path_wrapper(name, original=None):
-        original = original or getattr(_os, name)
-
-        def wrap(self, path, *args, **kw):
-            if self._active:
-                path = self._remap_input(name, path, *args, **kw)
-            return original(path, *args, **kw)
-
-        return wrap
-
-    if _file:
-        _file = _mk_single_path_wrapper('file', _file)
-    _open = _mk_single_path_wrapper('open', _open)
-    for name in [
-        "stat",
-        "listdir",
-        "chdir",
-        "open",
-        "chmod",
-        "chown",
-        "mkdir",
-        "remove",
-        "unlink",
-        "rmdir",
-        "utime",
-        "lchown",
-        "chroot",
-        "lstat",
-        "startfile",
-        "mkfifo",
-        "mknod",
-        "pathconf",
-        "access",
-    ]:
-        if hasattr(_os, name):
-            locals()[name] = _mk_single_path_wrapper(name)
-
-    def _mk_single_with_return(name):
-        original = getattr(_os, name)
-
-        def wrap(self, path, *args, **kw):
-            if self._active:
-                path = self._remap_input(name, path, *args, **kw)
-                return self._remap_output(name, original(path, *args, **kw))
-            return original(path, *args, **kw)
-
-        return wrap
-
-    for name in ['readlink', 'tempnam']:
-        if hasattr(_os, name):
-            locals()[name] = _mk_single_with_return(name)
-
-    def _mk_query(name):
-        original = getattr(_os, name)
-
-        def wrap(self, *args, **kw):
-            retval = original(*args, **kw)
-            if self._active:
-                return self._remap_output(name, retval)
-            return retval
-
-        return wrap
-
-    for name in ['getcwd', 'tmpnam']:
-        if hasattr(_os, name):
-            locals()[name] = _mk_query(name)
-
-    def _validate_path(self, path):
-        """Called to remap or validate any path, whether input or output"""
-        return path
-
-    def _remap_input(self, operation, path, *args, **kw):
-        """Called for path inputs"""
-        return self._validate_path(path)
-
-    def _remap_output(self, operation, path):
-        """Called for path outputs"""
-        return self._validate_path(path)
-
-    def _remap_pair(self, operation, src, dst, *args, **kw):
-        """Called for path pairs like rename, link, and symlink operations"""
-        return (
-            self._remap_input(operation + '-from', src, *args, **kw),
-            self._remap_input(operation + '-to', dst, *args, **kw),
-        )
-
-
-if hasattr(os, 'devnull'):
-    _EXCEPTIONS = [os.devnull]
-else:
-    _EXCEPTIONS = []
-
-
-class DirectorySandbox(AbstractSandbox):
-    """Restrict operations to a single subdirectory - pseudo-chroot"""
-
-    write_ops = dict.fromkeys(
-        [
-            "open",
-            "chmod",
-            "chown",
-            "mkdir",
-            "remove",
-            "unlink",
-            "rmdir",
-            "utime",
-            "lchown",
-            "chroot",
-            "mkfifo",
-            "mknod",
-            "tempnam",
-        ]
-    )
-
-    _exception_patterns = []
-    "exempt writing to paths that match the pattern"
-
-    def __init__(self, sandbox, exceptions=_EXCEPTIONS):
-        self._sandbox = os.path.normcase(os.path.realpath(sandbox))
-        self._prefix = os.path.join(self._sandbox, '')
-        self._exceptions = [
-            os.path.normcase(os.path.realpath(path)) for path in exceptions
-        ]
-        AbstractSandbox.__init__(self)
-
-    def _violation(self, operation, *args, **kw):
-        from setuptools.sandbox import SandboxViolation
-
-        raise SandboxViolation(operation, args, kw)
-
-    if _file:
-
-        def _file(self, path, mode='r', *args, **kw):
-            if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
-                self._violation("file", path, mode, *args, **kw)
-            return _file(path, mode, *args, **kw)
-
-    def _open(self, path, mode='r', *args, **kw):
-        if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
-            self._violation("open", path, mode, *args, **kw)
-        return _open(path, mode, *args, **kw)
-
-    def tmpnam(self):
-        self._violation("tmpnam")
-
-    def _ok(self, path):
-        active = self._active
-        try:
-            self._active = False
-            realpath = os.path.normcase(os.path.realpath(path))
-            return (
-                self._exempted(realpath)
-                or realpath == self._sandbox
-                or realpath.startswith(self._prefix)
-            )
-        finally:
-            self._active = active
-
-    def _exempted(self, filepath):
-        start_matches = (
-            filepath.startswith(exception) for exception in self._exceptions
-        )
-        pattern_matches = (
-            re.match(pattern, filepath) for pattern in self._exception_patterns
-        )
-        candidates = itertools.chain(start_matches, pattern_matches)
-        return any(candidates)
-
-    def _remap_input(self, operation, path, *args, **kw):
-        """Called for path inputs"""
-        if operation in self.write_ops and not self._ok(path):
-            self._violation(operation, os.path.realpath(path), *args, **kw)
-        return path
-
-    def _remap_pair(self, operation, src, dst, *args, **kw):
-        """Called for path pairs like rename, link, and symlink operations"""
-        if not self._ok(src) or not self._ok(dst):
-            self._violation(operation, src, dst, *args, **kw)
-        return (src, dst)
-
-    def open(self, file, flags, mode=0o777, *args, **kw):
-        """Called for low-level os.open()"""
-        if flags & WRITE_FLAGS and not self._ok(file):
-            self._violation("os.open", file, flags, mode, *args, **kw)
-        return _os.open(file, flags, mode, *args, **kw)
-
-
-WRITE_FLAGS = functools.reduce(
-    operator.or_,
-    [
-        getattr(_os, a, 0)
-        for a in "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()
-    ],
-)
-
-
-class SandboxViolation(DistutilsError):
-    """A setup script attempted to modify the filesystem outside the sandbox"""
-
-    tmpl = textwrap.dedent(
-        """
-        SandboxViolation: {cmd}{args!r} {kwargs}
-
-        The package setup script has attempted to modify files on your system
-        that are not within the EasyInstall build area, and has been aborted.
-
-        This package cannot be safely installed by EasyInstall, and may not
-        support alternate installation locations even if you run its setup
-        script by hand.  Please inform the package's author and the EasyInstall
-        maintainers to find out if a fix or workaround is available.
-        """
-    ).lstrip()
-
-    def __str__(self):
-        cmd, args, kwargs = self.args
-        return self.tmpl.format(**locals())
diff --git a/venv/lib/python3.11/site-packages/setuptools/script (dev).tmpl b/venv/lib/python3.11/site-packages/setuptools/script (dev).tmpl
deleted file mode 100755
index 39a24b0..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/script (dev).tmpl	
+++ /dev/null
@@ -1,6 +0,0 @@
-# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
-__requires__ = %(spec)r
-__import__('pkg_resources').require(%(spec)r)
-__file__ = %(dev_path)r
-with open(__file__) as f:
-    exec(compile(f.read(), __file__, 'exec'))
diff --git a/venv/lib/python3.11/site-packages/setuptools/script.tmpl b/venv/lib/python3.11/site-packages/setuptools/script.tmpl
deleted file mode 100755
index ff5efbc..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/script.tmpl
+++ /dev/null
@@ -1,3 +0,0 @@
-# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
-__requires__ = %(spec)r
-__import__('pkg_resources').run_script(%(spec)r, %(script_name)r)
diff --git a/venv/lib/python3.11/site-packages/setuptools/unicode_utils.py b/venv/lib/python3.11/site-packages/setuptools/unicode_utils.py
deleted file mode 100755
index e84e65e..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/unicode_utils.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import unicodedata
-import sys
-
-
-# HFS Plus uses decomposed UTF-8
-def decompose(path):
-    if isinstance(path, str):
-        return unicodedata.normalize('NFD', path)
-    try:
-        path = path.decode('utf-8')
-        path = unicodedata.normalize('NFD', path)
-        path = path.encode('utf-8')
-    except UnicodeError:
-        pass  # Not UTF-8
-    return path
-
-
-def filesys_decode(path):
-    """
-    Ensure that the given path is decoded,
-    NONE when no expected encoding works
-    """
-
-    if isinstance(path, str):
-        return path
-
-    fs_enc = sys.getfilesystemencoding() or 'utf-8'
-    candidates = fs_enc, 'utf-8'
-
-    for enc in candidates:
-        try:
-            return path.decode(enc)
-        except UnicodeDecodeError:
-            continue
-
-
-def try_encode(string, enc):
-    "turn unicode encoding into a functional routine"
-    try:
-        return string.encode(enc)
-    except UnicodeEncodeError:
-        return None
diff --git a/venv/lib/python3.11/site-packages/setuptools/version.py b/venv/lib/python3.11/site-packages/setuptools/version.py
deleted file mode 100755
index 95e1869..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/version.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import pkg_resources
-
-try:
-    __version__ = pkg_resources.get_distribution('setuptools').version
-except Exception:
-    __version__ = 'unknown'
diff --git a/venv/lib/python3.11/site-packages/setuptools/wheel.py b/venv/lib/python3.11/site-packages/setuptools/wheel.py
deleted file mode 100755
index 527ed3b..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/wheel.py
+++ /dev/null
@@ -1,222 +0,0 @@
-"""Wheels support."""
-
-import email
-import itertools
-import os
-import posixpath
-import re
-import zipfile
-import contextlib
-
-from distutils.util import get_platform
-
-import pkg_resources
-import setuptools
-from pkg_resources import parse_version
-from setuptools.extern.packaging.tags import sys_tags
-from setuptools.extern.packaging.utils import canonicalize_name
-from setuptools.command.egg_info import write_requirements
-from setuptools.archive_util import _unpack_zipfile_obj
-
-
-WHEEL_NAME = re.compile(
-    r"""^(?P.+?)-(?P\d.*?)
-    ((-(?P\d.*?))?-(?P.+?)-(?P.+?)-(?P.+?)
-    )\.whl$""",
-    re.VERBOSE).match
-
-NAMESPACE_PACKAGE_INIT = \
-    "__import__('pkg_resources').declare_namespace(__name__)\n"
-
-
-def unpack(src_dir, dst_dir):
-    '''Move everything under `src_dir` to `dst_dir`, and delete the former.'''
-    for dirpath, dirnames, filenames in os.walk(src_dir):
-        subdir = os.path.relpath(dirpath, src_dir)
-        for f in filenames:
-            src = os.path.join(dirpath, f)
-            dst = os.path.join(dst_dir, subdir, f)
-            os.renames(src, dst)
-        for n, d in reversed(list(enumerate(dirnames))):
-            src = os.path.join(dirpath, d)
-            dst = os.path.join(dst_dir, subdir, d)
-            if not os.path.exists(dst):
-                # Directory does not exist in destination,
-                # rename it and prune it from os.walk list.
-                os.renames(src, dst)
-                del dirnames[n]
-    # Cleanup.
-    for dirpath, dirnames, filenames in os.walk(src_dir, topdown=True):
-        assert not filenames
-        os.rmdir(dirpath)
-
-
-@contextlib.contextmanager
-def disable_info_traces():
-    """
-    Temporarily disable info traces.
-    """
-    from distutils import log
-    saved = log.set_threshold(log.WARN)
-    try:
-        yield
-    finally:
-        log.set_threshold(saved)
-
-
-class Wheel:
-
-    def __init__(self, filename):
-        match = WHEEL_NAME(os.path.basename(filename))
-        if match is None:
-            raise ValueError('invalid wheel name: %r' % filename)
-        self.filename = filename
-        for k, v in match.groupdict().items():
-            setattr(self, k, v)
-
-    def tags(self):
-        '''List tags (py_version, abi, platform) supported by this wheel.'''
-        return itertools.product(
-            self.py_version.split('.'),
-            self.abi.split('.'),
-            self.platform.split('.'),
-        )
-
-    def is_compatible(self):
-        '''Is the wheel is compatible with the current platform?'''
-        supported_tags = set(
-            (t.interpreter, t.abi, t.platform) for t in sys_tags())
-        return next((True for t in self.tags() if t in supported_tags), False)
-
-    def egg_name(self):
-        return pkg_resources.Distribution(
-            project_name=self.project_name, version=self.version,
-            platform=(None if self.platform == 'any' else get_platform()),
-        ).egg_name() + '.egg'
-
-    def get_dist_info(self, zf):
-        # find the correct name of the .dist-info dir in the wheel file
-        for member in zf.namelist():
-            dirname = posixpath.dirname(member)
-            if (dirname.endswith('.dist-info') and
-                    canonicalize_name(dirname).startswith(
-                        canonicalize_name(self.project_name))):
-                return dirname
-        raise ValueError("unsupported wheel format. .dist-info not found")
-
-    def install_as_egg(self, destination_eggdir):
-        '''Install wheel as an egg directory.'''
-        with zipfile.ZipFile(self.filename) as zf:
-            self._install_as_egg(destination_eggdir, zf)
-
-    def _install_as_egg(self, destination_eggdir, zf):
-        dist_basename = '%s-%s' % (self.project_name, self.version)
-        dist_info = self.get_dist_info(zf)
-        dist_data = '%s.data' % dist_basename
-        egg_info = os.path.join(destination_eggdir, 'EGG-INFO')
-
-        self._convert_metadata(zf, destination_eggdir, dist_info, egg_info)
-        self._move_data_entries(destination_eggdir, dist_data)
-        self._fix_namespace_packages(egg_info, destination_eggdir)
-
-    @staticmethod
-    def _convert_metadata(zf, destination_eggdir, dist_info, egg_info):
-        def get_metadata(name):
-            with zf.open(posixpath.join(dist_info, name)) as fp:
-                value = fp.read().decode('utf-8')
-                return email.parser.Parser().parsestr(value)
-
-        wheel_metadata = get_metadata('WHEEL')
-        # Check wheel format version is supported.
-        wheel_version = parse_version(wheel_metadata.get('Wheel-Version'))
-        wheel_v1 = (
-            parse_version('1.0') <= wheel_version < parse_version('2.0dev0')
-        )
-        if not wheel_v1:
-            raise ValueError(
-                'unsupported wheel format version: %s' % wheel_version)
-        # Extract to target directory.
-        _unpack_zipfile_obj(zf, destination_eggdir)
-        # Convert metadata.
-        dist_info = os.path.join(destination_eggdir, dist_info)
-        dist = pkg_resources.Distribution.from_location(
-            destination_eggdir, dist_info,
-            metadata=pkg_resources.PathMetadata(destination_eggdir, dist_info),
-        )
-
-        # Note: Evaluate and strip markers now,
-        # as it's difficult to convert back from the syntax:
-        # foobar; "linux" in sys_platform and extra == 'test'
-        def raw_req(req):
-            req.marker = None
-            return str(req)
-        install_requires = list(map(raw_req, dist.requires()))
-        extras_require = {
-            extra: [
-                req
-                for req in map(raw_req, dist.requires((extra,)))
-                if req not in install_requires
-            ]
-            for extra in dist.extras
-        }
-        os.rename(dist_info, egg_info)
-        os.rename(
-            os.path.join(egg_info, 'METADATA'),
-            os.path.join(egg_info, 'PKG-INFO'),
-        )
-        setup_dist = setuptools.Distribution(
-            attrs=dict(
-                install_requires=install_requires,
-                extras_require=extras_require,
-            ),
-        )
-        with disable_info_traces():
-            write_requirements(
-                setup_dist.get_command_obj('egg_info'),
-                None,
-                os.path.join(egg_info, 'requires.txt'),
-            )
-
-    @staticmethod
-    def _move_data_entries(destination_eggdir, dist_data):
-        """Move data entries to their correct location."""
-        dist_data = os.path.join(destination_eggdir, dist_data)
-        dist_data_scripts = os.path.join(dist_data, 'scripts')
-        if os.path.exists(dist_data_scripts):
-            egg_info_scripts = os.path.join(
-                destination_eggdir, 'EGG-INFO', 'scripts')
-            os.mkdir(egg_info_scripts)
-            for entry in os.listdir(dist_data_scripts):
-                # Remove bytecode, as it's not properly handled
-                # during easy_install scripts install phase.
-                if entry.endswith('.pyc'):
-                    os.unlink(os.path.join(dist_data_scripts, entry))
-                else:
-                    os.rename(
-                        os.path.join(dist_data_scripts, entry),
-                        os.path.join(egg_info_scripts, entry),
-                    )
-            os.rmdir(dist_data_scripts)
-        for subdir in filter(os.path.exists, (
-            os.path.join(dist_data, d)
-            for d in ('data', 'headers', 'purelib', 'platlib')
-        )):
-            unpack(subdir, destination_eggdir)
-        if os.path.exists(dist_data):
-            os.rmdir(dist_data)
-
-    @staticmethod
-    def _fix_namespace_packages(egg_info, destination_eggdir):
-        namespace_packages = os.path.join(
-            egg_info, 'namespace_packages.txt')
-        if os.path.exists(namespace_packages):
-            with open(namespace_packages) as fp:
-                namespace_packages = fp.read().split()
-            for mod in namespace_packages:
-                mod_dir = os.path.join(destination_eggdir, *mod.split('.'))
-                mod_init = os.path.join(mod_dir, '__init__.py')
-                if not os.path.exists(mod_dir):
-                    os.mkdir(mod_dir)
-                if not os.path.exists(mod_init):
-                    with open(mod_init, 'w') as fp:
-                        fp.write(NAMESPACE_PACKAGE_INIT)
diff --git a/venv/lib/python3.11/site-packages/setuptools/windows_support.py b/venv/lib/python3.11/site-packages/setuptools/windows_support.py
deleted file mode 100755
index 1ca64fb..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/windows_support.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import platform
-
-
-def windows_only(func):
-    if platform.system() != 'Windows':
-        return lambda *args, **kwargs: None
-    return func
-
-
-@windows_only
-def hide_file(path):
-    """
-    Set the hidden attribute on a file or directory.
-
-    From http://stackoverflow.com/questions/19622133/
-
-    `path` must be text.
-    """
-    import ctypes
-    __import__('ctypes.wintypes')
-    SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW
-    SetFileAttributes.argtypes = ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD
-    SetFileAttributes.restype = ctypes.wintypes.BOOL
-
-    FILE_ATTRIBUTE_HIDDEN = 0x02
-
-    ret = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN)
-    if not ret:
-        raise ctypes.WinError()
diff --git a/venv/lib/python3.11/site-packages/telegram/__init__.py b/venv/lib/python3.11/site-packages/telegram/__init__.py
deleted file mode 100755
index a895e60..0000000
--- a/venv/lib/python3.11/site-packages/telegram/__init__.py
+++ /dev/null
@@ -1,544 +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/].
-"""A library that provides a Python interface to the Telegram Bot API"""
-
-__author__ = "devs@python-telegram-bot.org"
-__all__ = (
-    "AffiliateInfo",
-    "Animation",
-    "Audio",
-    "BackgroundFill",
-    "BackgroundFillFreeformGradient",
-    "BackgroundFillGradient",
-    "BackgroundFillSolid",
-    "BackgroundType",
-    "BackgroundTypeChatTheme",
-    "BackgroundTypeFill",
-    "BackgroundTypePattern",
-    "BackgroundTypeWallpaper",
-    "Birthdate",
-    "Bot",
-    "BotCommand",
-    "BotCommandScope",
-    "BotCommandScopeAllChatAdministrators",
-    "BotCommandScopeAllGroupChats",
-    "BotCommandScopeAllPrivateChats",
-    "BotCommandScopeChat",
-    "BotCommandScopeChatAdministrators",
-    "BotCommandScopeChatMember",
-    "BotCommandScopeDefault",
-    "BotDescription",
-    "BotName",
-    "BotShortDescription",
-    "BusinessConnection",
-    "BusinessIntro",
-    "BusinessLocation",
-    "BusinessMessagesDeleted",
-    "BusinessOpeningHours",
-    "BusinessOpeningHoursInterval",
-    "CallbackGame",
-    "CallbackQuery",
-    "Chat",
-    "ChatAdministratorRights",
-    "ChatBackground",
-    "ChatBoost",
-    "ChatBoostAdded",
-    "ChatBoostRemoved",
-    "ChatBoostSource",
-    "ChatBoostSourceGiftCode",
-    "ChatBoostSourceGiveaway",
-    "ChatBoostSourcePremium",
-    "ChatBoostUpdated",
-    "ChatFullInfo",
-    "ChatInviteLink",
-    "ChatJoinRequest",
-    "ChatLocation",
-    "ChatMember",
-    "ChatMemberAdministrator",
-    "ChatMemberBanned",
-    "ChatMemberLeft",
-    "ChatMemberMember",
-    "ChatMemberOwner",
-    "ChatMemberRestricted",
-    "ChatMemberUpdated",
-    "ChatPermissions",
-    "ChatPhoto",
-    "ChatShared",
-    "ChosenInlineResult",
-    "Contact",
-    "CopyTextButton",
-    "Credentials",
-    "DataCredentials",
-    "Dice",
-    "Document",
-    "EncryptedCredentials",
-    "EncryptedPassportElement",
-    "ExternalReplyInfo",
-    "File",
-    "FileCredentials",
-    "ForceReply",
-    "ForumTopic",
-    "ForumTopicClosed",
-    "ForumTopicCreated",
-    "ForumTopicEdited",
-    "ForumTopicReopened",
-    "Game",
-    "GameHighScore",
-    "GeneralForumTopicHidden",
-    "GeneralForumTopicUnhidden",
-    "Gift",
-    "Gifts",
-    "Giveaway",
-    "GiveawayCompleted",
-    "GiveawayCreated",
-    "GiveawayWinners",
-    "IdDocumentData",
-    "InaccessibleMessage",
-    "InlineKeyboardButton",
-    "InlineKeyboardMarkup",
-    "InlineQuery",
-    "InlineQueryResult",
-    "InlineQueryResultArticle",
-    "InlineQueryResultAudio",
-    "InlineQueryResultCachedAudio",
-    "InlineQueryResultCachedDocument",
-    "InlineQueryResultCachedGif",
-    "InlineQueryResultCachedMpeg4Gif",
-    "InlineQueryResultCachedPhoto",
-    "InlineQueryResultCachedSticker",
-    "InlineQueryResultCachedVideo",
-    "InlineQueryResultCachedVoice",
-    "InlineQueryResultContact",
-    "InlineQueryResultDocument",
-    "InlineQueryResultGame",
-    "InlineQueryResultGif",
-    "InlineQueryResultLocation",
-    "InlineQueryResultMpeg4Gif",
-    "InlineQueryResultPhoto",
-    "InlineQueryResultVenue",
-    "InlineQueryResultVideo",
-    "InlineQueryResultVoice",
-    "InlineQueryResultsButton",
-    "InputContactMessageContent",
-    "InputFile",
-    "InputInvoiceMessageContent",
-    "InputLocationMessageContent",
-    "InputMedia",
-    "InputMediaAnimation",
-    "InputMediaAudio",
-    "InputMediaDocument",
-    "InputMediaPhoto",
-    "InputMediaVideo",
-    "InputMessageContent",
-    "InputPaidMedia",
-    "InputPaidMediaPhoto",
-    "InputPaidMediaVideo",
-    "InputPollOption",
-    "InputSticker",
-    "InputTextMessageContent",
-    "InputVenueMessageContent",
-    "Invoice",
-    "KeyboardButton",
-    "KeyboardButtonPollType",
-    "KeyboardButtonRequestChat",
-    "KeyboardButtonRequestUsers",
-    "LabeledPrice",
-    "LinkPreviewOptions",
-    "Location",
-    "LoginUrl",
-    "MaskPosition",
-    "MaybeInaccessibleMessage",
-    "MenuButton",
-    "MenuButtonCommands",
-    "MenuButtonDefault",
-    "MenuButtonWebApp",
-    "Message",
-    "MessageAutoDeleteTimerChanged",
-    "MessageEntity",
-    "MessageId",
-    "MessageOrigin",
-    "MessageOriginChannel",
-    "MessageOriginChat",
-    "MessageOriginHiddenUser",
-    "MessageOriginUser",
-    "MessageReactionCountUpdated",
-    "MessageReactionUpdated",
-    "OrderInfo",
-    "PaidMedia",
-    "PaidMediaInfo",
-    "PaidMediaPhoto",
-    "PaidMediaPreview",
-    "PaidMediaPurchased",
-    "PaidMediaVideo",
-    "PassportData",
-    "PassportElementError",
-    "PassportElementErrorDataField",
-    "PassportElementErrorFile",
-    "PassportElementErrorFiles",
-    "PassportElementErrorFrontSide",
-    "PassportElementErrorReverseSide",
-    "PassportElementErrorSelfie",
-    "PassportElementErrorTranslationFile",
-    "PassportElementErrorTranslationFiles",
-    "PassportElementErrorUnspecified",
-    "PassportFile",
-    "PersonalDetails",
-    "PhotoSize",
-    "Poll",
-    "PollAnswer",
-    "PollOption",
-    "PreCheckoutQuery",
-    "PreparedInlineMessage",
-    "ProximityAlertTriggered",
-    "ReactionCount",
-    "ReactionType",
-    "ReactionTypeCustomEmoji",
-    "ReactionTypeEmoji",
-    "ReactionTypePaid",
-    "RefundedPayment",
-    "ReplyKeyboardMarkup",
-    "ReplyKeyboardRemove",
-    "ReplyParameters",
-    "ResidentialAddress",
-    "RevenueWithdrawalState",
-    "RevenueWithdrawalStateFailed",
-    "RevenueWithdrawalStatePending",
-    "RevenueWithdrawalStateSucceeded",
-    "SecureData",
-    "SecureValue",
-    "SentWebAppMessage",
-    "SharedUser",
-    "ShippingAddress",
-    "ShippingOption",
-    "ShippingQuery",
-    "StarTransaction",
-    "StarTransactions",
-    "Sticker",
-    "StickerSet",
-    "Story",
-    "SuccessfulPayment",
-    "SwitchInlineQueryChosenChat",
-    "TelegramObject",
-    "TextQuote",
-    "TransactionPartner",
-    "TransactionPartnerAffiliateProgram",
-    "TransactionPartnerFragment",
-    "TransactionPartnerOther",
-    "TransactionPartnerTelegramAds",
-    "TransactionPartnerTelegramApi",
-    "TransactionPartnerUser",
-    "Update",
-    "User",
-    "UserChatBoosts",
-    "UserProfilePhotos",
-    "UsersShared",
-    "Venue",
-    "Video",
-    "VideoChatEnded",
-    "VideoChatParticipantsInvited",
-    "VideoChatScheduled",
-    "VideoChatStarted",
-    "VideoNote",
-    "Voice",
-    "WebAppData",
-    "WebAppInfo",
-    "WebhookInfo",
-    "WriteAccessAllowed",
-    "__bot_api_version__",
-    "__bot_api_version_info__",
-    "__version__",
-    "__version_info__",
-    "constants",
-    "error",
-    "helpers",
-    "request",
-    "warnings",
-)
-
-from telegram._payment.stars.startransactions import StarTransaction, StarTransactions
-from telegram._payment.stars.transactionpartner import (
-    TransactionPartner,
-    TransactionPartnerAffiliateProgram,
-    TransactionPartnerFragment,
-    TransactionPartnerOther,
-    TransactionPartnerTelegramAds,
-    TransactionPartnerTelegramApi,
-    TransactionPartnerUser,
-)
-
-from . import _version, constants, error, helpers, request, warnings
-from ._birthdate import Birthdate
-from ._bot import Bot
-from ._botcommand import BotCommand
-from ._botcommandscope import (
-    BotCommandScope,
-    BotCommandScopeAllChatAdministrators,
-    BotCommandScopeAllGroupChats,
-    BotCommandScopeAllPrivateChats,
-    BotCommandScopeChat,
-    BotCommandScopeChatAdministrators,
-    BotCommandScopeChatMember,
-    BotCommandScopeDefault,
-)
-from ._botdescription import BotDescription, BotShortDescription
-from ._botname import BotName
-from ._business import (
-    BusinessConnection,
-    BusinessIntro,
-    BusinessLocation,
-    BusinessMessagesDeleted,
-    BusinessOpeningHours,
-    BusinessOpeningHoursInterval,
-)
-from ._callbackquery import CallbackQuery
-from ._chat import Chat
-from ._chatadministratorrights import ChatAdministratorRights
-from ._chatbackground import (
-    BackgroundFill,
-    BackgroundFillFreeformGradient,
-    BackgroundFillGradient,
-    BackgroundFillSolid,
-    BackgroundType,
-    BackgroundTypeChatTheme,
-    BackgroundTypeFill,
-    BackgroundTypePattern,
-    BackgroundTypeWallpaper,
-    ChatBackground,
-)
-from ._chatboost import (
-    ChatBoost,
-    ChatBoostAdded,
-    ChatBoostRemoved,
-    ChatBoostSource,
-    ChatBoostSourceGiftCode,
-    ChatBoostSourceGiveaway,
-    ChatBoostSourcePremium,
-    ChatBoostUpdated,
-    UserChatBoosts,
-)
-from ._chatfullinfo import ChatFullInfo
-from ._chatinvitelink import ChatInviteLink
-from ._chatjoinrequest import ChatJoinRequest
-from ._chatlocation import ChatLocation
-from ._chatmember import (
-    ChatMember,
-    ChatMemberAdministrator,
-    ChatMemberBanned,
-    ChatMemberLeft,
-    ChatMemberMember,
-    ChatMemberOwner,
-    ChatMemberRestricted,
-)
-from ._chatmemberupdated import ChatMemberUpdated
-from ._chatpermissions import ChatPermissions
-from ._choseninlineresult import ChosenInlineResult
-from ._copytextbutton import CopyTextButton
-from ._dice import Dice
-from ._files.animation import Animation
-from ._files.audio import Audio
-from ._files.chatphoto import ChatPhoto
-from ._files.contact import Contact
-from ._files.document import Document
-from ._files.file import File
-from ._files.inputfile import InputFile
-from ._files.inputmedia import (
-    InputMedia,
-    InputMediaAnimation,
-    InputMediaAudio,
-    InputMediaDocument,
-    InputMediaPhoto,
-    InputMediaVideo,
-    InputPaidMedia,
-    InputPaidMediaPhoto,
-    InputPaidMediaVideo,
-)
-from ._files.inputsticker import InputSticker
-from ._files.location import Location
-from ._files.photosize import PhotoSize
-from ._files.sticker import MaskPosition, Sticker, StickerSet
-from ._files.venue import Venue
-from ._files.video import Video
-from ._files.videonote import VideoNote
-from ._files.voice import Voice
-from ._forcereply import ForceReply
-from ._forumtopic import (
-    ForumTopic,
-    ForumTopicClosed,
-    ForumTopicCreated,
-    ForumTopicEdited,
-    ForumTopicReopened,
-    GeneralForumTopicHidden,
-    GeneralForumTopicUnhidden,
-)
-from ._games.callbackgame import CallbackGame
-from ._games.game import Game
-from ._games.gamehighscore import GameHighScore
-from ._gifts import Gift, Gifts
-from ._giveaway import Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners
-from ._inline.inlinekeyboardbutton import InlineKeyboardButton
-from ._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from ._inline.inlinequery import InlineQuery
-from ._inline.inlinequeryresult import InlineQueryResult
-from ._inline.inlinequeryresultarticle import InlineQueryResultArticle
-from ._inline.inlinequeryresultaudio import InlineQueryResultAudio
-from ._inline.inlinequeryresultcachedaudio import InlineQueryResultCachedAudio
-from ._inline.inlinequeryresultcacheddocument import InlineQueryResultCachedDocument
-from ._inline.inlinequeryresultcachedgif import InlineQueryResultCachedGif
-from ._inline.inlinequeryresultcachedmpeg4gif import InlineQueryResultCachedMpeg4Gif
-from ._inline.inlinequeryresultcachedphoto import InlineQueryResultCachedPhoto
-from ._inline.inlinequeryresultcachedsticker import InlineQueryResultCachedSticker
-from ._inline.inlinequeryresultcachedvideo import InlineQueryResultCachedVideo
-from ._inline.inlinequeryresultcachedvoice import InlineQueryResultCachedVoice
-from ._inline.inlinequeryresultcontact import InlineQueryResultContact
-from ._inline.inlinequeryresultdocument import InlineQueryResultDocument
-from ._inline.inlinequeryresultgame import InlineQueryResultGame
-from ._inline.inlinequeryresultgif import InlineQueryResultGif
-from ._inline.inlinequeryresultlocation import InlineQueryResultLocation
-from ._inline.inlinequeryresultmpeg4gif import InlineQueryResultMpeg4Gif
-from ._inline.inlinequeryresultphoto import InlineQueryResultPhoto
-from ._inline.inlinequeryresultsbutton import InlineQueryResultsButton
-from ._inline.inlinequeryresultvenue import InlineQueryResultVenue
-from ._inline.inlinequeryresultvideo import InlineQueryResultVideo
-from ._inline.inlinequeryresultvoice import InlineQueryResultVoice
-from ._inline.inputcontactmessagecontent import InputContactMessageContent
-from ._inline.inputinvoicemessagecontent import InputInvoiceMessageContent
-from ._inline.inputlocationmessagecontent import InputLocationMessageContent
-from ._inline.inputmessagecontent import InputMessageContent
-from ._inline.inputtextmessagecontent import InputTextMessageContent
-from ._inline.inputvenuemessagecontent import InputVenueMessageContent
-from ._inline.preparedinlinemessage import PreparedInlineMessage
-from ._keyboardbutton import KeyboardButton
-from ._keyboardbuttonpolltype import KeyboardButtonPollType
-from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
-from ._linkpreviewoptions import LinkPreviewOptions
-from ._loginurl import LoginUrl
-from ._menubutton import MenuButton, MenuButtonCommands, MenuButtonDefault, MenuButtonWebApp
-from ._message import InaccessibleMessage, MaybeInaccessibleMessage, Message
-from ._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
-from ._messageentity import MessageEntity
-from ._messageid import MessageId
-from ._messageorigin import (
-    MessageOrigin,
-    MessageOriginChannel,
-    MessageOriginChat,
-    MessageOriginHiddenUser,
-    MessageOriginUser,
-)
-from ._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
-from ._paidmedia import (
-    PaidMedia,
-    PaidMediaInfo,
-    PaidMediaPhoto,
-    PaidMediaPreview,
-    PaidMediaPurchased,
-    PaidMediaVideo,
-)
-from ._passport.credentials import (
-    Credentials,
-    DataCredentials,
-    EncryptedCredentials,
-    FileCredentials,
-    SecureData,
-    SecureValue,
-)
-from ._passport.data import IdDocumentData, PersonalDetails, ResidentialAddress
-from ._passport.encryptedpassportelement import EncryptedPassportElement
-from ._passport.passportdata import PassportData
-from ._passport.passportelementerrors import (
-    PassportElementError,
-    PassportElementErrorDataField,
-    PassportElementErrorFile,
-    PassportElementErrorFiles,
-    PassportElementErrorFrontSide,
-    PassportElementErrorReverseSide,
-    PassportElementErrorSelfie,
-    PassportElementErrorTranslationFile,
-    PassportElementErrorTranslationFiles,
-    PassportElementErrorUnspecified,
-)
-from ._passport.passportfile import PassportFile
-from ._payment.invoice import Invoice
-from ._payment.labeledprice import LabeledPrice
-from ._payment.orderinfo import OrderInfo
-from ._payment.precheckoutquery import PreCheckoutQuery
-from ._payment.refundedpayment import RefundedPayment
-from ._payment.shippingaddress import ShippingAddress
-from ._payment.shippingoption import ShippingOption
-from ._payment.shippingquery import ShippingQuery
-from ._payment.stars.affiliateinfo import AffiliateInfo
-from ._payment.stars.revenuewithdrawalstate import (
-    RevenueWithdrawalState,
-    RevenueWithdrawalStateFailed,
-    RevenueWithdrawalStatePending,
-    RevenueWithdrawalStateSucceeded,
-)
-from ._payment.successfulpayment import SuccessfulPayment
-from ._poll import InputPollOption, Poll, PollAnswer, PollOption
-from ._proximityalerttriggered import ProximityAlertTriggered
-from ._reaction import (
-    ReactionCount,
-    ReactionType,
-    ReactionTypeCustomEmoji,
-    ReactionTypeEmoji,
-    ReactionTypePaid,
-)
-from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
-from ._replykeyboardmarkup import ReplyKeyboardMarkup
-from ._replykeyboardremove import ReplyKeyboardRemove
-from ._sentwebappmessage import SentWebAppMessage
-from ._shared import ChatShared, SharedUser, UsersShared
-from ._story import Story
-from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
-from ._telegramobject import TelegramObject
-from ._update import Update
-from ._user import User
-from ._userprofilephotos import UserProfilePhotos
-from ._videochat import (
-    VideoChatEnded,
-    VideoChatParticipantsInvited,
-    VideoChatScheduled,
-    VideoChatStarted,
-)
-from ._webappdata import WebAppData
-from ._webappinfo import WebAppInfo
-from ._webhookinfo import WebhookInfo
-from ._writeaccessallowed import WriteAccessAllowed
-
-#: :obj:`str`: The version of the `python-telegram-bot` library as string.
-#: To get detailed information about the version number, please use :data:`__version_info__`
-#: instead.
-__version__: str = _version.__version__
-#:  :class:`typing.NamedTuple`: A tuple containing the five components of the version number:
-#:  `major`, `minor`, `micro`, `releaselevel`, and `serial`.
-#:  All values except `releaselevel` are integers.
-#:  The release level is ``'alpha'``, ``'beta'``, ``'candidate'``, or ``'final'``.
-#:  The components can also be accessed by name, so ``__version_info__[0]`` is equivalent to
-#:  ``__version_info__.major`` and so on.
-#:
-#:  .. versionadded:: 20.0
-__version_info__: _version.Version = _version.__version_info__
-#: :obj:`str`: Shortcut for :const:`telegram.constants.BOT_API_VERSION`.
-#:
-#: .. versionchanged:: 20.0
-#:    This constant was previously named ``bot_api_version``.
-__bot_api_version__: str = constants.BOT_API_VERSION
-#: :class:`typing.NamedTuple`: Shortcut for :const:`telegram.constants.BOT_API_VERSION_INFO`.
-#:
-#: .. versionadded:: 20.0
-__bot_api_version_info__: constants._BotAPIVersion = constants.BOT_API_VERSION_INFO
diff --git a/venv/lib/python3.11/site-packages/telegram/__main__.py b/venv/lib/python3.11/site-packages/telegram/__main__.py
deleted file mode 100755
index 7d291b2..0000000
--- a/venv/lib/python3.11/site-packages/telegram/__main__.py
+++ /dev/null
@@ -1,54 +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
-# ruff: noqa: T201, D100, S603, S607
-import subprocess
-import sys
-from typing import Optional
-
-from . import __version__ as telegram_ver
-from .constants import BOT_API_VERSION
-
-
-def _git_revision() -> Optional[str]:
-    try:
-        output = subprocess.check_output(
-            ["git", "describe", "--long", "--tags"], stderr=subprocess.STDOUT
-        )
-    except (subprocess.SubprocessError, OSError):
-        return None
-    return output.decode().strip()
-
-
-def print_ver_info() -> None:
-    """Prints version information for python-telegram-bot, the Bot API and Python."""
-    git_revision = _git_revision()
-    print(f"python-telegram-bot {telegram_ver}" + (f" ({git_revision})" if git_revision else ""))
-    print(f"Bot API {BOT_API_VERSION}")
-    sys_version = sys.version.replace("\n", " ")
-    print(f"Python {sys_version}")
-
-
-def main() -> None:
-    """Prints version information for python-telegram-bot, the Bot API and Python."""
-    print_ver_info()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index b810a5dc8c8fa7b51ce6e3307c2cfa00095c530c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 17060
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%0DiVF1__r;SKIJG=eb&Sv#MB?j`^}1vRO4E
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

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommand.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommand.cpython-311.pyc
deleted file mode 100755
index 1dceb84a698356f54d35d7dac57ffec3403b5fd4..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3078
zcmeHJOKcNI7@qZW?br#A1_DCq3Zx1{u#0k_HK;0epb8;&Rf2@JhskDlVz1eUJ2L@-
za>xOxp+ag7R8$p*oM;g}^u)Qx_GT(eO;@TEsi)ptrK&1U{b#-F2Z@ySSgEtKvorr|
zX1@QQfA*_vHjSYC{P4^A4;h4h6@#$EgU+@Jokz$(Dl#M^Vo7#Hjo48&Dv5E_irH~B
z?)PI>!cMA5zaO_`JEf*16hZGJBXJKINs@dLMd%s4ouZ}<`5MZl?p~g&nM|==W62_l
z?mApE9j0iG;x5#Q&J|wMxI#&T5=I;j9A%DJq)IhgdC%oa$+d0GG4j6&v$=>Dzic|1
z<;j%>H(luEBrgS48P`A=2E(Ct#WxQW`O39QdCJte9xToO$iZMcAtCe$KtPZx0SuAr
zuyHkNMAVoOHDZq?BTnK*0^TG^kmQlBjm5+oT9gd=-mof@RNaSKFzZ91h&n_vB-_&<
z!$#@?FjHtiexxfuvO_+-i~PQ>{JtIXL%YcD@5=ArA)gWQYv_)o9sp-$y)-}`Agcf?vVyx}`C2DHWc#8yeLXAP7uH;e^`06!~~b
zvrN96SLSZJK}hVP?i&|wHVs0Fq4;VOiYcZcCRK_W=d?HMk@w`&x)iZwB73X;nuK6Bz
z`Pu0*E>&h{FP5j~&vfmJIrdV#c%!SR=rur02dr3LDZz;ePLJX`*0N%`w+YoXMh47Z
za;lceYKld;(3?;UvucV{1%NC$03Op_IBEH=QXf38?0c#Q+^gH~YX6fR0Tff0u9ZHV
z{$OspQvUaF^egv65_k|CZ!Rox^1mO$F#k{b5mI|HIDg(yUr?5xN?uxPnE2*x4Gt?6
zd6tS4OS91E;e7*19ErYox1U4vx%3EeK@G|i_&y5{R|NMef)pGnQ@E;8F5$)5QiD)W
z#@KXBj&X12UJ9EA78#FuNxVo2xl3|!FUE+q*pu?{0a5JdV2qhqggCFOFDr$bYmd(tAs1S5p(z(OkDXYHJ;-b-
zr`KXFd2H+G_~VJMW37{KHIKXvjNvUg^I7K8%>Cg9!)yMt4JMH{)R$&q&`X`(h~V@k
z4j=%xkB~bkkaaYhVC_u
z@m)G9q*7sXOfde024L+y?Z~0H+(x2#6YW2}I=%G~Zlh%UaIe{j`u%TD_@D1;-`{Cn
zzR_dv+B<+=KiL{T*BURa&a98Fvxi5Uu@cl5u~It{g~{Z-1x`$~j-PKGpINP}U;kqA
zq1ueiKz$LL2`%g)fW$oAh8_xmDCdUgI1Ic5Uv8LA)koWRjwgq~+HuZUILza)*ZHNP
z386n467zV8n-ok@isUdk6b;qneW1w-K=whm1@DoIlN4J6G}h&
q9dGVdx6pWVux_Hs=3w1Kr<#Mcoj4}}0y~@a@!tjYk6l>)ivI?>kU$Io

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommandscope.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommandscope.cpython-311.pyc
deleted file mode 100755
index 758e9cdae80731a22e22914a9a25d96f9b86b207..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 14363
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

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botdescription.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_botdescription.cpython-311.pyc
deleted file mode 100755
index bf6104d12fb7c5db351d66fb457b54a0f7e225a6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2918
zcmdUx-)kd99KdIjO|p$mw4TSMRqKe*yPS3RuEie&IlQxQSg=)65F$9;W+%<|HrY6{
z?X{&3eK@cu1$|IXqz}c1YN>yKkM|#3l!A3ZDEQ=Cq&~s+9%YlOGc#qIjzD1QJ0}L4jmMETs^&A_dio
zTI!Z!#b^vdj?=_oYj#Q9KqbXW+({R-4YaHjM2MQ7zTtWkZSTxw1tA%A5Metu5i1o@
zUF2QiB$F6Q;5Wx^35G$=ijK)SHkn9UrDig74l-z0u}4`&j-nqgnvU(Q=y;|hojuc~
zamYNkEy}2c<+M?3i)EqPJOg;JX(#&~}HW)rr<3-zz(y*=uPPw5F^f
z60U;Q&_YWt35{4!mNm4khH~e(dtJDbD35j{Qw**(%EtT{U#wB)YlPTU+apAV=JyfX
zB4R(epCBbh=_<{tzRIanYR3+vh&)_`aIrLO+xo-2QFbfTsF{iG1t5*$fd-Ro>S-fS=Q*L<8+iDOv*d3|YYbz`b)>kidUk^R>codX;
z0;<2((XU$SZela>vzGZu%WO~9waky2v9B3*%{ag>Z>alP=5T0uf9P_3aCAf6Odo3f
zpY?y*e>c6E-jKf|u!DA!A|F+=LJ9Gcgap(9xt|bmSDKmxA(mT&ZpZ_7fH5FO;gmA5
zCrn^cI_{^MX)033A!Ju!PlJk!Eq;rg6QdGgH6#>Os34T^*NCKIS_6q{7!AC*{?6gM
z?>A69cA;Huzb)k-wELO;HzwQtrP&b!%n(II!@~ukk@1Dk>Gn&GETzZ*{uQ!2YRdo{9qUk%m0{ztRMW(##l;(As`b3
z^rVoU5-ODqw0Z^ZgR2|DF1WoCPS2fivRj0@2{TVasFBwNp@t=)uG9y|P9#)tSmIIP!w%6xFLj@mP*r1dilCI0lICUJ5u;zQ4SG?Y(2lQ#1qDgacFAJ|_O}_;GKg
zW>@DW68%ibc%6h&@YjZkjQZ!pPMs`zw!?LpOL+iNiAZ627X_;ba6Z)D4A6XyjX+am
zf`0>5BdRD$V+1K5Ds@yiK+o2@pF=cW?|u%@<$Cwih-VZ)Y;X1XM}LUkKijI;dI!mg
NU+Kq3w&utf{svYW=feO1

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botname.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_botname.cpython-311.pyc
deleted file mode 100755
index 5db84c6fe582bd852d23fb226ed964d85754a985..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1897
zcmbVM%}?A$6rb6(*WS%85VdIuDah)fWUIz5<+h5dl5LV^MV13ps(cyDdKOIlv7H%6
zK^!zc+8@ef-|@
z{8*`!5RBiSJYTM82>l_2Y^W)7VgvIOxyVK?c5^-sa&|7r+j%VIysreRttPzU7Xr=J
z5?=N7plBB{%Avc+Eo>oIquPERp#ymP!!Eh{EUFgQ>vKyUH-gAr@u|^@Lg9EJH=NLj
z7M5vC7-Gp02BRHDISqy37<1I8i_8g(g-CECbOLJrDQ#ABv3kb~9Y5A*I>L*9tKzr_
zCb@7z!9f_v&dwyZVMTAu&NM&wTB4Q4m3#`RaKeE37V@Xa#(+WYOUT;JyE$8N^RBXs
zU6rbCfflHC_4IsO*+y;bYFh)gPK(P4#!|U_DcfR~X@w4)ouGrReiM}2=o@SgNmOF(
zRwSB`n$yGxB?zT(oFc&i87eUtPeCY^3>f{)xDmBM55Ts3hXb5UVjFZE<}3irUT6r)
zf@Bx{dd2ZQv1S@`52Fegz;Cm)-WeccpWAGmy`ec>
zL>sxE@IGh`PPG_q;0;7FFK7cTpYm;~k^Yjgf%cS)fAf3ZFZ^-{nkLs|vcsxstn!r(
zWwB0(7kYw_B(=CmJeSBS@mM2mM(H}ODzU<;-#*J7c9EoI2;tH-)MWGZw6zok)CwHd
zimXPo7)@GEr(>Q+~`j;@YwD?7#Gk+I$C
zv-f}>asVmNCwI
zA?OKl!Y~q!yq2WhN{Vue`aU65%-({%Tz1H3>}`3rn2~Ezu>}NhIeU7!imLaJBxC6E
z$mYG{JB=PHsPCSUXR`_a^YAa%4=3tp>lboEXl(p&bn~tX^UxAjAc+*73r{B-sS1SkJ27M`}0|O_Fi_tBlE8HolTAnq)b3v?

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_business.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_business.cpython-311.pyc
deleted file mode 100755
index 424437af6f2c02e1c2b127d68117e2f0f56ea5ec..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 19628
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
H8=wCV;Dycn

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chat.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chat.cpython-311.pyc
deleted file mode 100755
index 8641ff5993c5bff48f9aaef3ca35862d48ba4109..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 118735
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

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatbackground.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatbackground.cpython-311.pyc
deleted file mode 100755
index 130b0ff5e4e4c46135374883578b33b9f6fdea7a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 25026
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

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatfullinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatfullinfo.cpython-311.pyc
deleted file mode 100755
index 6d8829dc35f72cdba4e04f1f6fb063304af368af..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 25685
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

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatinvitelink.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatinvitelink.cpython-311.pyc
deleted file mode 100755
index d36365beac4cf57ffadb304655611d3a32667096..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 7885
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

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmember.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmember.cpython-311.pyc
deleted file mode 100755
index 2ce78543e6a02741708f25aebc84efafb1a89412..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 29417
zcmeHQYit`weqV|YkT7-?SCV^1I9fCqEL~N#w*<5=XfnMRC^_9X@osD=TuD
z#w`Mzaxic{!08!9+8V(%i7x?a^h2AE7o-L9p(v;;gJTI4Fi_+}ztOM@1ox@G|IE%l
zC`y)PCBEyKriL>+v$ON~&-`D%9e>=?5|;4!&uf2uVdtBY^xu>aAHNy78}~@kFC;}8
zl@yQCknxN*;Mbe+W__c+tbf#>4U7gnl;_JdW`mUpypW=^yMk6e*
z8F?*gq$aP6<+UQOZC>6gme-EFj(K^jSzagdBJ=XPSzZ_NR?W-nVR@^O*F7(
zBglGD&5o;D?0=~D!%=UgW#sjjjwOy9KX&B#6T{C{{LiLy$xJ19YSKvO5sP{%Av{Dk
zlBf%bR#Dk0_B34ay`rmHw4t(2eaq02DI;NAO6Shy6X&#iHle8Jl2aK&ue7qHkk`Y!~;
zEf*R^Y_w4gs-a$yl+>`|eF~|NaJPWcwAe9OG@fjZ?|
zt@5q&$~V?2-)5C>n^!)_%PS!z{DB7q->x*PArN0DX|i5vN)l;`Vg
z2^F8liqNnORAmW;Ur^5(ODJ|YnafdqtXt-Q(oh++b@1V*flB4GlSwT(j*TRplMPkN
zvH?|pJeAC(jhUD{GMzWK6_(+?omEbILt0TaRgu|k{c@Tfqoy@Eo-_boP8s`z{FG`IjM2>Vi674!
z&zRkf#pH{srepU)cJ4f=ATICO9ox+xLe=h+hgf&0vZ0qw$ope^`z;c&DPv5=VCC}Y
zH0W)7igs329(NNkUDBt<*^sKb)o@wPfK)Ih$?^O}m35xgC1>(zk%sNrn9?vqvXa)Y
zXJ=;Q@fkUuRgH=G*q>WOiuT3Mt44ylImXumHD8uTCNSVwKWabtfNt=a#bdPdQ(3;}
zW3*}X(`Ysp$ux@NnOU?2*O51qpOW>7{8UCk2hBz~8jmTfJ07C7c3XB*TZjuW1|g5J
z$>MVrJ97Hi(8#INV`K7kQYVg-Nv808>M5rTyQlV`$4k>`&c
zeZcw;4-F6FCQc1Q+Ia`L5v9sI=Is^4-^QYG`2@I{mQ500qe~c
zXaADxHiu{NN?$nk?8w;C>wNLpi-$3%GB*6hntJ*ex^&{m2xiCJ5r!-hw)cd`lcdFd
zuOrkK#m`8v65x%l_=tEa0ZtQ@us!L+H$9bbax$HGa~d0&uC+s=
z&`8eFdJv?9zz%s(qB#BC{U-$PdwwAqbk+R0rI8zs98p4&3f|8=A0g*cE7v0xJOwGy
zAj%XPkP^?73ep8TN4j8LKS!l});-bD3MkYw7T_5BLr$yy`)C{6`!tV&e^5d_@HQlaiK&)r$*4;dHHvz1}5@Z
zbs(G6Qu%?C`Sba`1IfwBfs1PH;y@-nJ}^0BOyqNWV}pYOdfHH*m`tYLOrBTu0l|X?
z81vzqS8Q@dTZ^hMMI76;X!IM%&`%-w_OkT9tx~A>>>No_8r&pZ@LrU(-32eoTk67MD(*^wqSn!ChYgdOxWziof7N>!Ze2yY@m&|K9c)+a0+c#c%hZ;QK5vuV$vGVLYu?
zvhjRr!L~NK+xizzDvb+{Wlh<%=WV|cwOi-j0&c9bbL<$6Z^8dr&~1aj2rpcZqbKfq
z=Fd|!bgBQ03b~F;nPP#*Mog86YY8z$OW!@aG^j{!kK)^G>xzgTib{V
zblN6ptHx%n$%t!v5M1iCTPh|5_B2V)Vt2y+S`AC>k)OTu(|4{Lb8TBnZChr2x7#9B
z$rI`+N4l@>s|KW&_A4jef2Z8sR%%}V^~M8;Tsir5&kp(>{(9YR`aS-BPF$|GG#(7k
zwpKf(=C=2D7Ms@Ld!y^)o)3FI*)i9*x74@y)}I&qj^SI5^xfF<@s1C7d~#@R)4meE
zk^R4oJpG%<)4$&L)tO@C>AA?urO3<0=9jxZS?hrfy!`(B;vd$rW}
z>g>_0>*ks_RD)>Y*PYvnP4xX_-#;As)uH0P7w2{jmv#*oca4_U?7cPe&u9PfZ1I`b
z=Jua0?LS-WeSP-ie?@wJe(>7C-$pk7CbIdHu3LM59WO>U&qanyk>O(V@HcH;?@eEs
zrV+hy^pn)=J9BM&N^N_J!97|ZhW(~zIND9@IhV|;i9{uwNO0>L;?0Q!Da&R~V<(|G$&z@4xq07f+
z_g{@%LFOTR=X{6CzNgB)n@YWVF}IhWojrDS^OciDAM)dKzIfU9bh%qDbq|)h4_rPv
zyY;H~%Fd$i0KRj+17+Wni{H6^TWS5l()z=fPhRz3Og)!9TiAoS@hiUX&keL8O@3xJGnaQpRVri4M
z6Aws+AVV>o@wC&BoPxG$YO>H?5zkM<^epsPR-UX26Hxb)nT(utn#|-$EqyT!L$nIh
z9xG}aYLbe=%rt|0V+X$@#XPNJf#q{E+5D6))bsItK12FBSJp?gDRoSkuUG^5#w^RE
z)j)IS7WEXjm6^IbnTRIRXnxMN0i>pM1Ey~yZNRSPumtqWd0|wK!>~z(WL}6&q0F|%
zjS1}G^>p9mSQp%CdNMPeoYCdDasCNrw5e+nHEl3AvZPx4f@Q(;koXI%?uMHyhwo;%Ykyr)(UejZ9i%yo&8?T
zwt;SA_gYsS0uwck=0wO#Od;*D5t}G)|Xn=SEYu~Q!FTN+cSFG>)D3?bISND1Q;msuiDT>G5`hrQpe!s6V+yE`>txJ
z$^R5$V6QC{lSIJSD50qn4(aO?*2P+
z>NCX7Bz2fbiRJ1r^?>IpY3{jQGQ*|SWbBX
z!K9LYd3qw9njk|xhJ_0|lX)1+$P2(cY7V=-;O~|v#`P43SRf4Cb%%X0HfRmiknMLf
zom!SNF%l3Yw6v;2b}_B%lmji?kz>{8aKlk419%UM%1%*^TxsY+WOh$Lp$I1DZ(t?K)WYAr6VPRm6r993pa$~$`g}@eL3F)#5
zvAxgl5?P_VgN*U{e^^qkIJgy$#0DE)z2z;AT5faZ!dA4nHB%YdkI
znHhKc8DIS_+RvDgRk3>q;`=UU9hPKQV@3HV8JcR5X5&W7ChwZ%`;9uMIGb;}9*NI^GO~*|cgexnqen0GTPH8F}dnD75*47WKU|z=$EoM#4PpUcEXr^Gd
zWO@=`@bg!>YdGr;k-eClhBeU@!cDn)QfsZl>c*BttVXCBLLYU&xxO!JsSEDn!0A!*
z&?DxXaoAa3!R4jG$!PC*tne(R;msEWYBsUQ3Qrxz`B>qp(FK?|u>^(3DM{M<9s_l9
zVbU!vKCDK>nq_K1u1(cN_H{HONIyVeFQgN>DZF^nGYWE~ndrH~$f7MfYpi(@51
z7fdx;aGy%2{Dyyj;^AfXwa~EKR
z)#kKY@ta+o(kuj9hwx$XF4f3gl`eXQ5buP2ngcZmWZ;Bwynr;vBb=ewFa@trK)@^Q
zbqZdj;4}qiDR`Lzg1&37QScH4uTn5VfsF64|j9ubEEjuCjHc_lu
z+OVnGLa|n%UV(rq#&D9Qyby9AGVqJ8{DvGU^)^4nJQ>=$#y%bwRv9%OiC#~|{)YO&*nSgi{0NQ5=DV@B*=Pl<#!DM!mn`{x
z3^U$B*am`j3R{%sP+0(2*#{e$4VC>jBvw>7qSrq0q?LfmE?;;E)Cv#8a=Gw8<8jmP
zVD{Dk@fSD<*hx&;$&7oCK(OYoK=IJx!hb_tm|l@3F6@3MlhCh&pZmUA!`<7?yThw&ngMjoaVxakE+KYT~FA?3OxY@YApq
z+f!`}`7uag_Oc0!N_NQDC`$(DHIp+R{IJxu)4D_OrY8G_s^jLR#5tFuX1ll)(F}d=
zUO`ZgOSw4|UK6<=64t@P9GKVu4mS!YUHDstztw6;4ci><+!lsu?Z){sP3+~8W;(n`
zdjd^L{tE;iwqq~;atV3(as)a|sTv(}|+c?bjF)Q4CtZ!Xv%By(wg;0$_u9)Jw|5M=F5!gtcv
z17Q*4kxA!pFcDrib+-$uKw?@Q$J^FG=3}$Cm{zABWE`B-;XqB3I}+70AQ9YyX0;q*
z1fQd@54zjpGWjioLXqg^y(`Q@VRBTk#kBmMg{x-NBN%`AgQn2eMVPz0ymqs;g)^
zP!bFWL5K*B2Vsf>*IPK&#H~qimDmPfCMZxSV0~v+e3g>tC`eO~q2NslvJ|lM
zLIj4v$UkQFADXqUr7w8C{ekRXJb
z5u1eeJmN)mq|1?})2-UIcDMD>*D(^TzzZ=Vg$LV)RdG8DKyR$6v`;mX;lvRxh0=*4M
z(OZ&&aSGTWFoe6}=k5$qtQJK=?il8ixrtfQ5Amt8U0yj4`Mg*-=Ivl8l3@?|x}w|t
zG&gq0d|fOVkh*%RjVu}@;75o>!-Vo^V$o)bwy3+`Rv=Y!Gl_Sxi&d;u@4%QzJSzLzXc
z8NT@a9@h5AEjH|6bK7$LkXVeHF02FN@YoUA2lFS<0tFa>`)OB{!#6CK!}Bw|IL6Um
z%g=}(XzLL~eGdLZ-QwT`I&lnq!pR>TN4V0Fs}^TSV;pok(26)ia}8(sW!o*~*OwSD
z;dCi@x)?lNu00i+t+r_RJ{#gvc0gKAY)!pJO)_|s>>aR$Hb4qCNF5P&0v2|^P$L~H
zDFU|jQ6gyVBklrr(FJ3C_n@}8b`OCZyGxkj`|lq1|AGUbzUzO%G5@cYAoddbsK<~t
zfNGQdpur{VCFG{Y@gMY`Ryf@5K)U;@+@E~<^8nfJw@
zC8^Wn6fA`k(PqqcWSz$0GEx`^@vqv@L!5|$eH?zq4>%6_(MS=PfU|?ZZ8HHG;IxCl
zra6#ij>7hB3&uECqIN~s@Pj5$
z)%C-x8}6{2d(QkHdAE3g|DPXRy>N%F-m|lYJ79lCnY&N{Tsg9R}^peEt!
Ky*gQpVEzv(nmVrl

diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmemberupdated.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmemberupdated.cpython-311.pyc
deleted file mode 100755
index dbfd950ad4aedd7166995c9868fa8cf7e264393f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 9738
zcmeHNU2GdycD}@AdGo%MFYizJIV|($I`TqFU~ykAkPoJUEbh;B=0m9vi+AM0
z`A90l;zF(~-<|4a@j$L8-<#^qM^jOj4(9su{i%MAP_O0(+MT(9{9tO3BOdZ2qJ(Y}
zB}^k9@`QW>Kl@3=6wi4QkF1=&Fq_rIys9kZsF+p@hMX8~dq
z=Qu+C6sC}p6bI7?)0g5EPs$r0_@@jiyyE?UQ+(8?_^Ds%pdE99Lr4*5KncJvNQ1O<
zlao!9PDqEE(xJ9=7}8<4Jkwhu8BU4Z?n*^y7jTU!U9B~gZW>g2+!jhNq=}o(_!))h
z?eK@ti%%LoNp&lIvSDG4*rX!NuCbttY6g%A
zMTVGXh)e{7B0M%|Sh0aPPv>MEFsvce^YgMM&j9L?64mmo7X70IIhQq-6XJy>wY~

dE|IdWi(5k+3cn$UbuMV%FmAqhhHA_Vqe`{a^5z;1T34p=?mjz)&v}ZA0t$-lA=27T;sE z4b9`F11;IAbjpsqsIWU5;bHgfdNi@yozFtg%<3%Vu&TBBSN~D5#?_L&F zqCkTp$!(mi&QQ7U5HPVl^>N+!?iDX6y--s#V7;Y(^k*Y09ArDSl!IX(rTtyhD$>AG&eDkF(ea@7lr%=d|(?H?@lQL+99{v8RrEz zRC?LDYoMkJpWR%stdGFpcaQ8iPA_=(-=2=|1D`PrD0ub(`qwCGY5!ULe*BBXz+Vyr zf8Eb*??3bV?ms81iGe4HrR~I0HL+x+x_)aKm*QML!eaw1&p1hA*Z!VK}x;9)N+L^#tbTVHDrWBmsUgc-cp6%5XtT%|; z`9o|veLfrgV>WhvD*h*ifgCUdcvS_sU*YW}&pZF6fN~qpzgH4uwdO|mQKuHC-$lnC!-UKw`1gUO(!Nzchye05X)m(=J_?On|u%-2q!V<#+lhDWT!uUKc^u%_p% z(J|}jNo(r7H9ldTK2sY$+5|g&1fAe&BeaO>`Il`SwI)h7quzbBI4vg7z`w z)DF_hLulyOqx>hgYlD;=LL;w!I{9nPUnEF)XS?^<&Xv{ztA2j@Dd^tWg~jxMJ_dx{ zk=JAy=Sj#kIAJwU_tYQupoMYV*@HLW7IYFt z?0t1c_hx|}Da#JVhU={*Q<7nN`dUc=4)?Z6CyvxU)X3%j`vPv3!3$A5_cgMRD*(em zFTu6l?KAkdVy>U}8l2!xK>QifPr-|#`kTa?j%`ipQ&30XPW@Ib$}mjr7-Div72UGX z(Q5dy(2449&zI;zHT+oUTs8byXrdZ^EHqUOKNfne8h$J^S>5f~S^s6UvxXRE+=`7= b!%wYwA;J*Py7#NfPJHDwfBhUTs=$8(G5@VR diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultphoto.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultphoto.cpython-311.pyc deleted file mode 100755 index d8712fee7c5f3bf056984028b3677aa1aba6a4af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6977 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultsbutton.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultsbutton.cpython-311.pyc deleted file mode 100755 index 31bc53336a7d1031ca2276d388ddaf7af3bace92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5589 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 DL(nED diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvenue.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvenue.cpython-311.pyc deleted file mode 100755 index 52a68bf092c513414a76f88b7868930ea6c0ff7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6868 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 GxBO4L5z1!( diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvideo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvideo.cpython-311.pyc deleted file mode 100755 index b6be8916e6a199073237719fabceb966b9dc581d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7929 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputcontactmessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputcontactmessagecontent.cpython-311.pyc deleted file mode 100755 index 6e9d38e974720721309a9b5edc5042c54d301871..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2814 zcmd5;&2Jk;6rc6y+Kt<$ZBSZB8Jbe+DDje(aPa!9lW$r_R)*M<+rAteU`nVZ^IiOg#rEl#}%dsto(HnKf8@Y6vLYpaFV`VAOKw@V6EKq}E za;i0h8zsn-V|E}Mvl%dxzydy-471=6_&|3GpX-3N-Z3QS)Aq#DS3Xb zw%|HUck0y=<8u_o_wCwqo8a>z?+3z}?lz@o^DuILPDnnN&C_;Oyd?r78pO+WTq_nA zQg@6h+t<-Ip=i=|gMxg~Ym~ZSk?kHBZJ%>rEF0Y1Jz$UPglSqqu~O5J1~p1o+R$4dt^uTVCJp!uH~R)f65o zUfQTx`t>CPHUYbjTG>rREcx0tgRprE!)9giiEO?olG?8;tdKJH+v`zNKY3!E-)MM`f!t7r>u zm1$LjmtAezop;Y`My;kTGG|efmEl+fcQps%>WazrFg+)yJ8kjm%JssHt;4*?Mz)Won~uXmfaMWomV1YxDwq3Y%w9 zn%+8jYU8BV90HToLaRUY@g1LFh^L)6-H3Z}J3Bjjb$9zjKP=&wkqIsONQ+IJPd<8A z0SdV;WYd^nJhvgiXv&VOHA!7J-LhW;y0Bd-fQ`cK!Ljr>R;G`smucs< z%xqiNvkE^3DuMgqLq333m~Ee&K*di$0NL=@iX4rrErMi(^naw>zS!y`r_XM_KHNHR zBz~@Skc{M7hma#7*?Q%8D~>{f3=FoC$f@MmYxgJbzTZlrlqQD! z*qP_TbOY|oZNprHsTZ;;$G;_BLN;oaGw*}ooepa-*RH{wUxU5H$8k%016|X)v}}=s zI7|dEB0vubAHu;9v1jUgK~6s4r$9s~MFU7Hswhh93{k#Nnxwc%UTyY1TV$%)`)rbt aX7AHVj3|KRi=_F+J5R9t=^i?NYX1S+K?(Q( diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputinvoicemessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputinvoicemessagecontent.cpython-311.pyc deleted file mode 100755 index a8e4007f926f22034c2702a368b552e97b316343..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13747 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputlocationmessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputlocationmessagecontent.cpython-311.pyc deleted file mode 100755 index e78983b3154e2593d568d91b1d86a677f0faf3c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6152 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputvenuemessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputvenuemessagecontent.cpython-311.pyc deleted file mode 100755 index ef5be756221b10d937e9695842d8422a0f1f7d21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4377 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardbutton.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardbutton.py deleted file mode 100755 index 61169ca..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardbutton.py +++ /dev/null @@ -1,341 +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 InlineKeyboardButton.""" - -from typing import TYPE_CHECKING, Final, Optional, Union - -from telegram import constants -from telegram._copytextbutton import CopyTextButton -from telegram._games.callbackgame import CallbackGame -from telegram._loginurl import LoginUrl -from telegram._switchinlinequerychosenchat import SwitchInlineQueryChosenChat -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict -from telegram._webappinfo import WebAppInfo - -if TYPE_CHECKING: - from telegram import Bot - - -class InlineKeyboardButton(TelegramObject): - """This object represents one button of an inline keyboard. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text`, :attr:`url`, :attr:`login_url`, :attr:`callback_data`, - :attr:`switch_inline_query`, :attr:`switch_inline_query_current_chat`, :attr:`callback_game`, - :attr:`web_app` and :attr:`pay` are equal. - - Note: - * Exactly one of the optional fields must be used to specify type of the button. - * Mind that :attr:`callback_game` is not - working as expected. Putting a game short name in it might, but is not guaranteed to - work. - * If your bot allows for arbitrary callback data, in keyboards returned in a response - from telegram, :attr:`callback_data` may be an instance of - :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data - associated with the button was already deleted. - - .. versionadded:: 13.6 - - * Since Bot API 5.5, it's now allowed to mention users by their ID in inline keyboards. - This will only work in Telegram versions released after December 7, 2021. - Older clients will display *unsupported message*. - - Warning: - * If your bot allows your arbitrary callback data, buttons whose callback data is a - non-hashable object will become unhashable. Trying to evaluate ``hash(button)`` will - result in a :class:`TypeError`. - - .. versionchanged:: 13.6 - - * After Bot API 6.1, only ``HTTPS`` links will be allowed in :paramref:`login_url`. - - Examples: - * :any:`Inline Keyboard 1 ` - * :any:`Inline Keyboard 2 ` - - .. seealso:: :class:`telegram.InlineKeyboardMarkup` - - .. versionchanged:: 20.0 - :attr:`web_app` is considered as well when comparing objects of this type in terms of - equality. - - Args: - text (:obj:`str`): Label text on the button. - url (:obj:`str`, optional): HTTP or tg:// url to be opened when the button is pressed. - Links ``tg://user?id=`` can be used to mention a user by - their ID without using a username, if this is allowed by their privacy settings. - - .. versionchanged:: 13.9 - You can now mention a user using ``tg://user?id=``. - login_url (:class:`telegram.LoginUrl`, optional): An ``HTTPS`` URL used to automatically - authorize the user. Can be used as a replacement for the Telegram Login Widget. - - Caution: - Only ``HTTPS`` links are allowed after Bot API 6.1. - callback_data (:obj:`str` | :obj:`object`, optional): Data to be sent in a callback query - to the bot when the button is pressed, UTF-8 - :tg-const:`telegram.InlineKeyboardButton.MIN_CALLBACK_DATA`- - :tg-const:`telegram.InlineKeyboardButton.MAX_CALLBACK_DATA` bytes. - If the bot instance allows arbitrary callback data, anything can be passed. - - Tip: - The value entered here will be available in :attr:`telegram.CallbackQuery.data`. - - .. seealso:: :wiki:`Arbitrary callback_data ` - - web_app (:class:`telegram.WebAppInfo`, optional): Description of the `Web App - `_ that will be launched when the user presses - the button. The Web App will be able to send an arbitrary message on behalf of the user - using the method :meth:`~telegram.Bot.answer_web_app_query`. Available only in - private chats between a user and the bot. Not supported for messages sent on behalf of - a Telegram Business account. - - .. versionadded:: 20.0 - switch_inline_query (:obj:`str`, optional): If set, pressing the button will prompt the - user to select one of their chats, open that chat and insert the bot's username and the - specified inline query in the input field. May be empty, in which case just the bot's - username will be inserted. Not supported for messages sent on behalf of a Telegram - Business account. - - Tip: - This is similar to the parameter :paramref:`switch_inline_query_chosen_chat`, - but gives no control over which chats can be selected. - switch_inline_query_current_chat (:obj:`str`, optional): If set, pressing the button will - insert the bot's username and the specified inline query in the current chat's input - field. May be empty, in which case only the bot's username will be inserted. - - This offers a quick way for the user to open your bot in inline mode in the same chat - - good for selecting something from multiple options. Not supported in channels and for - messages sent on behalf of a Telegram Business account. - copy_text (:class:`telegram.CopyTextButton`, optional): Description of the button that - copies the specified text to the clipboard. - - .. versionadded:: 21.7 - callback_game (:class:`telegram.CallbackGame`, optional): Description of the game that will - be launched when the user presses the button - - Note: - This type of button **must** always be the first button in the first row. - pay (:obj:`bool`, optional): Specify :obj:`True`, to send a Pay button. - Substrings ``“⭐️”`` and ``“XTR”`` in the buttons's text will be replaced with a - Telegram Star icon. - - Note: - This type of button **must** always be the first button in the first row and can - only be used in invoice messages. - switch_inline_query_chosen_chat (:class:`telegram.SwitchInlineQueryChosenChat`, optional): - If set, pressing the button will prompt the user to select one of their chats of the - specified type, open that chat and insert the bot's username and the specified inline - query in the input field. Not supported for messages sent on behalf of a Telegram - Business account. - - .. versionadded:: 20.3 - - Tip: - This is similar to :paramref:`switch_inline_query`, but gives more control on - which chats can be selected. - - Caution: - The PTB team has discovered that this field works correctly only if your Telegram - client is released after April 20th 2023. - - Attributes: - text (:obj:`str`): Label text on the button. - url (:obj:`str`): Optional. HTTP or tg:// url to be opened when the button is pressed. - Links ``tg://user?id=`` can be used to mention a user by - their ID without using a username, if this is allowed by their privacy settings. - - .. versionchanged:: 13.9 - You can now mention a user using ``tg://user?id=``. - login_url (:class:`telegram.LoginUrl`): Optional. An ``HTTPS`` URL used to automatically - authorize the user. Can be used as a replacement for the Telegram Login Widget. - - Caution: - Only ``HTTPS`` links are allowed after Bot API 6.1. - callback_data (:obj:`str` | :obj:`object`): Optional. Data to be sent in a callback query - to the bot when the button is pressed, UTF-8 - :tg-const:`telegram.InlineKeyboardButton.MIN_CALLBACK_DATA`- - :tg-const:`telegram.InlineKeyboardButton.MAX_CALLBACK_DATA` bytes. - web_app (:class:`telegram.WebAppInfo`): Optional. Description of the `Web App - `_ that will be launched when the user presses - the button. The Web App will be able to send an arbitrary message on behalf of the user - using the method :meth:`~telegram.Bot.answer_web_app_query`. Available only in - private chats between a user and the bot. Not supported for messages sent on behalf of - a Telegram Business account. - - .. versionadded:: 20.0 - switch_inline_query (:obj:`str`): Optional. If set, pressing the button will prompt the - user to select one of their chats, open that chat and insert the bot's username and the - specified inline query in the input field. May be empty, in which case just the bot's - username will be inserted. Not supported for messages sent on behalf of a Telegram - Business account. - - Tip: - This is similar to the parameter :paramref:`switch_inline_query_chosen_chat`, - but gives no control over which chats can be selected. - switch_inline_query_current_chat (:obj:`str`): Optional. If set, pressing the button will - insert the bot's username and the specified inline query in the current chat's input - field. May be empty, in which case only the bot's username will be inserted. - - This offers a quick way for the user to open your bot in inline mode in the same chat - - good for selecting something from multiple options. Not supported in channels and for - messages sent on behalf of a Telegram Business account. - copy_text (:class:`telegram.CopyTextButton`): Optional. Description of the button that - copies the specified text to the clipboard. - - .. versionadded:: 21.7 - callback_game (:class:`telegram.CallbackGame`): Optional. Description of the game that will - be launched when the user presses the button. - - Note: - This type of button **must** always be the first button in the first row. - pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button. - Substrings ``“⭐️”`` and ``“XTR”`` in the buttons's text will be replaced with a - Telegram Star icon. - - Note: - This type of button **must** always be the first button in the first row and can - only be used in invoice messages. - switch_inline_query_chosen_chat (:class:`telegram.SwitchInlineQueryChosenChat`): Optional. - If set, pressing the button will prompt the user to select one of their chats of the - specified type, open that chat and insert the bot's username and the specified inline - query in the input field. Not supported for messages sent on behalf of a Telegram - Business account. - - .. versionadded:: 20.3 - - Tip: - This is similar to :attr:`switch_inline_query`, but gives more control on - which chats can be selected. - - Caution: - The PTB team has discovered that this field works correctly only if your Telegram - client is released after April 20th 2023. - """ - - __slots__ = ( - "callback_data", - "callback_game", - "copy_text", - "login_url", - "pay", - "switch_inline_query", - "switch_inline_query_chosen_chat", - "switch_inline_query_current_chat", - "text", - "url", - "web_app", - ) - - def __init__( - self, - text: str, - url: Optional[str] = None, - callback_data: Optional[Union[str, object]] = None, - switch_inline_query: Optional[str] = None, - switch_inline_query_current_chat: Optional[str] = None, - callback_game: Optional[CallbackGame] = None, - pay: Optional[bool] = None, - login_url: Optional[LoginUrl] = None, - web_app: Optional[WebAppInfo] = None, - switch_inline_query_chosen_chat: Optional[SwitchInlineQueryChosenChat] = None, - copy_text: Optional[CopyTextButton] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.text: str = text - - # Optionals - self.url: Optional[str] = url - self.login_url: Optional[LoginUrl] = login_url - self.callback_data: Optional[Union[str, object]] = callback_data - self.switch_inline_query: Optional[str] = switch_inline_query - self.switch_inline_query_current_chat: Optional[str] = switch_inline_query_current_chat - self.callback_game: Optional[CallbackGame] = callback_game - self.pay: Optional[bool] = pay - self.web_app: Optional[WebAppInfo] = web_app - self.switch_inline_query_chosen_chat: Optional[SwitchInlineQueryChosenChat] = ( - switch_inline_query_chosen_chat - ) - self.copy_text: Optional[CopyTextButton] = copy_text - self._id_attrs = () - self._set_id_attrs() - - self._freeze() - - def _set_id_attrs(self) -> None: - self._id_attrs = ( - self.text, - self.url, - self.login_url, - self.callback_data, - self.web_app, - self.switch_inline_query, - self.switch_inline_query_current_chat, - self.callback_game, - self.pay, - ) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["InlineKeyboardButton"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["login_url"] = LoginUrl.de_json(data.get("login_url"), bot) - data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot) - data["callback_game"] = CallbackGame.de_json(data.get("callback_game"), bot) - data["switch_inline_query_chosen_chat"] = SwitchInlineQueryChosenChat.de_json( - data.get("switch_inline_query_chosen_chat"), bot - ) - data["copy_text"] = CopyTextButton.de_json(data.get("copy_text"), bot) - - return super().de_json(data=data, bot=bot) - - def update_callback_data(self, callback_data: Union[str, object]) -> None: - """ - Sets :attr:`callback_data` to the passed object. Intended to be used by - :class:`telegram.ext.CallbackDataCache`. - - .. versionadded:: 13.6 - - Args: - callback_data (:class:`object`): The new callback data. - """ - with self._unfrozen(): - self.callback_data = callback_data - self._set_id_attrs() - - MIN_CALLBACK_DATA: Final[int] = constants.InlineKeyboardButtonLimit.MIN_CALLBACK_DATA - """:const:`telegram.constants.InlineKeyboardButtonLimit.MIN_CALLBACK_DATA` - - .. versionadded:: 20.0 - """ - MAX_CALLBACK_DATA: Final[int] = constants.InlineKeyboardButtonLimit.MAX_CALLBACK_DATA - """:const:`telegram.constants.InlineKeyboardButtonLimit.MAX_CALLBACK_DATA` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardmarkup.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardmarkup.py deleted file mode 100755 index 834225e..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardmarkup.py +++ /dev/null @@ -1,165 +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 InlineKeyboardMarkup.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton -from telegram._telegramobject import TelegramObject -from telegram._utils.markup import check_keyboard_type -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class InlineKeyboardMarkup(TelegramObject): - """ - This object represents an inline keyboard that appears right next to the message it belongs to. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their size of :attr:`inline_keyboard` and all the buttons are equal. - - .. figure:: https://core.telegram.org/file/464001863/110f3/I47qTXAD9Z4.120010/e0\ - ea04f66357b640ec - :align: center - - An inline keyboard on a message - - .. seealso:: - Another kind of keyboard would be the :class:`telegram.ReplyKeyboardMarkup`. - - Examples: - * :any:`Inline Keyboard 1 ` - * :any:`Inline Keyboard 2 ` - - Args: - inline_keyboard (Sequence[Sequence[:class:`telegram.InlineKeyboardButton`]]): Sequence of - button rows, each represented by a sequence of :class:`~telegram.InlineKeyboardButton` - objects. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - Attributes: - inline_keyboard (tuple[tuple[:class:`telegram.InlineKeyboardButton`]]): Tuple of - button rows, each represented by a tuple of :class:`~telegram.InlineKeyboardButton` - objects. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - """ - - __slots__ = ("inline_keyboard",) - - def __init__( - self, - inline_keyboard: Sequence[Sequence[InlineKeyboardButton]], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - if not check_keyboard_type(inline_keyboard): - raise ValueError( - "The parameter `inline_keyboard` should be a sequence of sequences of " - "InlineKeyboardButtons" - ) - # Required - self.inline_keyboard: tuple[tuple[InlineKeyboardButton, ...], ...] = tuple( - tuple(row) for row in inline_keyboard - ) - - self._id_attrs = (self.inline_keyboard,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["InlineKeyboardMarkup"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - if not data: - return None - - keyboard = [] - for row in data["inline_keyboard"]: - tmp = [] - for col in row: - btn = InlineKeyboardButton.de_json(col, bot) - if btn: - tmp.append(btn) - keyboard.append(tmp) - - return cls(keyboard) - - @classmethod - def from_button(cls, button: InlineKeyboardButton, **kwargs: object) -> "InlineKeyboardMarkup": - """Shortcut for:: - - InlineKeyboardMarkup([[button]], **kwargs) - - Return an InlineKeyboardMarkup from a single InlineKeyboardButton - - Args: - button (:class:`telegram.InlineKeyboardButton`): The button to use in the markup - - """ - return cls([[button]], **kwargs) # type: ignore[arg-type] - - @classmethod - def from_row( - cls, button_row: Sequence[InlineKeyboardButton], **kwargs: object - ) -> "InlineKeyboardMarkup": - """Shortcut for:: - - InlineKeyboardMarkup([button_row], **kwargs) - - Return an InlineKeyboardMarkup from a single row of InlineKeyboardButtons - - Args: - button_row (Sequence[:class:`telegram.InlineKeyboardButton`]): The button to use - in the markup - - .. versionchanged:: 20.0 - |sequenceargs| - - """ - return cls([button_row], **kwargs) # type: ignore[arg-type] - - @classmethod - def from_column( - cls, button_column: Sequence[InlineKeyboardButton], **kwargs: object - ) -> "InlineKeyboardMarkup": - """Shortcut for:: - - InlineKeyboardMarkup([[button] for button in button_column], **kwargs) - - Return an InlineKeyboardMarkup from a single column of InlineKeyboardButtons - - Args: - button_column (Sequence[:class:`telegram.InlineKeyboardButton`]): The button to use - in the markup - - .. versionchanged:: 20.0 - |sequenceargs| - - """ - button_grid = [[button] for button in button_column] - return cls(button_grid, **kwargs) # type: ignore[arg-type] diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequery.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequery.py deleted file mode 100755 index dd6b957..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequery.py +++ /dev/null @@ -1,228 +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 InlineQuery.""" - -from collections.abc import Sequence -from typing import TYPE_CHECKING, Callable, Final, Optional, Union - -from telegram import constants -from telegram._files.location import Location -from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton -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, InlineQueryResult - - -class InlineQuery(TelegramObject): - """ - This object represents an incoming inline query. When the user sends an empty query, your bot - could return some default or trending results. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - .. figure:: https://core.telegram.org/file/464001466/10e4a/r4FKyQ7gw5g.134366/f2\ - 606a53d683374703 - :align: center - - Inline queries on Telegram - - .. seealso:: - The :class:`telegram.InlineQueryResult` classes represent the media the user can choose - from (see above figure). - - Note: - In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - - .. versionchanged:: 20.0 - The following are now keyword-only arguments in Bot methods: - ``{read, write, connect, pool}_timeout``, :paramref:`answer.api_kwargs`, - ``auto_pagination``. Use a named argument for those, - and notice that some positional arguments changed position as a result. - - Args: - id (:obj:`str`): Unique identifier for this query. - from_user (:class:`telegram.User`): Sender. - query (:obj:`str`): Text of the query (up to - :tg-const:`telegram.InlineQuery.MAX_QUERY_LENGTH` characters). - offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot. - chat_type (:obj:`str`, optional): Type of the chat, from which the inline query was sent. - Can be either :tg-const:`telegram.Chat.SENDER` for a private chat with the inline query - sender, :tg-const:`telegram.Chat.PRIVATE`, :tg-const:`telegram.Chat.GROUP`, - :tg-const:`telegram.Chat.SUPERGROUP` or :tg-const:`telegram.Chat.CHANNEL`. The chat - type should be always known for requests sent from official clients and most - third-party clients, unless the request was sent from a secret chat. - - .. versionadded:: 13.5 - location (:class:`telegram.Location`, optional): Sender location, only for bots that - request user location. - - Attributes: - id (:obj:`str`): Unique identifier for this query. - from_user (:class:`telegram.User`): Sender. - query (:obj:`str`): Text of the query (up to - :tg-const:`telegram.InlineQuery.MAX_QUERY_LENGTH` characters). - offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot. - chat_type (:obj:`str`): Optional. Type of the chat, from which the inline query was sent. - Can be either :tg-const:`telegram.Chat.SENDER` for a private chat with the inline query - sender, :tg-const:`telegram.Chat.PRIVATE`, :tg-const:`telegram.Chat.GROUP`, - :tg-const:`telegram.Chat.SUPERGROUP` or :tg-const:`telegram.Chat.CHANNEL`. The chat - type should be always known for requests sent from official clients and most - third-party clients, unless the request was sent from a secret chat. - - .. versionadded:: 13.5 - location (:class:`telegram.Location`): Optional. Sender location, only for bots that - request user location. - - """ - - __slots__ = ("chat_type", "from_user", "id", "location", "offset", "query") - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - from_user: User, - query: str, - offset: str, - location: Optional[Location] = None, - chat_type: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.id: str = id - self.from_user: User = from_user - self.query: str = query - self.offset: str = offset - - # Optional - self.location: Optional[Location] = location - self.chat_type: Optional[str] = chat_type - - self._id_attrs = (self.id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["InlineQuery"]: - """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["location"] = Location.de_json(data.get("location"), bot) - - return super().de_json(data=data, bot=bot) - - async def answer( - self, - 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, - auto_pagination: bool = False, - 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_inline_query( - update.inline_query.id, - *args, - current_offset=self.offset if auto_pagination else None, - **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.answer_inline_query`. - - .. versionchanged:: 20.0 - Raises :class:`ValueError` instead of :class:`TypeError`. - - Keyword Args: - auto_pagination (:obj:`bool`, optional): If set to :obj:`True`, :attr:`offset` will be - passed as - :paramref:`current_offset ` to - :meth:`telegram.Bot.answer_inline_query`. - Defaults to :obj:`False`. - - Raises: - ValueError: If both :paramref:`~telegram.Bot.answer_inline_query.current_offset` and - :paramref:`auto_pagination` are supplied. - """ - if current_offset and auto_pagination: - raise ValueError("current_offset and auto_pagination are mutually exclusive!") - return await self.get_bot().answer_inline_query( - inline_query_id=self.id, - current_offset=self.offset if auto_pagination else current_offset, - results=results, - cache_time=cache_time, - is_personal=is_personal, - next_offset=next_offset, - button=button, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - MAX_RESULTS: Final[int] = constants.InlineQueryLimit.RESULTS - """:const:`telegram.constants.InlineQueryLimit.RESULTS` - - .. versionadded:: 13.2 - """ - MIN_SWITCH_PM_TEXT_LENGTH: Final[int] = constants.InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH - """:const:`telegram.constants.InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_SWITCH_PM_TEXT_LENGTH: Final[int] = constants.InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH - """:const:`telegram.constants.InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_OFFSET_LENGTH: Final[int] = constants.InlineQueryLimit.MAX_OFFSET_LENGTH - """:const:`telegram.constants.InlineQueryLimit.MAX_OFFSET_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_QUERY_LENGTH: Final[int] = constants.InlineQueryLimit.MAX_QUERY_LENGTH - """:const:`telegram.constants.InlineQueryLimit.MAX_QUERY_LENGTH` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresult.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresult.py deleted file mode 100755 index 67ce6e4..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresult.py +++ /dev/null @@ -1,79 +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 InlineQueryResult.""" - -from typing import Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.types import JSONDict - - -class InlineQueryResult(TelegramObject): - """Baseclass for the InlineQueryResult* classes. - - 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: - All URLs passed in inline query results will be available to end users and therefore must - be assumed to be *public*. - - Examples: - :any:`Inline Bot ` - - Args: - type (:obj:`str`): Type of the result. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - - Attributes: - type (:obj:`str`): Type of the result. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - - """ - - __slots__ = ("id", "type") - - def __init__(self, type: str, id: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.type: str = enum.get_member(constants.InlineQueryResultType, type, type) - self.id: str = str(id) - - self._id_attrs = (self.id,) - - self._freeze() - - MIN_ID_LENGTH: Final[int] = constants.InlineQueryResultLimit.MIN_ID_LENGTH - """:const:`telegram.constants.InlineQueryResultLimit.MIN_ID_LENGTH` - - .. versionadded:: 20.0 - """ - MAX_ID_LENGTH: Final[int] = constants.InlineQueryResultLimit.MAX_ID_LENGTH - """:const:`telegram.constants.InlineQueryResultLimit.MAX_ID_LENGTH` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultarticle.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultarticle.py deleted file mode 100755 index 5fcee85..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultarticle.py +++ /dev/null @@ -1,149 +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 that represent Telegram InlineQueryResultArticle.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn -from telegram.constants import InlineQueryResultType -from telegram.warnings import PTBDeprecationWarning - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultArticle(InlineQueryResult): - """This object represents a Telegram InlineQueryResultArticle. - - Examples: - :any:`Inline Bot ` - - .. versionchanged:: 20.5 - Removed the deprecated arguments and attributes ``thumb_*``. - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - title (:obj:`str`): Title of the result. - input_message_content (:class:`telegram.InputMessageContent`): Content of the message to - be sent. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - url (:obj:`str`, optional): URL of the result. - hide_url (:obj:`bool`, optional): Pass :obj:`True`, if you don't want the URL to be shown - in the message. - - .. deprecated:: 21.10 - This attribute will be removed in future PTB versions. Pass an empty string as URL - instead. - description (:obj:`str`, optional): Short description of the result. - thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`, optional): Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`, optional): Thumbnail height. - - .. versionadded:: 20.2 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.ARTICLE`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - title (:obj:`str`): Title of the result. - input_message_content (:class:`telegram.InputMessageContent`): Content of the message to - be sent. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - url (:obj:`str`): Optional. URL of the result. - hide_url (:obj:`bool`): Optional. Pass :obj:`True`, if you don't want the URL to be shown - in the message. - - .. deprecated:: 21.10 - This attribute will be removed in future PTB versions. Pass an empty string as URL - instead. - description (:obj:`str`): Optional. Short description of the result. - thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`): Optional. Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`): Optional. Thumbnail height. - - .. versionadded:: 20.2 - - """ - - __slots__ = ( - "description", - "hide_url", - "input_message_content", - "reply_markup", - "thumbnail_height", - "thumbnail_url", - "thumbnail_width", - "title", - "url", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - title: str, - input_message_content: "InputMessageContent", - reply_markup: Optional[InlineKeyboardMarkup] = None, - url: Optional[str] = None, - hide_url: Optional[bool] = None, - description: Optional[str] = None, - thumbnail_url: Optional[str] = None, - thumbnail_width: Optional[int] = None, - thumbnail_height: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.ARTICLE, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.title: str = title - self.input_message_content: InputMessageContent = input_message_content - - # Optional - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.url: Optional[str] = url - if hide_url is not None: - warn( - PTBDeprecationWarning( - "21.10", - "The argument `hide_url` will be removed in future PTB" - "versions. Pass an empty string as URL instead.", - ), - stacklevel=2, - ) - self.hide_url: Optional[bool] = hide_url - self.description: Optional[str] = description - self.thumbnail_url: Optional[str] = thumbnail_url - self.thumbnail_width: Optional[int] = thumbnail_width - self.thumbnail_height: Optional[int] = thumbnail_height diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultaudio.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultaudio.py deleted file mode 100755 index 8e3376a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultaudio.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 classes that represent Telegram InlineQueryResultAudio.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultAudio(InlineQueryResult): - """ - Represents a link to an mp3 audio file. By default, this audio file will be sent by the user. - Alternatively, you can use :attr:`input_message_content` to send a message with the specified - content instead of the audio. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - audio_url (:obj:`str`): A valid URL for the audio file. - title (:obj:`str`): Title. - performer (:obj:`str`, optional): Performer. - audio_duration (:obj:`str`, optional): Audio duration in seconds. - caption (:obj:`str`, optional): Caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the audio. - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.AUDIO`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - audio_url (:obj:`str`): A valid URL for the audio file. - title (:obj:`str`): Title. - performer (:obj:`str`): Optional. Performer. - audio_duration (:obj:`str`): Optional. Audio duration in seconds. - caption (:obj:`str`): Optional. Caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the audio. - - """ - - __slots__ = ( - "audio_duration", - "audio_url", - "caption", - "caption_entities", - "input_message_content", - "parse_mode", - "performer", - "reply_markup", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - audio_url: str, - title: str, - performer: Optional[str] = None, - audio_duration: Optional[int] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.AUDIO, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.audio_url: str = audio_url - self.title: str = title - - # Optionals - self.performer: Optional[str] = performer - self.audio_duration: Optional[int] = audio_duration - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedaudio.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedaudio.py deleted file mode 100755 index f1f75a1..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedaudio.py +++ /dev/null @@ -1,116 +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 that represent Telegram InlineQueryResultCachedAudio.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultCachedAudio(InlineQueryResult): - """ - Represents a link to an mp3 audio file stored on the Telegram servers. By default, this audio - file will be sent by the user. Alternatively, you can use :attr:`input_message_content` to - send a message with the specified content instead of the audio. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - audio_file_id (:obj:`str`): A valid file identifier for the audio file. - caption (:obj:`str`, optional): Caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the audio. - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.AUDIO`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - audio_file_id (:obj:`str`): A valid file identifier for the audio file. - caption (:obj:`str`): Optional. Caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the audio. - - """ - - __slots__ = ( - "audio_file_id", - "caption", - "caption_entities", - "input_message_content", - "parse_mode", - "reply_markup", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - audio_file_id: str, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.AUDIO, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.audio_file_id: str = audio_file_id - - # Optionals - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcacheddocument.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcacheddocument.py deleted file mode 100755 index af2e6ef..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcacheddocument.py +++ /dev/null @@ -1,126 +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 that represent Telegram InlineQueryResultCachedDocument.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultCachedDocument(InlineQueryResult): - """ - Represents a link to a file stored on the Telegram servers. By default, this file will be sent - by the user with an optional caption. Alternatively, you can use :attr:`input_message_content` - to send a message with the specified content instead of the file. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - title (:obj:`str`): Title for the result. - document_file_id (:obj:`str`): A valid file identifier for the file. - description (:obj:`str`, optional): Short description of the result. - caption (:obj:`str`, optional): Caption of the document to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the file. - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.DOCUMENT`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - title (:obj:`str`): Title for the result. - document_file_id (:obj:`str`): A valid file identifier for the file. - description (:obj:`str`): Optional. Short description of the result. - caption (:obj:`str`): Optional. Caption of the document to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the file. - - """ - - __slots__ = ( - "caption", - "caption_entities", - "description", - "document_file_id", - "input_message_content", - "parse_mode", - "reply_markup", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - title: str, - document_file_id: str, - description: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.DOCUMENT, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.title: str = title - self.document_file_id: str = document_file_id - - # Optionals - self.description: Optional[str] = description - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedgif.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedgif.py deleted file mode 100755 index f682ec0..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedgif.py +++ /dev/null @@ -1,131 +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 that represent Telegram InlineQueryResultCachedGif.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultCachedGif(InlineQueryResult): - """ - Represents a link to an animated GIF file stored on the Telegram servers. By default, this - animated GIF file will be sent by the user with an optional caption. Alternatively, you can - use :attr:`input_message_content` to send a message with specified content instead of - the animation. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - gif_file_id (:obj:`str`): A valid file identifier for the GIF file. - title (:obj:`str`, optional): Title for the result. - caption (:obj:`str`, optional): Caption of the GIF file to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the gif. - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.GIF`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - gif_file_id (:obj:`str`): A valid file identifier for the GIF file. - title (:obj:`str`): Optional. Title for the result. - caption (:obj:`str`): Optional. Caption of the GIF file to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the gif. - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - - """ - - __slots__ = ( - "caption", - "caption_entities", - "gif_file_id", - "input_message_content", - "parse_mode", - "reply_markup", - "show_caption_above_media", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - gif_file_id: str, - title: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.GIF, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.gif_file_id: str = gif_file_id - - # Optionals - self.title: Optional[str] = title - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.show_caption_above_media: Optional[bool] = show_caption_above_media diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedmpeg4gif.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedmpeg4gif.py deleted file mode 100755 index 6dc7e55..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedmpeg4gif.py +++ /dev/null @@ -1,131 +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 that represent Telegram InlineQueryResultMpeg4Gif.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): - """ - Represents a link to a video animation (H.264/MPEG-4 AVC video without sound) stored on the - Telegram servers. By default, this animated MPEG-4 file will be sent by the user with an - optional caption. Alternatively, you can use :attr:`input_message_content` to send a message - with the specified content instead of the animation. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - mpeg4_file_id (:obj:`str`): A valid file identifier for the MP4 file. - title (:obj:`str`, optional): Title for the result. - caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the MPEG-4 file. - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.MPEG4GIF`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - mpeg4_file_id (:obj:`str`): A valid file identifier for the MP4 file. - title (:obj:`str`): Optional. Title for the result. - caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the MPEG-4 file. - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - - """ - - __slots__ = ( - "caption", - "caption_entities", - "input_message_content", - "mpeg4_file_id", - "parse_mode", - "reply_markup", - "show_caption_above_media", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - mpeg4_file_id: str, - title: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.MPEG4GIF, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.mpeg4_file_id: str = mpeg4_file_id - - # Optionals - self.title: Optional[str] = title - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.show_caption_above_media: Optional[bool] = show_caption_above_media diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedphoto.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedphoto.py deleted file mode 100755 index adf8ea6..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedphoto.py +++ /dev/null @@ -1,136 +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 that represent Telegram InlineQueryResultPhoto""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultCachedPhoto(InlineQueryResult): - """ - Represents a link to a photo stored on the Telegram servers. By default, this photo will be - sent by the user with an optional caption. Alternatively, you can use - :attr:`input_message_content` to send a message with the specified content instead - of the photo. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - photo_file_id (:obj:`str`): A valid file identifier of the photo. - title (:obj:`str`, optional): Title for the result. - description (:obj:`str`, optional): Short description of the result. - caption (:obj:`str`, optional): Caption of the photo to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the photo. - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.PHOTO`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - photo_file_id (:obj:`str`): A valid file identifier of the photo. - title (:obj:`str`): Optional. Title for the result. - description (:obj:`str`): Optional. Short description of the result. - caption (:obj:`str`): Optional. Caption of the photo to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the photo. - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - - """ - - __slots__ = ( - "caption", - "caption_entities", - "description", - "input_message_content", - "parse_mode", - "photo_file_id", - "reply_markup", - "show_caption_above_media", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - photo_file_id: str, - title: Optional[str] = None, - description: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.PHOTO, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.photo_file_id: str = photo_file_id - - # Optionals - self.title: Optional[str] = title - self.description: Optional[str] = description - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.show_caption_above_media: Optional[bool] = show_caption_above_media diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedsticker.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedsticker.py deleted file mode 100755 index 0dd8c55..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedsticker.py +++ /dev/null @@ -1,81 +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 that represent Telegram InlineQueryResultCachedSticker.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._utils.types import JSONDict -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultCachedSticker(InlineQueryResult): - """ - Represents a link to a sticker stored on the Telegram servers. By default, this sticker will - be sent by the user. Alternatively, you can use :attr:`input_message_content` to send a - message with the specified content instead of the sticker. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - sticker_file_id (:obj:`str`): A valid file identifier of the sticker. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the sticker. - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.STICKER`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - sticker_file_id (:obj:`str`): A valid file identifier of the sticker. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the sticker. - - """ - - __slots__ = ("input_message_content", "reply_markup", "sticker_file_id") - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - sticker_file_id: str, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.STICKER, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.sticker_file_id: str = sticker_file_id - - # Optionals - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvideo.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvideo.py deleted file mode 100755 index 3595330..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvideo.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/]. -"""This module contains the classes that represent Telegram InlineQueryResultCachedVideo.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultCachedVideo(InlineQueryResult): - """ - Represents a link to a video file stored on the Telegram servers. By default, this video file - will be sent by the user with an optional caption. Alternatively, you can use - :attr:`input_message_content` to send a message with the specified content instead - of the video. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - video_file_id (:obj:`str`): A valid file identifier for the video file. - title (:obj:`str`): Title for the result. - description (:obj:`str`, optional): Short description of the result. - caption (:obj:`str`, optional): Caption of the video to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the video. - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VIDEO`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - video_file_id (:obj:`str`): A valid file identifier for the video file. - title (:obj:`str`): Title for the result. - description (:obj:`str`): Optional. Short description of the result. - caption (:obj:`str`): Optional. Caption of the video to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the video. - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - - """ - - __slots__ = ( - "caption", - "caption_entities", - "description", - "input_message_content", - "parse_mode", - "reply_markup", - "show_caption_above_media", - "title", - "video_file_id", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - video_file_id: str, - title: str, - description: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.VIDEO, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.video_file_id: str = video_file_id - self.title: str = title - - # Optionals - self.description: Optional[str] = description - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.show_caption_above_media: Optional[bool] = show_caption_above_media diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvoice.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvoice.py deleted file mode 100755 index 139fdab..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvoice.py +++ /dev/null @@ -1,121 +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 that represent Telegram InlineQueryResultCachedVoice.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultCachedVoice(InlineQueryResult): - """ - Represents a link to a voice message stored on the Telegram servers. By default, this voice - message will be sent by the user. Alternatively, you can use :attr:`input_message_content` to - send a message with the specified content instead of the voice message. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - voice_file_id (:obj:`str`): A valid file identifier for the voice message. - title (:obj:`str`): Voice message title. - caption (:obj:`str`, optional): Caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |captionentitiesattr| - - .. versionchanged:: 20.0 - |sequenceclassargs| - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the voice message. - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VOICE`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - voice_file_id (:obj:`str`): A valid file identifier for the voice message. - title (:obj:`str`): Voice message title. - caption (:obj:`str`): Optional. Caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the voice message. - - """ - - __slots__ = ( - "caption", - "caption_entities", - "input_message_content", - "parse_mode", - "reply_markup", - "title", - "voice_file_id", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - voice_file_id: str, - title: str, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.VOICE, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.voice_file_id: str = voice_file_id - self.title: str = title - - # Optionals - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcontact.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcontact.py deleted file mode 100755 index 7ededbb..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcontact.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 classes that represent Telegram InlineQueryResultContact.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._utils.types import JSONDict -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultContact(InlineQueryResult): - """ - Represents a contact with a phone number. By default, this contact will be sent by the user. - Alternatively, you can use :attr:`input_message_content` to send a message with the specified - content instead of the contact. - - .. versionchanged:: 20.5 - |removed_thumb_wildcard_note| - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`, optional): Contact's last name. - vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, - 0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the contact. - thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`, optional): Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`, optional): Thumbnail height. - - .. versionadded:: 20.2 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.CONTACT`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`): Optional. Contact's last name. - vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard, - 0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the contact. - thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`): Optional. Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`): Optional. Thumbnail height. - - .. versionadded:: 20.2 - - """ - - __slots__ = ( - "first_name", - "input_message_content", - "last_name", - "phone_number", - "reply_markup", - "thumbnail_height", - "thumbnail_url", - "thumbnail_width", - "vcard", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - phone_number: str, - first_name: str, - last_name: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - vcard: Optional[str] = None, - thumbnail_url: Optional[str] = None, - thumbnail_width: Optional[int] = None, - thumbnail_height: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.CONTACT, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.phone_number: str = phone_number - self.first_name: str = first_name - - # Optionals - self.last_name: Optional[str] = last_name - self.vcard: Optional[str] = vcard - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.thumbnail_url: Optional[str] = thumbnail_url - self.thumbnail_width: Optional[int] = thumbnail_width - self.thumbnail_height: Optional[int] = thumbnail_height diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultdocument.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultdocument.py deleted file mode 100755 index e7114ef..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultdocument.py +++ /dev/null @@ -1,165 +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 that represent Telegram InlineQueryResultDocument""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultDocument(InlineQueryResult): - """ - Represents a link to a file. By default, this file will be sent by the user with an optional - caption. Alternatively, you can use :attr:`input_message_content` to send a message with the - specified content instead of the file. Currently, only .PDF and .ZIP files can be sent - using this method. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_wildcard_note| - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - title (:obj:`str`): Title for the result. - caption (:obj:`str`, optional): Caption of the document to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - document_url (:obj:`str`): A valid URL for the file. - mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf" - or "application/zip". - description (:obj:`str`, optional): Short description of the result. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the file. - thumbnail_url (:obj:`str`, optional): URL of the thumbnail (JPEG only) for the file. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`, optional): Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`, optional): Thumbnail height. - - .. versionadded:: 20.2 - - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.DOCUMENT`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - title (:obj:`str`): Title for the result. - caption (:obj:`str`): Optional. Caption of the document to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - document_url (:obj:`str`): A valid URL for the file. - mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf" - or "application/zip". - description (:obj:`str`): Optional. Short description of the result. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the file. - thumbnail_url (:obj:`str`): Optional. URL of the thumbnail (JPEG only) for the file. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`): Optional. Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`): Optional. Thumbnail height. - - .. versionadded:: 20.2 - - """ - - __slots__ = ( - "caption", - "caption_entities", - "description", - "document_url", - "input_message_content", - "mime_type", - "parse_mode", - "reply_markup", - "thumbnail_height", - "thumbnail_url", - "thumbnail_width", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - document_url: str, - title: str, - mime_type: str, - caption: Optional[str] = None, - description: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - thumbnail_url: Optional[str] = None, - thumbnail_width: Optional[int] = None, - thumbnail_height: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.DOCUMENT, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.document_url: str = document_url - self.title: str = title - self.mime_type: str = mime_type - - # Optionals - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.description: Optional[str] = description - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.thumbnail_url: Optional[str] = thumbnail_url - self.thumbnail_width: Optional[int] = thumbnail_width - self.thumbnail_height: Optional[int] = thumbnail_height diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgame.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgame.py deleted file mode 100755 index 27b12c8..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgame.py +++ /dev/null @@ -1,66 +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 that represent Telegram InlineQueryResultGame.""" -from typing import Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._utils.types import JSONDict -from telegram.constants import InlineQueryResultType - - -class InlineQueryResultGame(InlineQueryResult): - """Represents a :class:`telegram.Game`. - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - game_short_name (:obj:`str`): Short name of the game. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.GAME`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - game_short_name (:obj:`str`): Short name of the game. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - - """ - - __slots__ = ("game_short_name", "reply_markup") - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - game_short_name: str, - reply_markup: Optional[InlineKeyboardMarkup] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.GAME, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.id: str = id - self.game_short_name: str = game_short_name - - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgif.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgif.py deleted file mode 100755 index f454f44..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgif.py +++ /dev/null @@ -1,174 +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 that represent Telegram InlineQueryResultGif.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultGif(InlineQueryResult): - """ - Represents a link to an animated GIF file. By default, this animated GIF file will be sent by - the user with optional caption. Alternatively, you can use :attr:`input_message_content` to - send a message with the specified content instead of the animation. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_wildcard_note| - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - gif_url (:obj:`str`): A valid URL for the GIF file. File size must not exceed 1MB. - gif_width (:obj:`int`, optional): Width of the GIF. - gif_height (:obj:`int`, optional): Height of the GIF. - gif_duration (:obj:`int`, optional): Duration of the GIF in seconds. - thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) - thumbnail for the result. - - .. versionadded:: 20.2 - - ..versionchanged:: 20.5 - |thumbnail_url_mandatory| - - thumbnail_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of - ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``. - - .. versionadded:: 20.2 - title (:obj:`str`, optional): Title for the result. - caption (:obj:`str`, optional): Caption of the GIF file to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the GIF animation. - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.GIF`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - gif_url (:obj:`str`): A valid URL for the GIF file. File size must not exceed 1MB. - gif_width (:obj:`int`): Optional. Width of the GIF. - gif_height (:obj:`int`): Optional. Height of the GIF. - gif_duration (:obj:`int`): Optional. Duration of the GIF in seconds. - thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail - for the result. - - .. versionadded:: 20.2 - thumbnail_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of - ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``. - - .. versionadded:: 20.2 - title (:obj:`str`): Optional. Title for the result. - caption (:obj:`str`): Optional. Caption of the GIF file to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the GIF animation. - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - - """ - - __slots__ = ( - "caption", - "caption_entities", - "gif_duration", - "gif_height", - "gif_url", - "gif_width", - "input_message_content", - "parse_mode", - "reply_markup", - "show_caption_above_media", - "thumbnail_mime_type", - "thumbnail_url", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - gif_url: str, - thumbnail_url: str, - gif_width: Optional[int] = None, - gif_height: Optional[int] = None, - title: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - gif_duration: Optional[int] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - thumbnail_mime_type: Optional[str] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.GIF, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.gif_url: str = gif_url - self.thumbnail_url: str = thumbnail_url - - # Optionals - self.gif_width: Optional[int] = gif_width - self.gif_height: Optional[int] = gif_height - self.gif_duration: Optional[int] = gif_duration - self.title: Optional[str] = title - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.thumbnail_mime_type: Optional[str] = thumbnail_mime_type - self.show_caption_above_media: Optional[bool] = show_caption_above_media diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultlocation.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultlocation.py deleted file mode 100755 index 0103553..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultlocation.py +++ /dev/null @@ -1,207 +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 that represent Telegram InlineQueryResultLocation.""" - -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultLocation(InlineQueryResult): - """ - Represents a location on a map. By default, the location will be sent by the user. - Alternatively, you can use :attr:`input_message_content` to send a message with the specified - content instead of the location. - - .. versionchanged:: 20.5 - |removed_thumb_wildcard_note| - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - latitude (:obj:`float`): Location latitude in degrees. - longitude (:obj:`float`): Location longitude in degrees. - title (:obj:`str`): Location title. - horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, - measured in meters; 0- - :tg-const:`telegram.InlineQueryResultLocation.HORIZONTAL_ACCURACY`. - live_period (:obj:`int`, optional): Period in seconds for which the location will be - updated, should be between - :tg-const:`telegram.InlineQueryResultLocation.MIN_LIVE_PERIOD` and - :tg-const:`telegram.InlineQueryResultLocation.MAX_LIVE_PERIOD`. - heading (:obj:`int`, optional): For live locations, a direction in which the user is - moving, in degrees. Must be between - :tg-const:`telegram.InlineQueryResultLocation.MIN_HEADING` and - :tg-const:`telegram.InlineQueryResultLocation.MAX_HEADING` if specified. - proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance - for proximity alerts about approaching another chat member, in meters. Must be - between :tg-const:`telegram.InlineQueryResultLocation.MIN_PROXIMITY_ALERT_RADIUS` - and :tg-const:`telegram.InlineQueryResultLocation.MAX_PROXIMITY_ALERT_RADIUS` - if specified. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the location. - thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`, optional): Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`, optional): Thumbnail height. - - .. versionadded:: 20.2 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.LOCATION`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - latitude (:obj:`float`): Location latitude in degrees. - longitude (:obj:`float`): Location longitude in degrees. - title (:obj:`str`): Location title. - horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, - measured in meters; 0- - :tg-const:`telegram.InlineQueryResultLocation.HORIZONTAL_ACCURACY`. - live_period (:obj:`int`): Optional. Period in seconds for which the location will be - updated, should be between - :tg-const:`telegram.InlineQueryResultLocation.MIN_LIVE_PERIOD` and - :tg-const:`telegram.InlineQueryResultLocation.MAX_LIVE_PERIOD` or - :tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` for live - locations that can be edited indefinitely. - heading (:obj:`int`): Optional. For live locations, a direction in which the user is - moving, in degrees. Must be between - :tg-const:`telegram.InlineQueryResultLocation.MIN_HEADING` and - :tg-const:`telegram.InlineQueryResultLocation.MAX_HEADING` if specified. - proximity_alert_radius (:obj:`int`): Optional. For live locations, a maximum distance - for proximity alerts about approaching another chat member, in meters. Must be - between :tg-const:`telegram.InlineQueryResultLocation.MIN_PROXIMITY_ALERT_RADIUS` - and :tg-const:`telegram.InlineQueryResultLocation.MAX_PROXIMITY_ALERT_RADIUS` - if specified. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the location. - thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`): Optional. Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`): Optional. Thumbnail height. - - .. versionadded:: 20.2 - - """ - - __slots__ = ( - "heading", - "horizontal_accuracy", - "input_message_content", - "latitude", - "live_period", - "longitude", - "proximity_alert_radius", - "reply_markup", - "thumbnail_height", - "thumbnail_url", - "thumbnail_width", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - latitude: float, - longitude: float, - title: str, - live_period: Optional[int] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - horizontal_accuracy: Optional[float] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - thumbnail_url: Optional[str] = None, - thumbnail_width: Optional[int] = None, - thumbnail_height: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(constants.InlineQueryResultType.LOCATION, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.latitude: float = latitude - self.longitude: float = longitude - self.title: str = title - - # Optionals - self.live_period: Optional[int] = live_period - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.thumbnail_url: Optional[str] = thumbnail_url - self.thumbnail_width: Optional[int] = thumbnail_width - self.thumbnail_height: Optional[int] = thumbnail_height - self.horizontal_accuracy: Optional[float] = horizontal_accuracy - self.heading: Optional[int] = heading - self.proximity_alert_radius: Optional[int] = ( - int(proximity_alert_radius) if proximity_alert_radius else None - ) - - HORIZONTAL_ACCURACY: Final[int] = constants.LocationLimit.HORIZONTAL_ACCURACY - """:const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY` - - .. versionadded:: 20.0 - """ - MIN_HEADING: Final[int] = constants.LocationLimit.MIN_HEADING - """:const:`telegram.constants.LocationLimit.MIN_HEADING` - - .. versionadded:: 20.0 - """ - MAX_HEADING: Final[int] = constants.LocationLimit.MAX_HEADING - """:const:`telegram.constants.LocationLimit.MAX_HEADING` - - .. versionadded:: 20.0 - """ - MIN_LIVE_PERIOD: Final[int] = constants.LocationLimit.MIN_LIVE_PERIOD - """:const:`telegram.constants.LocationLimit.MIN_LIVE_PERIOD` - - .. versionadded:: 20.0 - """ - MAX_LIVE_PERIOD: Final[int] = constants.LocationLimit.MAX_LIVE_PERIOD - """:const:`telegram.constants.LocationLimit.MAX_LIVE_PERIOD` - - .. versionadded:: 20.0 - """ - MIN_PROXIMITY_ALERT_RADIUS: Final[int] = constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS - """:const:`telegram.constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS` - - .. versionadded:: 20.0 - """ - MAX_PROXIMITY_ALERT_RADIUS: Final[int] = constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS - """:const:`telegram.constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultmpeg4gif.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultmpeg4gif.py deleted file mode 100755 index ee2ed79..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultmpeg4gif.py +++ /dev/null @@ -1,176 +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 that represent Telegram InlineQueryResultMpeg4Gif.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultMpeg4Gif(InlineQueryResult): - """ - Represents a link to a video animation (H.264/MPEG-4 AVC video without sound). By default, this - animated MPEG-4 file will be sent by the user with optional caption. Alternatively, you can - use :attr:`input_message_content` to send a message with the specified content instead of the - animation. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_wildcard_note| - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - mpeg4_url (:obj:`str`): A valid URL for the MP4 file. File size must not exceed 1MB. - mpeg4_width (:obj:`int`, optional): Video width. - mpeg4_height (:obj:`int`, optional): Video height. - mpeg4_duration (:obj:`int`, optional): Video duration in seconds. - thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) - thumbnail for the result. - - .. versionadded:: 20.2 - - ..versionchanged:: 20.5 - |thumbnail_url_mandatory| - - thumbnail_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of - ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``. - - .. versionadded:: 20.2 - title (:obj:`str`, optional): Title for the result. - caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |captionentitiesattr| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the video animation. - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.MPEG4GIF`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - mpeg4_url (:obj:`str`): A valid URL for the MP4 file. File size must not exceed 1MB. - mpeg4_width (:obj:`int`): Optional. Video width. - mpeg4_height (:obj:`int`): Optional. Video height. - mpeg4_duration (:obj:`int`): Optional. Video duration in seconds. - thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail - for the result. - - .. versionadded:: 20.2 - thumbnail_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of - ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``. - - .. versionadded:: 20.2 - title (:obj:`str`): Optional. Title for the result. - caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the video animation. - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - """ - - __slots__ = ( - "caption", - "caption_entities", - "input_message_content", - "mpeg4_duration", - "mpeg4_height", - "mpeg4_url", - "mpeg4_width", - "parse_mode", - "reply_markup", - "show_caption_above_media", - "thumbnail_mime_type", - "thumbnail_url", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - mpeg4_url: str, - thumbnail_url: str, - mpeg4_width: Optional[int] = None, - mpeg4_height: Optional[int] = None, - title: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - mpeg4_duration: Optional[int] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - thumbnail_mime_type: Optional[str] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.MPEG4GIF, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.mpeg4_url: str = mpeg4_url - self.thumbnail_url: str = thumbnail_url - - # Optional - self.mpeg4_width: Optional[int] = mpeg4_width - self.mpeg4_height: Optional[int] = mpeg4_height - self.mpeg4_duration: Optional[int] = mpeg4_duration - self.title: Optional[str] = title - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.thumbnail_mime_type: Optional[str] = thumbnail_mime_type - self.show_caption_above_media: Optional[bool] = show_caption_above_media diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultphoto.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultphoto.py deleted file mode 100755 index e4556d6..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultphoto.py +++ /dev/null @@ -1,161 +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 that represent Telegram InlineQueryResultPhoto.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultPhoto(InlineQueryResult): - """ - Represents a link to a photo. By default, this photo will be sent by the user with optional - caption. Alternatively, you can use :attr:`input_message_content` to send a message with the - specified content instead of the photo. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_url_note| - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - photo_url (:obj:`str`): A valid URL of the photo. Photo must be in JPEG format. Photo size - must not exceed 5MB. - thumbnail_url (:obj:`str`): URL of the thumbnail for the photo. - - .. versionadded:: 20.2 - - ..versionchanged:: 20.5 - |thumbnail_url_mandatory| - - photo_width (:obj:`int`, optional): Width of the photo. - photo_height (:obj:`int`, optional): Height of the photo. - title (:obj:`str`, optional): Title for the result. - description (:obj:`str`, optional): Short description of the result. - caption (:obj:`str`, optional): Caption of the photo to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the photo. - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.PHOTO`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - photo_url (:obj:`str`): A valid URL of the photo. Photo must be in JPEG format. Photo size - must not exceed 5MB. - thumbnail_url (:obj:`str`): URL of the thumbnail for the photo. - photo_width (:obj:`int`): Optional. Width of the photo. - photo_height (:obj:`int`): Optional. Height of the photo. - title (:obj:`str`): Optional. Title for the result. - description (:obj:`str`): Optional. Short description of the result. - caption (:obj:`str`): Optional. Caption of the photo to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the photo. - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - - """ - - __slots__ = ( - "caption", - "caption_entities", - "description", - "input_message_content", - "parse_mode", - "photo_height", - "photo_url", - "photo_width", - "reply_markup", - "show_caption_above_media", - "thumbnail_url", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - photo_url: str, - thumbnail_url: str, - photo_width: Optional[int] = None, - photo_height: Optional[int] = None, - title: Optional[str] = None, - description: Optional[str] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.PHOTO, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.photo_url: str = photo_url - self.thumbnail_url: str = thumbnail_url - - # Optionals - self.photo_width: Optional[int] = photo_width - self.photo_height: Optional[int] = photo_height - self.title: Optional[str] = title - self.description: Optional[str] = description - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.show_caption_above_media: Optional[bool] = show_caption_above_media diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultsbutton.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultsbutton.py deleted file mode 100755 index 11ba092..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultsbutton.py +++ /dev/null @@ -1,118 +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 that represent a Telegram InlineQueryResultsButton.""" - -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict -from telegram._webappinfo import WebAppInfo - -if TYPE_CHECKING: - from telegram import Bot - - -class InlineQueryResultsButton(TelegramObject): - """This object represents a button to be shown above inline query results. You **must** use - exactly one of the optional fields. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text`, :attr:`web_app` and :attr:`start_parameter` are equal. - - Args: - text (:obj:`str`): Label text on the button. - web_app (:class:`telegram.WebAppInfo`, optional): Description of the - `Web App `_ that will be launched when the - user presses the button. The Web App will be able to switch back to the inline mode - using the method - `switchInlineQuery `_ - inside the Web App. - start_parameter (:obj:`str`, optional): Deep-linking parameter for the - :guilabel:`/start` message sent to the bot when user presses the switch button. - :tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`- - :tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters, - only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed. - - Example: - An inline bot that sends YouTube videos can ask the user to connect the bot to - their YouTube account to adapt search results accordingly. To do this, it displays - a 'Connect your YouTube account' button above the results, or even before showing - any. The user presses the button, switches to a private chat with the bot and, in - doing so, passes a start parameter that instructs the bot to return an OAuth link. - Once done, the bot can offer a switch_inline button so that the user can easily - return to the chat where they wanted to use the bot's inline capabilities. - - Attributes: - text (:obj:`str`): Label text on the button. - web_app (:class:`telegram.WebAppInfo`): Optional. Description of the - `Web App `_ that will be launched when the - user presses the button. The Web App will be able to switch back to the inline mode - using the method ``web_app_switch_inline_query`` inside the Web App. - start_parameter (:obj:`str`): Optional. Deep-linking parameter for the - :guilabel:`/start` message sent to the bot when user presses the switch button. - :tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`- - :tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters, - only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed. - - """ - - __slots__ = ("start_parameter", "text", "web_app") - - def __init__( - self, - text: str, - web_app: Optional[WebAppInfo] = None, - start_parameter: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.text: str = text - - # Optional - self.web_app: Optional[WebAppInfo] = web_app - self.start_parameter: Optional[str] = start_parameter - - self._id_attrs = (self.text, self.web_app, self.start_parameter) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["InlineQueryResultsButton"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - if not data: - return None - - data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot) - - return super().de_json(data=data, bot=bot) - - MIN_START_PARAMETER_LENGTH: Final[int] = ( - constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH - ) - """:const:`telegram.constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH`""" - MAX_START_PARAMETER_LENGTH: Final[int] = ( - constants.InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH - ) - """:const:`telegram.constants.InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH`""" diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvenue.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvenue.py deleted file mode 100755 index 639b0da..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvenue.py +++ /dev/null @@ -1,160 +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 that represent Telegram InlineQueryResultVenue.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._utils.types import JSONDict -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultVenue(InlineQueryResult): - """ - Represents a venue. By default, the venue will be sent by the user. Alternatively, you can - use :attr:`input_message_content` to send a message with the specified content instead of the - venue. - - Note: - Foursquare details and Google Pace details are mutually exclusive. However, this - behaviour is undocumented and might be changed by Telegram. - - .. versionchanged:: 20.5 - |removed_thumb_wildcard_note| - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - latitude (:obj:`float`): Latitude of the venue location in degrees. - longitude (:obj:`float`): Longitude of the venue location in degrees. - title (:obj:`str`): Title of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue if known. - foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. - (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or - "food/icecream".) - google_place_id (:obj:`str`, optional): Google Places identifier of the venue. - google_place_type (:obj:`str`, optional): Google Places type of the venue. (See - `supported types `_.) - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the venue. - thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`, optional): Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`, optional): Thumbnail height. - - .. versionadded:: 20.2 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VENUE`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - latitude (:obj:`float`): Latitude of the venue location in degrees. - longitude (:obj:`float`): Longitude of the venue location in degrees. - title (:obj:`str`): Title of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue if known. - foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known. - (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or - "food/icecream".) - google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. - google_place_type (:obj:`str`): Optional. Google Places type of the venue. (See - `supported types `_.) - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the venue. - thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result. - - .. versionadded:: 20.2 - thumbnail_width (:obj:`int`): Optional. Thumbnail width. - - .. versionadded:: 20.2 - thumbnail_height (:obj:`int`): Optional. Thumbnail height. - - .. versionadded:: 20.2 - - """ - - __slots__ = ( - "address", - "foursquare_id", - "foursquare_type", - "google_place_id", - "google_place_type", - "input_message_content", - "latitude", - "longitude", - "reply_markup", - "thumbnail_height", - "thumbnail_url", - "thumbnail_width", - "title", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - latitude: float, - longitude: float, - title: str, - address: str, - foursquare_id: Optional[str] = None, - foursquare_type: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - google_place_id: Optional[str] = None, - google_place_type: Optional[str] = None, - thumbnail_url: Optional[str] = None, - thumbnail_width: Optional[int] = None, - thumbnail_height: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.VENUE, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.latitude: float = latitude - self.longitude: float = longitude - self.title: str = title - self.address: str = address - - # Optional - self.foursquare_id: Optional[str] = foursquare_id - self.foursquare_type: Optional[str] = foursquare_type - self.google_place_id: Optional[str] = google_place_id - self.google_place_type: Optional[str] = google_place_type - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.thumbnail_url: Optional[str] = thumbnail_url - self.thumbnail_width: Optional[int] = thumbnail_width - self.thumbnail_height: Optional[int] = thumbnail_height diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvideo.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvideo.py deleted file mode 100755 index edc6ce3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvideo.py +++ /dev/null @@ -1,182 +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 that represent Telegram InlineQueryResultVideo.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultVideo(InlineQueryResult): - """ - Represents a link to a page containing an embedded video player or a video file. By default, - this video file will be sent by the user with an optional caption. Alternatively, you can use - :attr:`input_message_content` to send a message with the specified content instead of - the video. - - Note: - If an InlineQueryResultVideo message contains an embedded video (e.g., YouTube), you must - replace its content using :attr:`input_message_content`. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_url_note| - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - video_url (:obj:`str`): A valid URL for the embedded video player or video file. - mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4". - thumbnail_url (:obj:`str`, optional): URL of the thumbnail (JPEG only) for the video. - - .. versionadded:: 20.2 - - ..versionchanged:: 20.5 - |thumbnail_url_mandatory| - - title (:obj:`str`): Title for the result. - caption (:obj:`str`, optional): Caption of the video to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - video_width (:obj:`int`, optional): Video width. - video_height (:obj:`int`, optional): Video height. - video_duration (:obj:`int`, optional): Video duration in seconds. - description (:obj:`str`, optional): Short description of the result. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the video. This field is required if - ``InlineQueryResultVideo`` is used to send an HTML-page as a result - (e.g., a YouTube video). - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VIDEO`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - video_url (:obj:`str`): A valid URL for the embedded video player or video file. - mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4". - thumbnail_url (:obj:`str`): URL of the thumbnail (JPEG only) for the video. - - .. versionadded:: 20.2 - title (:obj:`str`): Title for the result. - caption (:obj:`str`): Optional. Caption of the video to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. - |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - - video_width (:obj:`int`): Optional. Video width. - video_height (:obj:`int`): Optional. Video height. - video_duration (:obj:`int`): Optional. Video duration in seconds. - description (:obj:`str`): Optional. Short description of the result. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the video. This field is required if - ``InlineQueryResultVideo`` is used to send an HTML-page as a result - (e.g., a YouTube video). - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - - """ - - __slots__ = ( - "caption", - "caption_entities", - "description", - "input_message_content", - "mime_type", - "parse_mode", - "reply_markup", - "show_caption_above_media", - "thumbnail_url", - "title", - "video_duration", - "video_height", - "video_url", - "video_width", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - video_url: str, - mime_type: str, - thumbnail_url: str, - title: str, - caption: Optional[str] = None, - video_width: Optional[int] = None, - video_height: Optional[int] = None, - video_duration: Optional[int] = None, - description: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.VIDEO, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.video_url: str = video_url - self.mime_type: str = mime_type - self.thumbnail_url: str = thumbnail_url - self.title: str = title - - # Optional - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.video_width: Optional[int] = video_width - self.video_height: Optional[int] = video_height - self.video_duration: Optional[int] = video_duration - self.description: Optional[str] = description - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content - self.show_caption_above_media: Optional[bool] = show_caption_above_media diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvoice.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvoice.py deleted file mode 100755 index b798040..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvoice.py +++ /dev/null @@ -1,127 +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 that represent Telegram InlineQueryResultVoice.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._inline.inlinequeryresult import InlineQueryResult -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput -from telegram.constants import InlineQueryResultType - -if TYPE_CHECKING: - from telegram import InputMessageContent - - -class InlineQueryResultVoice(InlineQueryResult): - """ - Represents a link to a voice recording in an .ogg container encoded with OPUS. By default, - this voice recording will be sent by the user. Alternatively, you can use - :attr:`input_message_content` to send a message with the specified content instead of - the voice message. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - voice_url (:obj:`str`): A valid URL for the voice recording. - title (:obj:`str`): Recording title. - caption (:obj:`str`, optional): Caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - voice_duration (:obj:`int`, optional): Recording duration in seconds. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the voice recording. - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VOICE`. - id (:obj:`str`): Unique identifier for this result, - :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`- - :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes. - voice_url (:obj:`str`): A valid URL for the voice recording. - title (:obj:`str`): Recording title. - caption (:obj:`str`): Optional. Caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - voice_duration (:obj:`int`): Optional. Recording duration in seconds. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the voice recording. - - """ - - __slots__ = ( - "caption", - "caption_entities", - "input_message_content", - "parse_mode", - "reply_markup", - "title", - "voice_duration", - "voice_url", - ) - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - voice_url: str, - title: str, - voice_duration: Optional[int] = None, - caption: Optional[str] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - input_message_content: Optional["InputMessageContent"] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # Required - super().__init__(InlineQueryResultType.VOICE, id, api_kwargs=api_kwargs) - with self._unfrozen(): - self.voice_url: str = voice_url - self.title: str = title - - # Optional - self.voice_duration: Optional[int] = voice_duration - self.caption: Optional[str] = caption - self.parse_mode: ODVInput[str] = parse_mode - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.input_message_content: Optional[InputMessageContent] = input_message_content diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputcontactmessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputcontactmessagecontent.py deleted file mode 100755 index f7a76df..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inputcontactmessagecontent.py +++ /dev/null @@ -1,68 +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 that represent Telegram InputContactMessageContent.""" -from typing import Optional - -from telegram._inline.inputmessagecontent import InputMessageContent -from telegram._utils.types import JSONDict - - -class InputContactMessageContent(InputMessageContent): - """Represents the content of a contact message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`phone_number` is equal. - - Args: - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`, optional): Contact's last name. - vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, - 0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes. - - Attributes: - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`): Optional. Contact's last name. - vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard, - 0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes. - - """ - - __slots__ = ("first_name", "last_name", "phone_number", "vcard") - - def __init__( - self, - phone_number: str, - first_name: str, - last_name: Optional[str] = None, - vcard: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - with self._unfrozen(): - # Required - self.phone_number: str = phone_number - self.first_name: str = first_name - # Optionals - self.last_name: Optional[str] = last_name - self.vcard: Optional[str] = vcard - - self._id_attrs = (self.phone_number,) diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputinvoicemessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputinvoicemessagecontent.py deleted file mode 100755 index ecef394..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inputinvoicemessagecontent.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 a class that represents a Telegram InputInvoiceMessageContent.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inputmessagecontent import InputMessageContent -from telegram._payment.labeledprice import LabeledPrice -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class InputInvoiceMessageContent(InputMessageContent): - """ - Represents the content of a invoice message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`title`, :attr:`description`, :attr:`payload`, - :attr:`provider_token`, :attr:`currency` and :attr:`prices` are equal. - - .. versionadded:: 13.5 - - Args: - title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`- - :tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters. - description (:obj:`str`): Product description. - :tg-const:`telegram.Invoice.MIN_DESCRIPTION_LENGTH`- - :tg-const:`telegram.Invoice.MAX_DESCRIPTION_LENGTH` characters. - payload (:obj:`str`): Bot-defined invoice payload. - :tg-const:`telegram.Invoice.MIN_PAYLOAD_LENGTH`- - :tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be displayed - to the user, use it for your internal processes. - provider_token (:obj:`str`): Payment provider token, obtained via - `@Botfather `_. Pass an empty string for payments in - |tg_stars|. - - .. deprecated:: 21.3 - As of Bot API 7.4, this parameter is now optional and future versions of the - library will make it optional as well. - currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on - `currencies `_. - Pass ``XTR`` for payments in |tg_stars|. - prices (Sequence[:class:`telegram.LabeledPrice`]): Price breakdown, a list of - components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, - etc.). Must contain exactly one item for payments in |tg_stars|. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the - *smallest units* of the currency (integer, **not** float/double). For example, for a - maximum tip of ``US$ 1.45`` pass ``max_tip_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). Defaults to ``0``. Not supported for payments in |tg_stars|. - suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of suggested - amounts of tip in the *smallest units* of the currency (integer, **not** float/double). - At most 4 suggested tip amounts can be specified. The suggested tip amounts must be - positive, passed in a strictly increased order and must not exceed - :attr:`max_tip_amount`. - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - - provider_data (:obj:`str`, optional): An object for data about the invoice, - which will be shared with the payment provider. A detailed description of the required - fields should be provided by the payment provider. - photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a photo - of the goods or a marketing image for a service. People like it better when they see - what they are paying for. - photo_size (:obj:`int`, optional): Photo size. - photo_width (:obj:`int`, optional): Photo width. - photo_height (:obj:`int`, optional): Photo height. - need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full - name to complete the order. Ignored for payments in |tg_stars|. - need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's - phone number to complete the order. Ignored for payments in |tg_stars|. - need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email - address to complete the order. Ignored for payments in |tg_stars|. - need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the - user's shipping address to complete the order. Ignored for payments in |tg_stars| - send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's - phone number should be sent to provider. Ignored for payments in |tg_stars|. - send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email - address should be sent to provider. Ignored for payments in |tg_stars|. - is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on - the shipping method. Ignored for payments in |tg_stars|. - - Attributes: - title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`- - :tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters. - description (:obj:`str`): Product description. - :tg-const:`telegram.Invoice.MIN_DESCRIPTION_LENGTH`- - :tg-const:`telegram.Invoice.MAX_DESCRIPTION_LENGTH` characters. - payload (:obj:`str`): Bot-defined invoice payload. - :tg-const:`telegram.Invoice.MIN_PAYLOAD_LENGTH`- - :tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be displayed - to the user, use it for your internal processes. - provider_token (:obj:`str`): Payment provider token, obtained via - `@Botfather `_. Pass an empty string for payments in `Telegram - Stars `_. - currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on - `currencies `_. - Pass ``XTR`` for payments in |tg_stars|. - prices (tuple[:class:`telegram.LabeledPrice`]): Price breakdown, a list of - components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, - etc.). Must contain exactly one item for payments in |tg_stars|. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - max_tip_amount (:obj:`int`): Optional. The maximum accepted amount for tips in the - *smallest units* of the currency (integer, **not** float/double). For example, for a - maximum tip of ``US$ 1.45`` ``max_tip_amount`` is ``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). Defaults to ``0``. Not supported for payments in |tg_stars|. - suggested_tip_amounts (tuple[:obj:`int`]): Optional. An array of suggested - amounts of tip in the *smallest units* of the currency (integer, **not** float/double). - At most 4 suggested tip amounts can be specified. The suggested tip amounts must be - positive, passed in a strictly increased order and must not exceed - :attr:`max_tip_amount`. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - provider_data (:obj:`str`): Optional. An object for data about the invoice, - which will be shared with the payment provider. A detailed description of the required - fields should be provided by the payment provider. - photo_url (:obj:`str`): Optional. URL of the product photo for the invoice. Can be a photo - of the goods or a marketing image for a service. People like it better when they see - what they are paying for. - photo_size (:obj:`int`): Optional. Photo size. - photo_width (:obj:`int`): Optional. Photo width. - photo_height (:obj:`int`): Optional. Photo height. - need_name (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's full name to - complete the order. Ignored for payments in |tg_stars|. - need_phone_number (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's - phone number to complete the order. Ignored for payments in |tg_stars|. - need_email (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's email - address to complete the order. Ignored for payments in |tg_stars|. - need_shipping_address (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's - shipping address to complete the order. Ignored for payments in |tg_stars|. - send_phone_number_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's phone - number should be sent to provider. Ignored for payments in |tg_stars|. - send_email_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's email address - should be sent to provider. Ignored for payments in |tg_stars|. - is_flexible (:obj:`bool`): Optional. Pass :obj:`True`, if the final price depends on the - shipping method. Ignored for payments in |tg_stars|. - - """ - - __slots__ = ( - "currency", - "description", - "is_flexible", - "max_tip_amount", - "need_email", - "need_name", - "need_phone_number", - "need_shipping_address", - "payload", - "photo_height", - "photo_size", - "photo_url", - "photo_width", - "prices", - "provider_data", - "provider_token", - "send_email_to_provider", - "send_phone_number_to_provider", - "suggested_tip_amounts", - "title", - ) - - def __init__( - self, - title: str, - description: str, - payload: str, - provider_token: Optional[str], # This arg is now optional since Bot API 7.4 - currency: str, - prices: Sequence[LabeledPrice], - max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[Sequence[int]] = None, - provider_data: 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, - send_phone_number_to_provider: Optional[bool] = None, - send_email_to_provider: Optional[bool] = None, - is_flexible: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - with self._unfrozen(): - # Required - self.title: str = title - self.description: str = description - self.payload: str = payload - self.provider_token: Optional[str] = provider_token - self.currency: str = currency - self.prices: tuple[LabeledPrice, ...] = parse_sequence_arg(prices) - # Optionals - self.max_tip_amount: Optional[int] = max_tip_amount - self.suggested_tip_amounts: tuple[int, ...] = parse_sequence_arg(suggested_tip_amounts) - self.provider_data: Optional[str] = provider_data - self.photo_url: Optional[str] = photo_url - self.photo_size: Optional[int] = photo_size - self.photo_width: Optional[int] = photo_width - self.photo_height: Optional[int] = photo_height - self.need_name: Optional[bool] = need_name - self.need_phone_number: Optional[bool] = need_phone_number - self.need_email: Optional[bool] = need_email - self.need_shipping_address: Optional[bool] = need_shipping_address - self.send_phone_number_to_provider: Optional[bool] = send_phone_number_to_provider - self.send_email_to_provider: Optional[bool] = send_email_to_provider - self.is_flexible: Optional[bool] = is_flexible - - self._id_attrs = ( - self.title, - self.description, - self.payload, - self.provider_token, - self.currency, - self.prices, - ) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["InputInvoiceMessageContent"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["prices"] = LabeledPrice.de_list(data.get("prices"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputlocationmessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputlocationmessagecontent.py deleted file mode 100755 index f71a716..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inputlocationmessagecontent.py +++ /dev/null @@ -1,150 +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 that represent Telegram InputLocationMessageContent.""" - -from typing import Final, Optional - -from telegram import constants -from telegram._inline.inputmessagecontent import InputMessageContent -from telegram._utils.types import JSONDict - - -class InputLocationMessageContent(InputMessageContent): - # fmt: off - """ - Represents the content of a location message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`latitude` and :attr:`longitude` are equal. - - Args: - latitude (:obj:`float`): Latitude of the location in degrees. - longitude (:obj:`float`): Longitude of the location in degrees. - horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, - measured in meters; 0- - :tg-const:`telegram.InputLocationMessageContent.HORIZONTAL_ACCURACY`. - live_period (:obj:`int`, optional): Period in seconds for which the location will be - updated, should be between - :tg-const:`telegram.InputLocationMessageContent.MIN_LIVE_PERIOD` and - :tg-const:`telegram.InputLocationMessageContent.MAX_LIVE_PERIOD` or - :tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` for live - locations that can be edited indefinitely. - heading (:obj:`int`, optional): For live locations, a direction in which the user is - moving, in degrees. Must be between - :tg-const:`telegram.InputLocationMessageContent.MIN_HEADING` and - :tg-const:`telegram.InputLocationMessageContent.MAX_HEADING` if specified. - proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance - for proximity alerts about approaching another chat member, in meters. Must be - between :tg-const:`telegram.InputLocationMessageContent.MIN_PROXIMITY_ALERT_RADIUS` - and :tg-const:`telegram.InputLocationMessageContent.MAX_PROXIMITY_ALERT_RADIUS` - if specified. - - Attributes: - latitude (:obj:`float`): Latitude of the location in degrees. - longitude (:obj:`float`): Longitude of the location in degrees. - horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, - measured in meters; 0- - :tg-const:`telegram.InputLocationMessageContent.HORIZONTAL_ACCURACY`. - live_period (:obj:`int`): Optional. Period in seconds for which the location can be - updated, should be between - :tg-const:`telegram.InputLocationMessageContent.MIN_LIVE_PERIOD` and - :tg-const:`telegram.InputLocationMessageContent.MAX_LIVE_PERIOD`. - heading (:obj:`int`): Optional. For live locations, a direction in which the user is - moving, in degrees. Must be between - :tg-const:`telegram.InputLocationMessageContent.MIN_HEADING` and - :tg-const:`telegram.InputLocationMessageContent.MAX_HEADING` if specified. - proximity_alert_radius (:obj:`int`): Optional. For live locations, a maximum distance - for proximity alerts about approaching another chat member, in meters. Must be - between :tg-const:`telegram.InputLocationMessageContent.MIN_PROXIMITY_ALERT_RADIUS` - and :tg-const:`telegram.InputLocationMessageContent.MAX_PROXIMITY_ALERT_RADIUS` - if specified. - - """ - - __slots__ = ( - "heading", - "horizontal_accuracy", - "latitude", - "live_period", - "longitude", - "proximity_alert_radius") - # fmt: on - - def __init__( - self, - latitude: float, - longitude: float, - live_period: Optional[int] = None, - horizontal_accuracy: Optional[float] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - with self._unfrozen(): - # Required - self.latitude: float = latitude - self.longitude: float = longitude - - # Optionals - self.live_period: Optional[int] = live_period - self.horizontal_accuracy: Optional[float] = horizontal_accuracy - self.heading: Optional[int] = heading - self.proximity_alert_radius: Optional[int] = ( - int(proximity_alert_radius) if proximity_alert_radius else None - ) - - self._id_attrs = (self.latitude, self.longitude) - - HORIZONTAL_ACCURACY: Final[int] = constants.LocationLimit.HORIZONTAL_ACCURACY - """:const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY` - - .. versionadded:: 20.0 - """ - MIN_HEADING: Final[int] = constants.LocationLimit.MIN_HEADING - """:const:`telegram.constants.LocationLimit.MIN_HEADING` - - .. versionadded:: 20.0 - """ - MAX_HEADING: Final[int] = constants.LocationLimit.MAX_HEADING - """:const:`telegram.constants.LocationLimit.MAX_HEADING` - - .. versionadded:: 20.0 - """ - MIN_LIVE_PERIOD: Final[int] = constants.LocationLimit.MIN_LIVE_PERIOD - """:const:`telegram.constants.LocationLimit.MIN_LIVE_PERIOD` - - .. versionadded:: 20.0 - """ - MAX_LIVE_PERIOD: Final[int] = constants.LocationLimit.MAX_LIVE_PERIOD - """:const:`telegram.constants.LocationLimit.MAX_LIVE_PERIOD` - - .. versionadded:: 20.0 - """ - MIN_PROXIMITY_ALERT_RADIUS: Final[int] = constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS - """:const:`telegram.constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS` - - .. versionadded:: 20.0 - """ - MAX_PROXIMITY_ALERT_RADIUS: Final[int] = constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS - """:const:`telegram.constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputmessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputmessagecontent.py deleted file mode 100755 index e37fa12..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inputmessagecontent.py +++ /dev/null @@ -1,42 +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 that represent Telegram InputMessageContent.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class InputMessageContent(TelegramObject): - """Base class for Telegram InputMessageContent Objects. - - See: :class:`telegram.InputContactMessageContent`, - :class:`telegram.InputInvoiceMessageContent`, - :class:`telegram.InputLocationMessageContent`, :class:`telegram.InputTextMessageContent` and - :class:`telegram.InputVenueMessageContent` for more details. - - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(api_kwargs=api_kwargs) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputtextmessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputtextmessagecontent.py deleted file mode 100755 index 11a2373..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inputtextmessagecontent.py +++ /dev/null @@ -1,116 +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 that represent Telegram InputTextMessageContent.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._inline.inputmessagecontent import InputMessageContent -from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram._linkpreviewoptions import LinkPreviewOptions - - -class InputTextMessageContent(InputMessageContent): - """ - Represents the content of a text message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_text` is equal. - - Examples: - :any:`Inline Bot ` - - Args: - message_text (:obj:`str`): Text of the message to be sent, - :tg-const:`telegram.constants.MessageLimit.MIN_TEXT_LENGTH`- - :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation - options for the message. Mutually exclusive with - :paramref:`disable_web_page_preview`. - - .. versionadded:: 20.8 - - Keyword Args: - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the - sent message. Convenience parameter for setting :paramref:`link_preview_options`. - Mutually exclusive with :paramref:`link_preview_options`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`link_preview_options` replacing this - argument. PTB will automatically convert this argument to that one, but - for advanced options, please use :paramref:`link_preview_options` directly. - - .. versionchanged:: 21.0 - |keyword_only_arg| - - Attributes: - message_text (:obj:`str`): Text of the message to be sent, - :tg-const:`telegram.constants.MessageLimit.MIN_TEXT_LENGTH`- - :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - link_preview_options (:obj:`LinkPreviewOptions`): Optional. Link preview generation - options for the message. - - .. versionadded:: 20.8 - - """ - - __slots__ = ("entities", "link_preview_options", "message_text", "parse_mode") - - def __init__( - self, - message_text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - entities: Optional[Sequence[MessageEntity]] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, - *, - disable_web_page_preview: Optional[bool] = None, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - with self._unfrozen(): - # Required - self.message_text: str = message_text - # Optionals - self.parse_mode: ODVInput[str] = parse_mode - self.entities: tuple[MessageEntity, ...] = parse_sequence_arg(entities) - self.link_preview_options: ODVInput[LinkPreviewOptions] = parse_lpo_and_dwpp( - disable_web_page_preview, link_preview_options - ) - - self._id_attrs = (self.message_text,) diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputvenuemessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputvenuemessagecontent.py deleted file mode 100755 index c836ea1..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/inputvenuemessagecontent.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 classes that represent Telegram InputVenueMessageContent.""" -from typing import Optional - -from telegram._inline.inputmessagecontent import InputMessageContent -from telegram._utils.types import JSONDict - - -class InputVenueMessageContent(InputMessageContent): - """Represents the content of a venue message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`latitude`, :attr:`longitude` and :attr:`title` - are equal. - - Note: - Foursquare details and Google Pace details are mutually exclusive. However, this - behaviour is undocumented and might be changed by Telegram. - - Args: - latitude (:obj:`float`): Latitude of the location in degrees. - longitude (:obj:`float`): Longitude of the location in degrees. - title (:obj:`str`): Name of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue, if known. - foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. - (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or - "food/icecream".) - google_place_id (:obj:`str`, optional): Google Places identifier of the venue. - google_place_type (:obj:`str`, optional): Google Places type of the venue. (See - `supported types `_.) - - Attributes: - latitude (:obj:`float`): Latitude of the location in degrees. - longitude (:obj:`float`): Longitude of the location in degrees. - title (:obj:`str`): Name of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue, if known. - foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known. - (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or - "food/icecream".) - google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. - google_place_type (:obj:`str`): Optional. Google Places type of the venue. (See - `supported types `_.) - - """ - - __slots__ = ( - "address", - "foursquare_id", - "foursquare_type", - "google_place_id", - "google_place_type", - "latitude", - "longitude", - "title", - ) - - def __init__( - self, - latitude: float, - longitude: float, - title: str, - address: str, - foursquare_id: Optional[str] = None, - foursquare_type: Optional[str] = None, - google_place_id: Optional[str] = None, - google_place_type: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - with self._unfrozen(): - # Required - self.latitude: float = latitude - self.longitude: float = longitude - self.title: str = title - self.address: str = address - # Optionals - self.foursquare_id: Optional[str] = foursquare_id - self.foursquare_type: Optional[str] = foursquare_type - self.google_place_id: Optional[str] = google_place_id - self.google_place_type: Optional[str] = google_place_type - - self._id_attrs = ( - self.latitude, - self.longitude, - self.title, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/preparedinlinemessage.py b/venv/lib/python3.11/site-packages/telegram/_inline/preparedinlinemessage.py deleted file mode 100755 index 35f4628..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_inline/preparedinlinemessage.py +++ /dev/null @@ -1,83 +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 Prepared inline Message.""" -import datetime as dtm -from typing import TYPE_CHECKING, Optional - -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 PreparedInlineMessage(TelegramObject): - """Describes an inline message to be sent by a user of a Mini App. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - .. versionadded:: 21.8 - - Args: - id (:obj:`str`): Unique identifier of the prepared message - expiration_date (:class:`datetime.datetime`): Expiration date of the prepared message. - Expired prepared messages can no longer be used. - |datetime_localization| - - Attributes: - id (:obj:`str`): Unique identifier of the prepared message - expiration_date (:class:`datetime.datetime`): Expiration date of the prepared message. - Expired prepared messages can no longer be used. - |datetime_localization| - """ - - __slots__ = ("expiration_date", "id") - - def __init__( - self, - id: str, # pylint: disable=redefined-builtin - expiration_date: dtm.datetime, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.id: str = id - self.expiration_date: dtm.datetime = expiration_date - - self._id_attrs = (self.id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PreparedInlineMessage"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - data["expiration_date"] = from_timestamp(data.get("expiration_date"), tzinfo=loc_tzinfo) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_keyboardbutton.py b/venv/lib/python3.11/site-packages/telegram/_keyboardbutton.py deleted file mode 100755 index 7bb8949..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_keyboardbutton.py +++ /dev/null @@ -1,191 +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 KeyboardButton.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._keyboardbuttonpolltype import KeyboardButtonPollType -from telegram._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict -from telegram._webappinfo import WebAppInfo - -if TYPE_CHECKING: - from telegram import Bot - - -class KeyboardButton(TelegramObject): - """ - This object represents one button of the reply keyboard. At most one of the optional fields - must be used to specify type of the button. For simple text buttons, :obj:`str` - can be used instead of this object to specify text of the button. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text`, :attr:`request_contact`, :attr:`request_location`, - :attr:`request_poll`, :attr:`web_app`, :attr:`request_users` and :attr:`request_chat` are - equal. - - Note: - * Optional fields are mutually exclusive. - * :attr:`request_contact` and :attr:`request_location` options will only work in Telegram - versions released after 9 April, 2016. Older clients will display unsupported message. - * :attr:`request_poll` option will only work in Telegram versions released after 23 - January, 2020. Older clients will display unsupported message. - * :attr:`web_app` option will only work in Telegram versions released after 16 April, 2022. - Older clients will display unsupported message. - * :attr:`request_users` and :attr:`request_chat` options will only work in Telegram - versions released after 3 February, 2023. Older clients will display unsupported - message. - - .. versionchanged:: 21.0 - Removed deprecated argument and attribute ``request_user``. - .. versionchanged:: 20.0 - :attr:`web_app` is considered as well when comparing objects of this type in terms of - equality. - .. versionchanged:: 20.5 - :attr:`request_users` and :attr:`request_chat` are considered as well when - comparing objects of this type in terms of equality. - - Args: - text (:obj:`str`): Text of the button. If none of the optional fields are used, it will be - sent to the bot as a message when the button is pressed. - request_contact (:obj:`bool`, optional): If :obj:`True`, the user's phone number will be - sent as a contact when the button is pressed. Available in private chats only. - request_location (:obj:`bool`, optional): If :obj:`True`, the user's current location will - be sent when the button is pressed. Available in private chats only. - request_poll (:class:`~telegram.KeyboardButtonPollType`, optional): If specified, the user - will be asked to create a poll and send it to the bot when the button is pressed. - Available in private chats only. - web_app (:class:`~telegram.WebAppInfo`, optional): If specified, the described `Web App - `_ will be launched when the button is pressed. - The Web App will be able to send a :attr:`Message.web_app_data` service message. - Available in private chats only. - - .. versionadded:: 20.0 - - request_users (:class:`KeyboardButtonRequestUsers`, optional): If specified, pressing the - button will open a list of suitable users. Tapping on any user will send its - identifier to the bot in a :attr:`telegram.Message.users_shared` service message. - Available in private chats only. - - .. versionadded:: 20.8 - request_chat (:class:`KeyboardButtonRequestChat`, optional): If specified, pressing the - button will open a list of suitable chats. Tapping on a chat will send its - identifier to the bot in a :attr:`telegram.Message.chat_shared` service message. - Available in private chats only. - - .. versionadded:: 20.1 - Attributes: - text (:obj:`str`): Text of the button. If none of the optional fields are used, it will be - sent to the bot as a message when the button is pressed. - request_contact (:obj:`bool`): Optional. If :obj:`True`, the user's phone number will be - sent as a contact when the button is pressed. Available in private chats only. - request_location (:obj:`bool`): Optional. If :obj:`True`, the user's current location will - be sent when the button is pressed. Available in private chats only. - request_poll (:class:`~telegram.KeyboardButtonPollType`): Optional. If specified, - the user will be asked to create a poll and send it to the bot when the button is - pressed. Available in private chats only. - web_app (:class:`~telegram.WebAppInfo`): Optional. If specified, the described `Web App - `_ will be launched when the button is pressed. - The Web App will be able to send a :attr:`Message.web_app_data` service message. - Available in private chats only. - - .. versionadded:: 20.0 - request_users (:class:`KeyboardButtonRequestUsers`): Optional. If specified, pressing the - button will open a list of suitable users. Tapping on any user will send its - identifier to the bot in a :attr:`telegram.Message.users_shared` service message. - Available in private chats only. - - .. versionadded:: 20.8 - request_chat (:class:`KeyboardButtonRequestChat`): Optional. If specified, pressing the - button will open a list of suitable chats. Tapping on a chat will send its - identifier to the bot in a :attr:`telegram.Message.chat_shared` service message. - Available in private chats only. - - .. versionadded:: 20.1 - """ - - __slots__ = ( - "request_chat", - "request_contact", - "request_location", - "request_poll", - "request_users", - "text", - "web_app", - ) - - def __init__( - self, - text: str, - request_contact: Optional[bool] = None, - request_location: Optional[bool] = None, - request_poll: Optional[KeyboardButtonPollType] = None, - web_app: Optional[WebAppInfo] = None, - request_chat: Optional[KeyboardButtonRequestChat] = None, - request_users: Optional[KeyboardButtonRequestUsers] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.text: str = text - # Optionals - self.request_contact: Optional[bool] = request_contact - self.request_location: Optional[bool] = request_location - self.request_poll: Optional[KeyboardButtonPollType] = request_poll - self.web_app: Optional[WebAppInfo] = web_app - self.request_users: Optional[KeyboardButtonRequestUsers] = request_users - self.request_chat: Optional[KeyboardButtonRequestChat] = request_chat - - self._id_attrs = ( - self.text, - self.request_contact, - self.request_location, - self.request_poll, - self.web_app, - self.request_users, - self.request_chat, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["KeyboardButton"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["request_poll"] = KeyboardButtonPollType.de_json(data.get("request_poll"), bot) - data["request_users"] = KeyboardButtonRequestUsers.de_json(data.get("request_users"), bot) - data["request_chat"] = KeyboardButtonRequestChat.de_json(data.get("request_chat"), bot) - data["web_app"] = WebAppInfo.de_json(data.get("web_app"), 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 request_user := data.get("request_user"): - api_kwargs = {"request_user": request_user} - - return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonpolltype.py b/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonpolltype.py deleted file mode 100755 index fb21cfe..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonpolltype.py +++ /dev/null @@ -1,63 +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 type of a Telegram Poll.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.types import JSONDict -from telegram.constants import PollType - - -class KeyboardButtonPollType(TelegramObject): - """This object represents type of a poll, which is allowed to be created - and sent when the corresponding button is pressed. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` is equal. - - Examples: - :any:`Poll Bot ` - - Args: - type (:obj:`str`, optional): If :tg-const:`telegram.Poll.QUIZ` is passed, the user will be - allowed to create only polls in the quiz mode. If :tg-const:`telegram.Poll.REGULAR` is - passed, only regular polls will be allowed. Otherwise, the user will be allowed to - create a poll of any type. - Attributes: - type (:obj:`str`): Optional. If equals :tg-const:`telegram.Poll.QUIZ`, the user will - be allowed to create only polls in the quiz mode. If equals - :tg-const:`telegram.Poll.REGULAR`, only regular polls will be allowed. - Otherwise, the user will be allowed to create a poll of any type. - """ - - __slots__ = ("type",) - - def __init__( - self, - type: Optional[str] = None, # pylint: disable=redefined-builtin - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.type: Optional[str] = enum.get_member(PollType, type, type) - - self._id_attrs = (self.type,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonrequest.py b/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonrequest.py deleted file mode 100755 index b929f0b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonrequest.py +++ /dev/null @@ -1,276 +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 to request chats/users.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._chatadministratorrights import ChatAdministratorRights -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class KeyboardButtonRequestUsers(TelegramObject): - """This object defines the criteria used to request a suitable user. The identifier of the - selected user will be shared with the bot when the corresponding button is pressed. `More - about requesting users » `_. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`request_id` is equal. - - .. versionadded:: 20.8 - This class was previously named ``KeyboardButtonRequestUser``. - - Args: - request_id (:obj:`int`): Signed 32-bit identifier of the request, which will be received - back in the :class:`telegram.UsersShared` object. Must be unique within the message. - user_is_bot (:obj:`bool`, optional): Pass :obj:`True` to request a bot, pass :obj:`False` - to request a regular user. If not specified, no additional restrictions are applied. - user_is_premium (:obj:`bool`, optional): Pass :obj:`True` to request a premium user, pass - :obj:`False` to request a non-premium user. If not specified, no additional - restrictions are applied. - max_quantity (:obj:`int`, optional): The maximum number of users to be selected; - :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MIN_QUANTITY` - - :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MAX_QUANTITY`. - Defaults to :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MIN_QUANTITY` - . - - .. versionadded:: 20.8 - request_name (:obj:`bool`, optional): Pass :obj:`True` to request the users' first and last - name. - - .. versionadded:: 21.1 - request_username (:obj:`bool`, optional): Pass :obj:`True` to request the users' username. - - .. versionadded:: 21.1 - request_photo (:obj:`bool`, optional): Pass :obj:`True` to request the users' photo. - - .. versionadded:: 21.1 - - Attributes: - request_id (:obj:`int`): Identifier of the request. - user_is_bot (:obj:`bool`): Optional. Pass :obj:`True` to request a bot, pass :obj:`False` - to request a regular user. If not specified, no additional restrictions are applied. - user_is_premium (:obj:`bool`): Optional. Pass :obj:`True` to request a premium user, pass - :obj:`False` to request a non-premium user. If not specified, no additional - restrictions are applied. - max_quantity (:obj:`int`): Optional. The maximum number of users to be selected; - :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MIN_QUANTITY` - - :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MAX_QUANTITY`. - Defaults to :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MIN_QUANTITY` - . - - .. versionadded:: 20.8 - request_name (:obj:`bool`): Optional. Pass :obj:`True` to request the users' first and last - name. - - .. versionadded:: 21.1 - request_username (:obj:`bool`): Optional. Pass :obj:`True` to request the users' username. - - .. versionadded:: 21.1 - request_photo (:obj:`bool`): Optional. Pass :obj:`True` to request the users' photo. - - .. versionadded:: 21.1 - - """ - - __slots__ = ( - "max_quantity", - "request_id", - "request_name", - "request_photo", - "request_username", - "user_is_bot", - "user_is_premium", - ) - - def __init__( - self, - request_id: int, - user_is_bot: Optional[bool] = None, - user_is_premium: Optional[bool] = None, - max_quantity: Optional[int] = None, - request_name: Optional[bool] = None, - request_username: Optional[bool] = None, - request_photo: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.request_id: int = request_id - - # Optionals - self.user_is_bot: Optional[bool] = user_is_bot - self.user_is_premium: Optional[bool] = user_is_premium - self.max_quantity: Optional[int] = max_quantity - self.request_name: Optional[bool] = request_name - self.request_username: Optional[bool] = request_username - self.request_photo: Optional[bool] = request_photo - - self._id_attrs = (self.request_id,) - - self._freeze() - - -class KeyboardButtonRequestChat(TelegramObject): - """This object defines the criteria used to request a suitable chat. The identifier of the - selected user will be shared with the bot when the corresponding button is pressed. `More - about requesting users » `_. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`request_id` is equal. - - .. versionadded:: 20.1 - - Args: - request_id (:obj:`int`): Signed 32-bit identifier of the request, which will be received - back in the :class:`telegram.ChatShared` object. Must be unique within the message. - chat_is_channel (:obj:`bool`): Pass :obj:`True` to request a channel chat, pass - :obj:`False` to request a group or a supergroup chat. - chat_is_forum (:obj:`bool`, optional): Pass :obj:`True` to request a forum supergroup, pass - :obj:`False` to request a non-forum chat. If not specified, no additional - restrictions are applied. - chat_has_username (:obj:`bool`, optional): Pass :obj:`True` to request a supergroup or a - channel with a username, pass :obj:`False` to request a chat without a username. If - not specified, no additional restrictions are applied. - chat_is_created (:obj:`bool`, optional): Pass :obj:`True` to request a chat owned by the - user. Otherwise, no additional restrictions are applied. - user_administrator_rights (:class:`ChatAdministratorRights`, optional): Specifies the - required administrator rights of the user in the chat. If not specified, no additional - restrictions are applied. - bot_administrator_rights (:class:`ChatAdministratorRights`, optional): Specifies the - required administrator rights of the bot in the chat. The rights must be a subset of - :paramref:`user_administrator_rights`. If not specified, no additional restrictions are - applied. - bot_is_member (:obj:`bool`, optional): Pass :obj:`True` to request a chat with the bot - as a member. Otherwise, no additional restrictions are applied. - request_title (:obj:`bool`, optional): Pass :obj:`True` to request the chat's title. - - .. versionadded:: 21.1 - request_username (:obj:`bool`, optional): Pass :obj:`True` to request the chat's username. - - .. versionadded:: 21.1 - request_photo (:obj:`bool`, optional): Pass :obj:`True` to request the chat's photo. - - .. versionadded:: 21.1 - Attributes: - request_id (:obj:`int`): Identifier of the request. - chat_is_channel (:obj:`bool`): Pass :obj:`True` to request a channel chat, pass - :obj:`False` to request a group or a supergroup chat. - chat_is_forum (:obj:`bool`): Optional. Pass :obj:`True` to request a forum supergroup, pass - :obj:`False` to request a non-forum chat. If not specified, no additional - restrictions are applied. - chat_has_username (:obj:`bool`): Optional. Pass :obj:`True` to request a supergroup or a - channel with a username, pass :obj:`False` to request a chat without a username. If - not specified, no additional restrictions are applied. - chat_is_created (:obj:`bool`) Optional. Pass :obj:`True` to request a chat owned by the - user. Otherwise, no additional restrictions are applied. - user_administrator_rights (:class:`ChatAdministratorRights`) Optional. Specifies the - required administrator rights of the user in the chat. If not specified, no additional - restrictions are applied. - bot_administrator_rights (:class:`ChatAdministratorRights`) Optional. Specifies the - required administrator rights of the bot in the chat. The rights must be a subset of - :attr:`user_administrator_rights`. If not specified, no additional restrictions are - applied. - bot_is_member (:obj:`bool`) Optional. Pass :obj:`True` to request a chat with the bot - as a member. Otherwise, no additional restrictions are applied. - request_title (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's title. - - .. versionadded:: 21.1 - request_username (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's username. - - .. versionadded:: 21.1 - request_photo (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's photo. - - .. versionadded:: 21.1 - """ - - __slots__ = ( - "bot_administrator_rights", - "bot_is_member", - "chat_has_username", - "chat_is_channel", - "chat_is_created", - "chat_is_forum", - "request_id", - "request_photo", - "request_title", - "request_username", - "user_administrator_rights", - ) - - def __init__( - self, - request_id: int, - chat_is_channel: bool, - chat_is_forum: Optional[bool] = None, - chat_has_username: Optional[bool] = None, - chat_is_created: Optional[bool] = None, - user_administrator_rights: Optional[ChatAdministratorRights] = None, - bot_administrator_rights: Optional[ChatAdministratorRights] = None, - bot_is_member: Optional[bool] = None, - request_title: Optional[bool] = None, - request_username: Optional[bool] = None, - request_photo: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # required - self.request_id: int = request_id - self.chat_is_channel: bool = chat_is_channel - - # optional - self.chat_is_forum: Optional[bool] = chat_is_forum - self.chat_has_username: Optional[bool] = chat_has_username - self.chat_is_created: Optional[bool] = chat_is_created - self.user_administrator_rights: Optional[ChatAdministratorRights] = ( - user_administrator_rights - ) - self.bot_administrator_rights: Optional[ChatAdministratorRights] = bot_administrator_rights - self.bot_is_member: Optional[bool] = bot_is_member - self.request_title: Optional[bool] = request_title - self.request_username: Optional[bool] = request_username - self.request_photo: Optional[bool] = request_photo - - self._id_attrs = (self.request_id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["KeyboardButtonRequestChat"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["user_administrator_rights"] = ChatAdministratorRights.de_json( - data.get("user_administrator_rights"), bot - ) - data["bot_administrator_rights"] = ChatAdministratorRights.de_json( - data.get("bot_administrator_rights"), bot - ) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_linkpreviewoptions.py b/venv/lib/python3.11/site-packages/telegram/_linkpreviewoptions.py deleted file mode 100755 index 6e28c92..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_linkpreviewoptions.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 LinkPreviewOptions class.""" - - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput - - -class LinkPreviewOptions(TelegramObject): - """ - Describes the options used for link preview generation. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`is_disabled`, :attr:`url`, :attr:`prefer_small_media`, - :attr:`prefer_large_media`, and :attr:`show_above_text` are equal. - - .. versionadded:: 20.8 - - Args: - is_disabled (:obj:`bool`, optional): :obj:`True`, if the link preview is disabled. - url (:obj:`str`, optional): The URL to use for the link preview. If empty, then the first - URL found in the message text will be used. - prefer_small_media (:obj:`bool`, optional): :obj:`True`, if the media in the link preview - is supposed to be shrunk; ignored if the URL isn't explicitly specified or media size - change isn't supported for the preview. - prefer_large_media (:obj:`bool`, optional): :obj:`True`, if the media in the link preview - is supposed to be enlarged; ignored if the URL isn't explicitly specified or media - size change isn't supported for the preview. - show_above_text (:obj:`bool`, optional): :obj:`True`, if the link preview must be shown - above the message text; otherwise, the link preview will be shown below the message - text. - - Attributes: - is_disabled (:obj:`bool`): Optional. :obj:`True`, if the link preview is disabled. - url (:obj:`str`): Optional. The URL to use for the link preview. If empty, then the first - URL found in the message text will be used. - prefer_small_media (:obj:`bool`): Optional. :obj:`True`, if the media in the link preview - is supposed to be shrunk; ignored if the URL isn't explicitly specified or media size - change isn't supported for the preview. - prefer_large_media (:obj:`bool`): Optional. :obj:`True`, if the media in the link preview - is supposed to be enlarged; ignored if the URL isn't explicitly specified or media size - change isn't supported for the preview. - show_above_text (:obj:`bool`): Optional. :obj:`True`, if the link preview must be shown - above the message text; otherwise, the link preview will be shown below the message - text. - """ - - __slots__ = ( - "is_disabled", - "prefer_large_media", - "prefer_small_media", - "show_above_text", - "url", - ) - - def __init__( - self, - is_disabled: ODVInput[bool] = DEFAULT_NONE, - url: ODVInput[str] = DEFAULT_NONE, - prefer_small_media: ODVInput[bool] = DEFAULT_NONE, - prefer_large_media: ODVInput[bool] = DEFAULT_NONE, - show_above_text: ODVInput[bool] = DEFAULT_NONE, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Optionals - - self.is_disabled: ODVInput[bool] = is_disabled - self.url: ODVInput[str] = url - self.prefer_small_media: ODVInput[bool] = prefer_small_media - self.prefer_large_media: ODVInput[bool] = prefer_large_media - self.show_above_text: ODVInput[bool] = show_above_text - - self._id_attrs = ( - self.is_disabled, - self.url, - self.prefer_small_media, - self.prefer_large_media, - self.show_above_text, - ) - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_loginurl.py b/venv/lib/python3.11/site-packages/telegram/_loginurl.py deleted file mode 100755 index 3400542..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_loginurl.py +++ /dev/null @@ -1,105 +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 LoginUrl.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class LoginUrl(TelegramObject): - """This object represents a parameter of the inline keyboard button used to automatically - authorize a user. Serves as a great replacement for the Telegram Login Widget when the user is - coming from Telegram. All the user needs to do is tap/click a button and confirm that they want - to log in. Telegram apps support these buttons as of version 5.7. - - Sample bot: `@discussbot `_ - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`url` is equal. - - Note: - You must always check the hash of the received data to verify the authentication - and the integrity of the data as described in - `Checking authorization `_ - - Args: - url (:obj:`str`): An HTTPS URL to be opened with user authorization data added to the query - string when the button is pressed. If the user refuses to provide authorization data, - the original URL without information about the user will be opened. The data added is - the same as described in - `Receiving authorization data - `_. - forward_text (:obj:`str`, optional): New text of the button in forwarded messages. - bot_username (:obj:`str`, optional): Username of a bot, which will be used for user - authorization. See - `Setting up a bot `_ - for more details. If not specified, the current - bot's username will be assumed. The url's domain must be the same as the domain linked - with the bot. See - `Linking your domain to the bot - `_ - for more details. - request_write_access (:obj:`bool`, optional): Pass :obj:`True` to request the permission - for your bot to send messages to the user. - - Attributes: - url (:obj:`str`): An HTTPS URL to be opened with user authorization data added to the query - string when the button is pressed. If the user refuses to provide authorization data, - the original URL without information about the user will be opened. The data added is - the same as described in - `Receiving authorization data - `_. - forward_text (:obj:`str`): Optional. New text of the button in forwarded messages. - bot_username (:obj:`str`): Optional. Username of a bot, which will be used for user - authorization. See - `Setting up a bot `_ - for more details. If not specified, the current - bot's username will be assumed. The url's domain must be the same as the domain linked - with the bot. See - `Linking your domain to the bot - `_ - for more details. - request_write_access (:obj:`bool`): Optional. Pass :obj:`True` to request the permission - for your bot to send messages to the user. - - """ - - __slots__ = ("bot_username", "forward_text", "request_write_access", "url") - - def __init__( - self, - url: str, - forward_text: Optional[str] = None, - bot_username: Optional[str] = None, - request_write_access: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.url: str = url - # Optional - self.forward_text: Optional[str] = forward_text - self.bot_username: Optional[str] = bot_username - self.request_write_access: Optional[bool] = request_write_access - - self._id_attrs = (self.url,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_menubutton.py b/venv/lib/python3.11/site-packages/telegram/_menubutton.py deleted file mode 100755 index 76c0ee4..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_menubutton.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 objects related to Telegram menu buttons.""" -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.types import JSONDict -from telegram._webappinfo import WebAppInfo - -if TYPE_CHECKING: - from telegram import Bot - - -class MenuButton(TelegramObject): - """This object describes the bot's menu button in a private chat. It should be one of - - * :class:`telegram.MenuButtonCommands` - * :class:`telegram.MenuButtonWebApp` - * :class:`telegram.MenuButtonDefault` - - If a menu button other than :class:`telegram.MenuButtonDefault` is set for a private chat, - then it is applied in the chat. Otherwise the default menu button is applied. By default, the - menu button opens the list of bot commands. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` is equal. For subclasses with additional attributes, - the notion of equality is overridden. - - .. versionadded:: 20.0 - - Args: - type (:obj:`str`): Type of menu button that the instance represents. - - Attributes: - type (:obj:`str`): Type of menu button that the instance represents. - """ - - __slots__ = ("type",) - - def __init__( - self, - type: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): # pylint: disable=redefined-builtin - super().__init__(api_kwargs=api_kwargs) - self.type: str = enum.get_member(constants.MenuButtonType, type, type) - - self._id_attrs = (self.type,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MenuButton"]: - """Converts JSON data to the appropriate :class:`MenuButton` object, i.e. takes - care of selecting the correct subclass. - - 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. - - """ - data = cls._parse_data(data) - - if data is None: - return None - - if not data and cls is MenuButton: - return None - - _class_mapping: dict[str, type[MenuButton]] = { - cls.COMMANDS: MenuButtonCommands, - cls.WEB_APP: MenuButtonWebApp, - cls.DEFAULT: MenuButtonDefault, - } - - if cls is MenuButton and data.get("type") in _class_mapping: - return _class_mapping[data.pop("type")].de_json(data, bot=bot) - return super().de_json(data=data, bot=bot) - - COMMANDS: Final[str] = constants.MenuButtonType.COMMANDS - """:const:`telegram.constants.MenuButtonType.COMMANDS`""" - WEB_APP: Final[str] = constants.MenuButtonType.WEB_APP - """:const:`telegram.constants.MenuButtonType.WEB_APP`""" - DEFAULT: Final[str] = constants.MenuButtonType.DEFAULT - """:const:`telegram.constants.MenuButtonType.DEFAULT`""" - - -class MenuButtonCommands(MenuButton): - """Represents a menu button, which opens the bot's list of commands. - - .. include:: inclusions/menu_button_command_video.rst - - .. versionadded:: 20.0 - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.MenuButtonType.COMMANDS`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=constants.MenuButtonType.COMMANDS, api_kwargs=api_kwargs) - self._freeze() - - -class MenuButtonWebApp(MenuButton): - """Represents a menu button, which launches a - `Web App `_. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type`, :attr:`text` and :attr:`web_app` - are equal. - - .. versionadded:: 20.0 - - Args: - text (:obj:`str`): Text of the button. - web_app (:class:`telegram.WebAppInfo`): Description of the Web App that will be launched - when the user presses the button. The Web App will be able to send an arbitrary - message on behalf of the user using the method :meth:`~telegram.Bot.answerWebAppQuery` - of :class:`~telegram.Bot`. Alternatively, a ``t.me`` link to a Web App of the bot can - be specified in the object instead of the Web App's URL, in which case the Web App - will be opened as if the user pressed the link. - - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.MenuButtonType.WEB_APP`. - text (:obj:`str`): Text of the button. - web_app (:class:`telegram.WebAppInfo`): Description of the Web App that will be launched - when the user presses the button. The Web App will be able to send an arbitrary - message on behalf of the user using the method :meth:`~telegram.Bot.answerWebAppQuery` - of :class:`~telegram.Bot`. Alternatively, a ``t.me`` link to a Web App of the bot can - be specified in the object instead of the Web App's URL, in which case the Web App - will be opened as if the user pressed the link. - """ - - __slots__ = ("text", "web_app") - - def __init__(self, text: str, web_app: WebAppInfo, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=constants.MenuButtonType.WEB_APP, api_kwargs=api_kwargs) - with self._unfrozen(): - self.text: str = text - self.web_app: WebAppInfo = web_app - - self._id_attrs = (self.type, self.text, self.web_app) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MenuButtonWebApp"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot) - - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class MenuButtonDefault(MenuButton): - """Describes that no specific value for the menu button was set. - - .. versionadded:: 20.0 - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.MenuButtonType.DEFAULT`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=constants.MenuButtonType.DEFAULT, api_kwargs=api_kwargs) - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_message.py b/venv/lib/python3.11/site-packages/telegram/_message.py deleted file mode 100755 index df8ea36..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_message.py +++ /dev/null @@ -1,5160 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=too-many-instance-attributes, 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 Message.""" - -import datetime as dtm -import re -from collections.abc import Sequence -from html import escape -from typing import TYPE_CHECKING, Optional, TypedDict, Union - -from telegram._chat import Chat -from telegram._chatbackground import ChatBackground -from telegram._chatboost import ChatBoostAdded -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._forumtopic import ( - ForumTopicClosed, - ForumTopicCreated, - ForumTopicEdited, - ForumTopicReopened, - GeneralForumTopicHidden, - GeneralForumTopicUnhidden, -) -from telegram._games.game import Game -from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from telegram._linkpreviewoptions import LinkPreviewOptions -from telegram._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged -from telegram._messageentity import MessageEntity -from telegram._paidmedia import PaidMediaInfo -from telegram._passport.passportdata import PassportData -from telegram._payment.invoice import Invoice -from telegram._payment.refundedpayment import RefundedPayment -from telegram._payment.successfulpayment import SuccessfulPayment -from telegram._poll import Poll -from telegram._proximityalerttriggered import ProximityAlertTriggered -from telegram._reply import ReplyParameters -from telegram._shared import ChatShared, UsersShared -from telegram._story import Story -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.defaultvalue import DEFAULT_NONE, DefaultValue -from telegram._utils.entities import parse_message_entities, parse_message_entity -from telegram._utils.strings import TextEncoding -from telegram._utils.types import ( - CorrectOptionID, - FileInput, - JSONDict, - MarkdownVersion, - ODVInput, - ReplyMarkup, -) -from telegram._utils.warnings import warn -from telegram._videochat import ( - VideoChatEnded, - VideoChatParticipantsInvited, - VideoChatScheduled, - VideoChatStarted, -) -from telegram._webappdata import WebAppData -from telegram._writeaccessallowed import WriteAccessAllowed -from telegram.constants import ZERO_DATE, MessageAttachmentType, ParseMode -from telegram.helpers import escape_markdown -from telegram.warnings import PTBDeprecationWarning - -if TYPE_CHECKING: - from telegram import ( - Bot, - ExternalReplyInfo, - GameHighScore, - Giveaway, - GiveawayCompleted, - GiveawayCreated, - GiveawayWinners, - InputMedia, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - InputPaidMedia, - InputPollOption, - LabeledPrice, - MessageId, - MessageOrigin, - ReactionType, - TextQuote, - ) - - -class _ReplyKwargs(TypedDict): - __slots__ = ("chat_id", "reply_parameters") # type: ignore[misc] - - chat_id: Union[str, int] - reply_parameters: ReplyParameters - - -class MaybeInaccessibleMessage(TelegramObject): - """Base class for Telegram Message Objects. - - Currently, that includes :class:`telegram.Message` and :class:`telegram.InaccessibleMessage`. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_id` and :attr:`chat` are equal - - .. versionchanged:: 21.0 - ``__bool__`` is no longer overriden and defaults to Pythons standard implementation. - - .. versionadded:: 20.8 - - Args: - message_id (:obj:`int`): Unique message identifier. - date (:class:`datetime.datetime`): Date the message was sent in Unix time or 0 in Unix - time. Converted to :class:`datetime.datetime` - - |datetime_localization| - chat (:class:`telegram.Chat`): Conversation the message belongs to. - - Attributes: - message_id (:obj:`int`): Unique message identifier. - date (:class:`datetime.datetime`): Date the message was sent in Unix time or 0 in Unix - time. Converted to :class:`datetime.datetime` - - |datetime_localization| - chat (:class:`telegram.Chat`): Conversation the message belongs to. - """ - - __slots__ = ("chat", "date", "message_id") - - def __init__( - self, - chat: Chat, - message_id: int, - date: dtm.datetime, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.chat: Chat = chat - self.message_id: int = message_id - self.date: dtm.datetime = date - - self._id_attrs = (self.message_id, self.chat) - - self._freeze() - - @property - def is_accessible(self) -> bool: - """Convenience attribute. :obj:`True`, if the date is not 0 in Unix time. - - .. versionadded:: 20.8 - """ - # Once we drop support for python 3.9, this can be made a TypeGuard function: - # def is_accessible(self) -> TypeGuard[Message]: - return self.date != ZERO_DATE - - @classmethod - def _de_json( - cls, - data: Optional[JSONDict], - bot: Optional["Bot"] = None, - api_kwargs: Optional[JSONDict] = None, - ) -> Optional["MaybeInaccessibleMessage"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - if cls is MaybeInaccessibleMessage: - if data["date"] == 0: - return InaccessibleMessage.de_json(data=data, bot=bot) - return Message.de_json(data=data, bot=bot) - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - # this is to include the Literal from InaccessibleMessage - if data["date"] == 0: - data["date"] = ZERO_DATE - else: - data["date"] = from_timestamp(data["date"], tzinfo=loc_tzinfo) - - data["chat"] = Chat.de_json(data.get("chat"), bot) - return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) - - -class InaccessibleMessage(MaybeInaccessibleMessage): - """This object represents an inaccessible message. - - These are messages that are e.g. deleted. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_id` and :attr:`chat` are equal - - .. versionadded:: 20.8 - - Args: - message_id (:obj:`int`): Unique message identifier. - chat (:class:`telegram.Chat`): Chat the message belongs to. - - Attributes: - message_id (:obj:`int`): Unique message identifier. - date (:class:`constants.ZERO_DATE`): Always :tg-const:`telegram.constants.ZERO_DATE`. - The field can be used to differentiate regular and inaccessible messages. - chat (:class:`telegram.Chat`): Chat the message belongs to. - """ - - __slots__ = () - - def __init__( - self, - chat: Chat, - message_id: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(chat=chat, message_id=message_id, date=ZERO_DATE, api_kwargs=api_kwargs) - self._freeze() - - -class Message(MaybeInaccessibleMessage): - # fmt: off - """This object represents a message. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_id` and :attr:`chat` are equal. - - Note: - In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - - .. versionchanged:: 21.0 - Removed deprecated arguments and attributes ``user_shared``, ``forward_from``, - ``forward_from_chat``, ``forward_from_message_id``, ``forward_signature``, - ``forward_sender_name`` and ``forward_date``. - - .. versionchanged:: 20.8 - * This class is now a subclass of :class:`telegram.MaybeInaccessibleMessage`. - * The :paramref:`pinned_message` now can be either :class:`telegram.Message` or - :class:`telegram.InaccessibleMessage`. - - .. versionchanged:: 20.0 - - * The arguments and attributes ``voice_chat_scheduled``, ``voice_chat_started`` and - ``voice_chat_ended``, ``voice_chat_participants_invited`` were renamed to - :paramref:`video_chat_scheduled`/:attr:`video_chat_scheduled`, - :paramref:`video_chat_started`/:attr:`video_chat_started`, - :paramref:`video_chat_ended`/:attr:`video_chat_ended` and - :paramref:`video_chat_participants_invited`/:attr:`video_chat_participants_invited`, - respectively, in accordance to Bot API 6.0. - * The following are now keyword-only arguments in Bot methods: - ``{read, write, connect, pool}_timeout``, ``api_kwargs``, ``contact``, ``quote``, - ``filename``, ``loaction``, ``venue``. Use a named argument for those, - and notice that some positional arguments changed position as a result. - - Args: - message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances - (e.g., message containing a video sent to a big chat), the server might automatically - schedule a message instead of sending it immediately. In such cases, this field will be - ``0`` and the relevant message will be unusable until it is actually sent. - from_user (:class:`telegram.User`, optional): Sender of the message; may be empty for - messages sent to channels. For backward compatibility, if the message was sent on - behalf of a chat, the field contains a fake sender user in non-channel chats. - sender_chat (:class:`telegram.Chat`, optional): Sender of the message when sent on behalf - of a chat. For example, the supergroup itself for messages sent by its anonymous - administrators or a linked channel for messages automatically forwarded to the - channel's discussion group. For backward compatibility, if the message was sent on - behalf of a chat, the field from contains a fake sender user in non-channel chats. - date (:class:`datetime.datetime`): Date the message was sent in Unix time. Converted to - :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - chat (:class:`telegram.Chat`): Conversation the message belongs to. - is_automatic_forward (:obj:`bool`, optional): :obj:`True`, if the message is a channel - post that was automatically forwarded to the connected discussion group. - - .. versionadded:: 13.9 - reply_to_message (:class:`telegram.Message`, optional): For replies, the original message. - Note that the Message object in this field will not contain further - ``reply_to_message`` fields even if it itself is a reply. - edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix - time. Converted to :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - has_protected_content (:obj:`bool`, optional): :obj:`True`, if the message can't be - forwarded. - - .. versionadded:: 13.9 - is_from_offline (:obj:`bool`, optional): :obj:`True`, if the message was sent - by an implicit action, for example, as an away or a greeting business message, - or as a scheduled message. - - .. versionadded:: 21.1 - media_group_id (:obj:`str`, optional): The unique identifier of a media message group this - message belongs to. - text (:obj:`str`, optional): For text messages, the actual UTF-8 text of the message, - 0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters. - entities (Sequence[:class:`telegram.MessageEntity`], optional): For text messages, special - entities like usernames, URLs, bot commands, etc. that appear in the text. See - :attr:`parse_entity` and :attr:`parse_entities` methods for how to use properly. - This list is empty if the message does not contain entities. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - link_preview_options (:class:`telegram.LinkPreviewOptions`, optional): Options used for - link preview generation for the message, if it is a text message and link preview - options were changed. - - .. versionadded:: 20.8 - - effect_id (:obj:`str`, optional): Unique identifier of the message effect added to the - message. - - .. versionadded:: 21.3 - - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): For messages with a - Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the - caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities` - methods for how to use properly. This list is empty if the message does not contain - caption entities. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - show_caption_above_media (:obj:`bool`, optional): |show_cap_above_med| - - .. versionadded:: 21.3 - 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. - animation (:class:`telegram.Animation`, optional): Message is an animation, information - about the animation. For backward compatibility, when this field is set, the document - field will also be set. - game (:class:`telegram.Game`, optional): Message is a game, information about the game. - :ref:`More about games >> `. - photo (Sequence[:class:`telegram.PhotoSize`], optional): Message is a photo, available - sizes of the photo. This list is empty if the message does not contain a photo. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information - about the sticker. - story (:class:`telegram.Story`, optional): Message is a forwarded story. - - .. versionadded:: 20.5 - video (:class:`telegram.Video`, optional): Message is a video, information about the - video. - voice (:class:`telegram.Voice`, optional): Message is a voice message, information about - the file. - video_note (:class:`telegram.VideoNote`, optional): Message is a - `video note `_, information - about the video message. - new_chat_members (Sequence[:class:`telegram.User`], optional): New members that were added - to the group or supergroup and information about them (the bot itself may be one of - these members). This list is empty if the message does not contain new chat members. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - caption (:obj:`str`, optional): Caption for the animation, audio, document, paid media, - photo, video - or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters. - contact (:class:`telegram.Contact`, optional): Message is a shared contact, information - about the contact. - location (:class:`telegram.Location`, optional): Message is a shared location, information - about the location. - venue (:class:`telegram.Venue`, optional): Message is a venue, information about the - venue. For backward compatibility, when this field is set, the location field will - also be set. - left_chat_member (:class:`telegram.User`, optional): A member was removed from the group, - information about them (this member may be the bot itself). - new_chat_title (:obj:`str`, optional): A chat title was changed to this value. - new_chat_photo (Sequence[:class:`telegram.PhotoSize`], optional): A chat photo was changed - to this value. This list is empty if the message does not contain a new chat photo. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - delete_chat_photo (:obj:`bool`, optional): Service message: The chat photo was deleted. - group_chat_created (:obj:`bool`, optional): Service message: The group has been created. - supergroup_chat_created (:obj:`bool`, optional): Service message: The supergroup has been - created. This field can't be received in a message coming through updates, because bot - can't be a member of a supergroup when it is created. It can only be found in - :attr:`reply_to_message` if someone replies to a very first message in a directly - created supergroup. - channel_chat_created (:obj:`bool`, optional): Service message: The channel has been - created. This field can't be received in a message coming through updates, because bot - can't be a member of a channel when it is created. It can only be found in - :attr:`reply_to_message` if someone replies to a very first message in a channel. - message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`, \ - optional): Service message: auto-delete timer settings changed in the chat. - - .. versionadded:: 13.4 - migrate_to_chat_id (:obj:`int`, optional): The group has been migrated to a supergroup - with the specified identifier. - migrate_from_chat_id (:obj:`int`, optional): The supergroup has been migrated from a group - with the specified identifier. - pinned_message (:class:`telegram.MaybeInaccessibleMessage`, optional): Specified message - was pinned. Note that the Message object in this field will not contain further - :attr:`reply_to_message` fields even if it is itself a reply. - - .. versionchanged:: 20.8 - This attribute now is either :class:`telegram.Message` or - :class:`telegram.InaccessibleMessage`. - invoice (:class:`telegram.Invoice`, optional): Message is an invoice for a payment, - information about the invoice. - :ref:`More about payments >> `. - successful_payment (:class:`telegram.SuccessfulPayment`, optional): Message is a service - message about a successful payment, information about the payment. - :ref:`More about payments >> `. - connected_website (:obj:`str`, optional): The domain name of the website on which the user - has logged in. - `More about Telegram Login >> `_. - author_signature (:obj:`str`, optional): Signature of the post author for messages in - channels, or the custom title of an anonymous group administrator. - passport_data (:class:`telegram.PassportData`, optional): Telegram Passport data. - poll (:class:`telegram.Poll`, optional): Message is a native poll, - information about the poll. - dice (:class:`telegram.Dice`, optional): Message is a dice with random value. - via_bot (:class:`telegram.User`, optional): Bot through which message was sent. - proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`, optional): Service - message. A user in the chat triggered another user's proximity alert while sharing - Live Location. - video_chat_scheduled (:class:`telegram.VideoChatScheduled`, optional): Service message: - video chat scheduled. - - .. versionadded:: 20.0 - video_chat_started (:class:`telegram.VideoChatStarted`, optional): Service message: video - chat started. - - .. versionadded:: 20.0 - video_chat_ended (:class:`telegram.VideoChatEnded`, optional): Service message: video chat - ended. - - .. versionadded:: 20.0 - video_chat_participants_invited (:class:`telegram.VideoChatParticipantsInvited` optional): - Service message: new participants invited to a video chat. - - .. versionadded:: 20.0 - web_app_data (:class:`telegram.WebAppData`, optional): Service message: data sent by a Web - App. - - .. versionadded:: 20.0 - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. :paramref:`~telegram.InlineKeyboardButton.login_url` buttons are - represented as ordinary url buttons. - is_topic_message (:obj:`bool`, optional): :obj:`True`, if the message is sent to a forum - topic. - - .. versionadded:: 20.0 - message_thread_id (:obj:`int`, optional): Unique identifier of a message thread to which - the message belongs; for supergroups only. - - .. versionadded:: 20.0 - forum_topic_created (:class:`telegram.ForumTopicCreated`, optional): Service message: - forum topic created. - - .. versionadded:: 20.0 - forum_topic_closed (:class:`telegram.ForumTopicClosed`, optional): Service message: - forum topic closed. - - .. versionadded:: 20.0 - forum_topic_reopened (:class:`telegram.ForumTopicReopened`, optional): Service message: - forum topic reopened. - - .. versionadded:: 20.0 - forum_topic_edited (:class:`telegram.ForumTopicEdited`, optional): Service message: - forum topic edited. - - .. versionadded:: 20.0 - general_forum_topic_hidden (:class:`telegram.GeneralForumTopicHidden`, optional): - Service message: General forum topic hidden. - - .. versionadded:: 20.0 - general_forum_topic_unhidden (:class:`telegram.GeneralForumTopicUnhidden`, optional): - Service message: General forum topic unhidden. - - .. versionadded:: 20.0 - write_access_allowed (:class:`telegram.WriteAccessAllowed`, optional): Service message: - the user allowed the bot to write messages after adding it to the attachment or side - menu, launching a Web App from a link, or accepting an explicit request from a Web App - sent by the method - `requestWriteAccess `_. - - .. versionadded:: 20.0 - has_media_spoiler (:obj:`bool`, optional): :obj:`True`, if the message media is covered - by a spoiler animation. - - .. versionadded:: 20.0 - users_shared (:class:`telegram.UsersShared`, optional): Service message: users were shared - with the bot - - .. versionadded:: 20.8 - chat_shared (:class:`telegram.ChatShared`, optional):Service message: a chat was shared - with the bot. - - .. versionadded:: 20.1 - giveaway_created (:class:`telegram.GiveawayCreated`, optional): Service message: a - scheduled giveaway was created - - .. versionadded:: 20.8 - giveaway (:class:`telegram.Giveaway`, optional): The message is a scheduled giveaway - message - - .. versionadded:: 20.8 - giveaway_winners (:class:`telegram.GiveawayWinners`, optional): A giveaway with public - winners was completed - - .. versionadded:: 20.8 - giveaway_completed (:class:`telegram.GiveawayCompleted`, optional): Service message: a - giveaway without public winners was completed - - .. versionadded:: 20.8 - external_reply (:class:`telegram.ExternalReplyInfo`, optional): Information about the - message that is being replied to, which may come from another chat or forum topic. - - .. versionadded:: 20.8 - quote (:class:`telegram.TextQuote`, optional): For replies that quote part of the original - message, the quoted part of the message. - - .. versionadded:: 20.8 - forward_origin (:class:`telegram.MessageOrigin`, optional): Information about the original - message for forwarded messages - - .. versionadded:: 20.8 - reply_to_story (:class:`telegram.Story`, optional): For replies to a story, the original - story. - - .. versionadded:: 21.0 - boost_added (:class:`telegram.ChatBoostAdded`, optional): Service message: user boosted - the chat. - - .. versionadded:: 21.0 - sender_boost_count (:obj:`int`, optional): If the sender of the - message boosted the chat, the number of boosts added by the user. - - .. versionadded:: 21.0 - business_connection_id (:obj:`str`, optional): Unique identifier of the business connection - from which the message was received. If non-empty, the message belongs to a chat of the - corresponding business account that is independent from any potential bot chat which - might share the same identifier. - - .. versionadded:: 21.1 - - sender_business_bot (:class:`telegram.User`, optional): The bot that actually sent the - message on behalf of the business account. Available only for outgoing messages sent - on behalf of the connected business account. - - .. versionadded:: 21.1 - - chat_background_set (:class:`telegram.ChatBackground`, optional): Service message: chat - background set. - - .. versionadded:: 21.2 - paid_media (:class:`telegram.PaidMediaInfo`, optional): Message contains paid media; - information about the paid media. - - .. versionadded:: 21.4 - refunded_payment (:class:`telegram.RefundedPayment`, optional): Message is a service - message about a refunded payment, information about the payment. - - .. versionadded:: 21.4 - - Attributes: - message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances - (e.g., message containing a video sent to a big chat), the server might automatically - schedule a message instead of sending it immediately. In such cases, this field will be - ``0`` and the relevant message will be unusable until it is actually sent. - from_user (:class:`telegram.User`): Optional. Sender of the message; may be empty for - messages sent to channels. For backward compatibility, if the message was sent on - behalf of a chat, the field contains a fake sender user in non-channel chats. - sender_chat (:class:`telegram.Chat`): Optional. Sender of the message when sent on behalf - of a chat. For example, the supergroup itself for messages sent by its anonymous - administrators or a linked channel for messages automatically forwarded to the - channel's discussion group. For backward compatibility, if the message was sent on - behalf of a chat, the field from contains a fake sender user in non-channel chats. - date (:class:`datetime.datetime`): Date the message was sent in Unix time. Converted to - :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - chat (:class:`telegram.Chat`): Conversation the message belongs to. - is_automatic_forward (:obj:`bool`): Optional. :obj:`True`, if the message is a channel - post that was automatically forwarded to the connected discussion group. - - .. versionadded:: 13.9 - reply_to_message (:class:`telegram.Message`): Optional. For replies, the original message. - Note that the Message object in this field will not contain further - ``reply_to_message`` fields even if it itself is a reply. - edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited in Unix - time. Converted to :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - has_protected_content (:obj:`bool`): Optional. :obj:`True`, if the message can't be - forwarded. - - .. versionadded:: 13.9 - is_from_offline (:obj:`bool`): Optional. :obj:`True`, if the message was sent - by an implicit action, for example, as an away or a greeting business message, - or as a scheduled message. - - .. versionadded:: 21.1 - media_group_id (:obj:`str`): Optional. The unique identifier of a media message group this - message belongs to. - text (:obj:`str`): Optional. For text messages, the actual UTF-8 text of the message, - 0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters. - entities (tuple[:class:`telegram.MessageEntity`]): Optional. For text messages, special - entities like usernames, URLs, bot commands, etc. that appear in the text. See - :attr:`parse_entity` and :attr:`parse_entities` methods for how to use properly. - This list is empty if the message does not contain entities. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - link_preview_options (:class:`telegram.LinkPreviewOptions`): Optional. Options used for - link preview generation for the message, if it is a text message and link preview - options were changed. - - .. versionadded:: 20.8 - - effect_id (:obj:`str`): Optional. Unique identifier of the message effect added to the - message. - - ..versionadded:: 21.3 - - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. For messages with a - Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the - caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities` - methods for how to use properly. This list is empty if the message does not contain - caption entities. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - audio (:class:`telegram.Audio`): Optional. Message is an audio file, information - about the file. - - .. seealso:: :wiki:`Working with Files and Media ` - document (:class:`telegram.Document`): Optional. Message is a general file, information - about the file. - - .. seealso:: :wiki:`Working with Files and Media ` - animation (:class:`telegram.Animation`): Optional. Message is an animation, information - about the animation. For backward compatibility, when this field is set, the document - field will also be set. - - .. seealso:: :wiki:`Working with Files and Media ` - game (:class:`telegram.Game`): Optional. Message is a game, information about the game. - :ref:`More about games >> `. - photo (tuple[:class:`telegram.PhotoSize`]): Optional. Message is a photo, available - sizes of the photo. This list is empty if the message does not contain a photo. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.0 - |tupleclassattrs| - - sticker (:class:`telegram.Sticker`): Optional. Message is a sticker, information - about the sticker. - - .. seealso:: :wiki:`Working with Files and Media ` - story (:class:`telegram.Story`): Optional. Message is a forwarded story. - - .. versionadded:: 20.5 - video (:class:`telegram.Video`): Optional. Message is a video, information about the - video. - - .. seealso:: :wiki:`Working with Files and Media ` - voice (:class:`telegram.Voice`): Optional. Message is a voice message, information about - the file. - - .. seealso:: :wiki:`Working with Files and Media ` - video_note (:class:`telegram.VideoNote`): Optional. Message is a - `video note `_, information - about the video message. - - .. seealso:: :wiki:`Working with Files and Media ` - new_chat_members (tuple[:class:`telegram.User`]): Optional. New members that were added - to the group or supergroup and information about them (the bot itself may be one of - these members). This list is empty if the message does not contain new chat members. - - .. versionchanged:: 20.0 - |tupleclassattrs| - caption (:obj:`str`): Optional. Caption for the animation, audio, document, paid media, - photo, video - or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters. - contact (:class:`telegram.Contact`): Optional. Message is a shared contact, information - about the contact. - location (:class:`telegram.Location`): Optional. Message is a shared location, information - about the location. - venue (:class:`telegram.Venue`): Optional. Message is a venue, information about the - venue. For backward compatibility, when this field is set, the location field will - also be set. - left_chat_member (:class:`telegram.User`): Optional. A member was removed from the group, - information about them (this member may be the bot itself). - new_chat_title (:obj:`str`): Optional. A chat title was changed to this value. - new_chat_photo (tuple[:class:`telegram.PhotoSize`]): A chat photo was changed to - this value. This list is empty if the message does not contain a new chat photo. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - delete_chat_photo (:obj:`bool`): Optional. Service message: The chat photo was deleted. - group_chat_created (:obj:`bool`): Optional. Service message: The group has been created. - supergroup_chat_created (:obj:`bool`): Optional. Service message: The supergroup has been - created. This field can't be received in a message coming through updates, because bot - can't be a member of a supergroup when it is created. It can only be found in - :attr:`reply_to_message` if someone replies to a very first message in a directly - created supergroup. - channel_chat_created (:obj:`bool`): Optional. Service message: The channel has been - created. This field can't be received in a message coming through updates, because bot - can't be a member of a channel when it is created. It can only be found in - :attr:`reply_to_message` if someone replies to a very first message in a channel. - message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`): - Optional. Service message: auto-delete timer settings changed in the chat. - - .. versionadded:: 13.4 - migrate_to_chat_id (:obj:`int`): Optional. The group has been migrated to a supergroup - with the specified identifier. - migrate_from_chat_id (:obj:`int`): Optional. The supergroup has been migrated from a group - with the specified identifier. - pinned_message (:class:`telegram.MaybeInaccessibleMessage`): Optional. Specified message - was pinned. Note that the Message object in this field will not contain further - :attr:`reply_to_message` fields even if it is itself a reply. - - .. versionchanged:: 20.8 - This attribute now is either :class:`telegram.Message` or - :class:`telegram.InaccessibleMessage`. - invoice (:class:`telegram.Invoice`): Optional. Message is an invoice for a payment, - information about the invoice. - :ref:`More about payments >> `. - successful_payment (:class:`telegram.SuccessfulPayment`): Optional. Message is a service - message about a successful payment, information about the payment. - :ref:`More about payments >> `. - connected_website (:obj:`str`): Optional. The domain name of the website on which the user - has logged in. - `More about Telegram Login >> `_. - author_signature (:obj:`str`): Optional. Signature of the post author for messages in - channels, or the custom title of an anonymous group administrator. - passport_data (:class:`telegram.PassportData`): Optional. Telegram Passport data. - - Examples: - :any:`Passport Bot ` - poll (:class:`telegram.Poll`): Optional. Message is a native poll, - information about the poll. - dice (:class:`telegram.Dice`): Optional. Message is a dice with random value. - via_bot (:class:`telegram.User`): Optional. Bot through which message was sent. - proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`): Optional. Service - message. A user in the chat triggered another user's proximity alert while sharing - Live Location. - video_chat_scheduled (:class:`telegram.VideoChatScheduled`): Optional. Service message: - video chat scheduled. - - .. versionadded:: 20.0 - video_chat_started (:class:`telegram.VideoChatStarted`): Optional. Service message: video - chat started. - - .. versionadded:: 20.0 - video_chat_ended (:class:`telegram.VideoChatEnded`): Optional. Service message: video chat - ended. - - .. versionadded:: 20.0 - video_chat_participants_invited (:class:`telegram.VideoChatParticipantsInvited`): Optional. - Service message: new participants invited to a video chat. - - .. versionadded:: 20.0 - web_app_data (:class:`telegram.WebAppData`): Optional. Service message: data sent by a Web - App. - - .. versionadded:: 20.0 - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. :paramref:`~telegram.InlineKeyboardButton.login_url` buttons are - represented as ordinary url buttons. - is_topic_message (:obj:`bool`): Optional. :obj:`True`, if the message is sent to a forum - topic. - - .. versionadded:: 20.0 - message_thread_id (:obj:`int`): Optional. Unique identifier of a message thread to which - the message belongs; for supergroups only. - - .. versionadded:: 20.0 - forum_topic_created (:class:`telegram.ForumTopicCreated`): Optional. Service message: - forum topic created. - - .. versionadded:: 20.0 - forum_topic_closed (:class:`telegram.ForumTopicClosed`): Optional. Service message: - forum topic closed. - - .. versionadded:: 20.0 - forum_topic_reopened (:class:`telegram.ForumTopicReopened`): Optional. Service message: - forum topic reopened. - - .. versionadded:: 20.0 - forum_topic_edited (:class:`telegram.ForumTopicEdited`): Optional. Service message: - forum topic edited. - - .. versionadded:: 20.0 - general_forum_topic_hidden (:class:`telegram.GeneralForumTopicHidden`): Optional. - Service message: General forum topic hidden. - - .. versionadded:: 20.0 - general_forum_topic_unhidden (:class:`telegram.GeneralForumTopicUnhidden`): Optional. - Service message: General forum topic unhidden. - - .. versionadded:: 20.0 - write_access_allowed (:class:`telegram.WriteAccessAllowed`): Optional. Service message: - the user allowed the bot added to the attachment menu to write messages. - - .. versionadded:: 20.0 - has_media_spoiler (:obj:`bool`): Optional. :obj:`True`, if the message media is covered - by a spoiler animation. - - .. versionadded:: 20.0 - users_shared (:class:`telegram.UsersShared`): Optional. Service message: users were shared - with the bot - - .. versionadded:: 20.8 - chat_shared (:class:`telegram.ChatShared`): Optional. Service message: a chat was shared - with the bot. - - .. versionadded:: 20.1 - giveaway_created (:class:`telegram.GiveawayCreated`): Optional. Service message: a - scheduled giveaway was created - - .. versionadded:: 20.8 - giveaway (:class:`telegram.Giveaway`): Optional. The message is a scheduled giveaway - message - - .. versionadded:: 20.8 - giveaway_winners (:class:`telegram.GiveawayWinners`): Optional. A giveaway with public - winners was completed - - .. versionadded:: 20.8 - giveaway_completed (:class:`telegram.GiveawayCompleted`): Optional. Service message: a - giveaway without public winners was completed - - .. versionadded:: 20.8 - external_reply (:class:`telegram.ExternalReplyInfo`): Optional. Information about the - message that is being replied to, which may come from another chat or forum topic. - - .. versionadded:: 20.8 - quote (:class:`telegram.TextQuote`): Optional. For replies that quote part of the original - message, the quoted part of the message. - - .. versionadded:: 20.8 - forward_origin (:class:`telegram.MessageOrigin`): Optional. Information about the original - message for forwarded messages - - .. versionadded:: 20.8 - reply_to_story (:class:`telegram.Story`): Optional. For replies to a story, the original - story. - - .. versionadded:: 21.0 - boost_added (:class:`telegram.ChatBoostAdded`): Optional. Service message: user boosted - the chat. - - .. versionadded:: 21.0 - sender_boost_count (:obj:`int`): Optional. If the sender of the - message boosted the chat, the number of boosts added by the user. - - .. versionadded:: 21.0 - - business_connection_id (:obj:`str`): Optional. Unique identifier of the business connection - from which the message was received. If non-empty, the message belongs to a chat of the - corresponding business account that is independent from any potential bot chat which - might share the same identifier. - - .. versionadded:: 21.1 - - sender_business_bot (:class:`telegram.User`): Optional. The bot that actually sent the - message on behalf of the business account. Available only for outgoing messages sent - on behalf of the connected business account. - - .. versionadded:: 21.1 - - chat_background_set (:class:`telegram.ChatBackground`): Optional. Service message: chat - background set - - .. versionadded:: 21.2 - paid_media (:class:`telegram.PaidMediaInfo`): Optional. Message contains paid media; - information about the paid media. - - .. versionadded:: 21.4 - refunded_payment (:class:`telegram.RefundedPayment`): Optional. Message is a service - message about a refunded payment, information about the payment. - - .. versionadded:: 21.4 - - .. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by - :attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a - :exc:`ValueError` when encountering a custom emoji. - - .. |blockquote_no_md1_support| replace:: Since block quotation entities are not supported - by :attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a - :exc:`ValueError` when encountering a block quotation. - - .. |reply_same_thread| replace:: If :paramref:`message_thread_id` is not provided, - this will reply to the same thread (topic) of the original message. - """ - - # fmt: on - __slots__ = ( - "_effective_attachment", - "animation", - "audio", - "author_signature", - "boost_added", - "business_connection_id", - "caption", - "caption_entities", - "channel_chat_created", - "chat_background_set", - "chat_shared", - "connected_website", - "contact", - "delete_chat_photo", - "dice", - "document", - "edit_date", - "effect_id", - "entities", - "external_reply", - "forum_topic_closed", - "forum_topic_created", - "forum_topic_edited", - "forum_topic_reopened", - "forward_origin", - "from_user", - "game", - "general_forum_topic_hidden", - "general_forum_topic_unhidden", - "giveaway", - "giveaway_completed", - "giveaway_created", - "giveaway_winners", - "group_chat_created", - "has_media_spoiler", - "has_protected_content", - "invoice", - "is_automatic_forward", - "is_from_offline", - "is_topic_message", - "left_chat_member", - "link_preview_options", - "location", - "media_group_id", - "message_auto_delete_timer_changed", - "message_thread_id", - "migrate_from_chat_id", - "migrate_to_chat_id", - "new_chat_members", - "new_chat_photo", - "new_chat_title", - "paid_media", - "passport_data", - "photo", - "pinned_message", - "poll", - "proximity_alert_triggered", - "quote", - "refunded_payment", - "reply_markup", - "reply_to_message", - "reply_to_story", - "sender_boost_count", - "sender_business_bot", - "sender_chat", - "show_caption_above_media", - "sticker", - "story", - "successful_payment", - "supergroup_chat_created", - "text", - "users_shared", - "venue", - "via_bot", - "video", - "video_chat_ended", - "video_chat_participants_invited", - "video_chat_scheduled", - "video_chat_started", - "video_note", - "voice", - "web_app_data", - "write_access_allowed", - ) - - def __init__( - self, - message_id: int, - date: dtm.datetime, - chat: Chat, - from_user: Optional[User] = None, - reply_to_message: Optional["Message"] = None, - edit_date: Optional[dtm.datetime] = None, - text: Optional[str] = None, - entities: Optional[Sequence["MessageEntity"]] = None, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - audio: Optional[Audio] = None, - document: Optional[Document] = None, - game: Optional[Game] = None, - photo: Optional[Sequence[PhotoSize]] = None, - sticker: Optional[Sticker] = None, - video: Optional[Video] = None, - voice: Optional[Voice] = None, - video_note: Optional[VideoNote] = None, - new_chat_members: Optional[Sequence[User]] = None, - caption: Optional[str] = None, - contact: Optional[Contact] = None, - location: Optional[Location] = None, - venue: Optional[Venue] = None, - left_chat_member: Optional[User] = None, - new_chat_title: Optional[str] = None, - new_chat_photo: Optional[Sequence[PhotoSize]] = None, - delete_chat_photo: Optional[bool] = None, - group_chat_created: Optional[bool] = None, - supergroup_chat_created: Optional[bool] = None, - channel_chat_created: Optional[bool] = None, - migrate_to_chat_id: Optional[int] = None, - migrate_from_chat_id: Optional[int] = None, - pinned_message: Optional[MaybeInaccessibleMessage] = None, - invoice: Optional[Invoice] = None, - successful_payment: Optional[SuccessfulPayment] = None, - author_signature: Optional[str] = None, - media_group_id: Optional[str] = None, - connected_website: Optional[str] = None, - animation: Optional[Animation] = None, - passport_data: Optional[PassportData] = None, - poll: Optional[Poll] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, - dice: Optional[Dice] = None, - via_bot: Optional[User] = None, - proximity_alert_triggered: Optional[ProximityAlertTriggered] = None, - sender_chat: Optional[Chat] = None, - video_chat_started: Optional[VideoChatStarted] = None, - video_chat_ended: Optional[VideoChatEnded] = None, - video_chat_participants_invited: Optional[VideoChatParticipantsInvited] = None, - message_auto_delete_timer_changed: Optional[MessageAutoDeleteTimerChanged] = None, - video_chat_scheduled: Optional[VideoChatScheduled] = None, - is_automatic_forward: Optional[bool] = None, - has_protected_content: Optional[bool] = None, - web_app_data: Optional[WebAppData] = None, - is_topic_message: Optional[bool] = None, - message_thread_id: Optional[int] = None, - forum_topic_created: Optional[ForumTopicCreated] = None, - forum_topic_closed: Optional[ForumTopicClosed] = None, - forum_topic_reopened: Optional[ForumTopicReopened] = None, - forum_topic_edited: Optional[ForumTopicEdited] = None, - general_forum_topic_hidden: Optional[GeneralForumTopicHidden] = None, - general_forum_topic_unhidden: Optional[GeneralForumTopicUnhidden] = None, - write_access_allowed: Optional[WriteAccessAllowed] = None, - has_media_spoiler: Optional[bool] = None, - chat_shared: Optional[ChatShared] = None, - story: Optional[Story] = None, - giveaway: Optional["Giveaway"] = None, - giveaway_completed: Optional["GiveawayCompleted"] = None, - giveaway_created: Optional["GiveawayCreated"] = None, - giveaway_winners: Optional["GiveawayWinners"] = None, - users_shared: Optional[UsersShared] = None, - link_preview_options: Optional[LinkPreviewOptions] = None, - external_reply: Optional["ExternalReplyInfo"] = None, - quote: Optional["TextQuote"] = None, - forward_origin: Optional["MessageOrigin"] = None, - reply_to_story: Optional[Story] = None, - boost_added: Optional[ChatBoostAdded] = None, - sender_boost_count: Optional[int] = None, - business_connection_id: Optional[str] = None, - sender_business_bot: Optional[User] = None, - is_from_offline: Optional[bool] = None, - chat_background_set: Optional[ChatBackground] = None, - effect_id: Optional[str] = None, - show_caption_above_media: Optional[bool] = None, - paid_media: Optional[PaidMediaInfo] = None, - refunded_payment: Optional[RefundedPayment] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(chat=chat, message_id=message_id, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - # Required - self.message_id: int = message_id - # Optionals - self.from_user: Optional[User] = from_user - self.sender_chat: Optional[Chat] = sender_chat - self.date: dtm.datetime = date - self.chat: Chat = chat - self.is_automatic_forward: Optional[bool] = is_automatic_forward - self.reply_to_message: Optional[Message] = reply_to_message - self.edit_date: Optional[dtm.datetime] = edit_date - self.has_protected_content: Optional[bool] = has_protected_content - self.text: Optional[str] = text - self.entities: tuple[MessageEntity, ...] = parse_sequence_arg(entities) - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.audio: Optional[Audio] = audio - self.game: Optional[Game] = game - self.document: Optional[Document] = document - self.photo: tuple[PhotoSize, ...] = parse_sequence_arg(photo) - self.sticker: Optional[Sticker] = sticker - self.video: Optional[Video] = video - self.voice: Optional[Voice] = voice - self.video_note: Optional[VideoNote] = video_note - self.caption: Optional[str] = caption - self.contact: Optional[Contact] = contact - self.location: Optional[Location] = location - self.venue: Optional[Venue] = venue - self.new_chat_members: tuple[User, ...] = parse_sequence_arg(new_chat_members) - self.left_chat_member: Optional[User] = left_chat_member - self.new_chat_title: Optional[str] = new_chat_title - self.new_chat_photo: tuple[PhotoSize, ...] = parse_sequence_arg(new_chat_photo) - self.delete_chat_photo: Optional[bool] = bool(delete_chat_photo) - self.group_chat_created: Optional[bool] = bool(group_chat_created) - self.supergroup_chat_created: Optional[bool] = bool(supergroup_chat_created) - self.migrate_to_chat_id: Optional[int] = migrate_to_chat_id - self.migrate_from_chat_id: Optional[int] = migrate_from_chat_id - self.channel_chat_created: Optional[bool] = bool(channel_chat_created) - self.message_auto_delete_timer_changed: Optional[MessageAutoDeleteTimerChanged] = ( - message_auto_delete_timer_changed - ) - self.pinned_message: Optional[MaybeInaccessibleMessage] = pinned_message - self.invoice: Optional[Invoice] = invoice - self.successful_payment: Optional[SuccessfulPayment] = successful_payment - self.connected_website: Optional[str] = connected_website - self.author_signature: Optional[str] = author_signature - self.media_group_id: Optional[str] = media_group_id - self.animation: Optional[Animation] = animation - self.passport_data: Optional[PassportData] = passport_data - self.poll: Optional[Poll] = poll - self.dice: Optional[Dice] = dice - self.via_bot: Optional[User] = via_bot - self.proximity_alert_triggered: Optional[ProximityAlertTriggered] = ( - proximity_alert_triggered - ) - self.video_chat_scheduled: Optional[VideoChatScheduled] = video_chat_scheduled - self.video_chat_started: Optional[VideoChatStarted] = video_chat_started - self.video_chat_ended: Optional[VideoChatEnded] = video_chat_ended - self.video_chat_participants_invited: Optional[VideoChatParticipantsInvited] = ( - video_chat_participants_invited - ) - self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup - self.web_app_data: Optional[WebAppData] = web_app_data - self.is_topic_message: Optional[bool] = is_topic_message - self.message_thread_id: Optional[int] = message_thread_id - self.forum_topic_created: Optional[ForumTopicCreated] = forum_topic_created - self.forum_topic_closed: Optional[ForumTopicClosed] = forum_topic_closed - self.forum_topic_reopened: Optional[ForumTopicReopened] = forum_topic_reopened - self.forum_topic_edited: Optional[ForumTopicEdited] = forum_topic_edited - self.general_forum_topic_hidden: Optional[GeneralForumTopicHidden] = ( - general_forum_topic_hidden - ) - self.general_forum_topic_unhidden: Optional[GeneralForumTopicUnhidden] = ( - general_forum_topic_unhidden - ) - self.write_access_allowed: Optional[WriteAccessAllowed] = write_access_allowed - self.has_media_spoiler: Optional[bool] = has_media_spoiler - self.users_shared: Optional[UsersShared] = users_shared - self.chat_shared: Optional[ChatShared] = chat_shared - self.story: Optional[Story] = story - self.giveaway: Optional[Giveaway] = giveaway - self.giveaway_completed: Optional[GiveawayCompleted] = giveaway_completed - self.giveaway_created: Optional[GiveawayCreated] = giveaway_created - self.giveaway_winners: Optional[GiveawayWinners] = giveaway_winners - self.link_preview_options: Optional[LinkPreviewOptions] = link_preview_options - self.external_reply: Optional[ExternalReplyInfo] = external_reply - self.quote: Optional[TextQuote] = quote - self.forward_origin: Optional[MessageOrigin] = forward_origin - self.reply_to_story: Optional[Story] = reply_to_story - self.boost_added: Optional[ChatBoostAdded] = boost_added - self.sender_boost_count: Optional[int] = sender_boost_count - self.business_connection_id: Optional[str] = business_connection_id - self.sender_business_bot: Optional[User] = sender_business_bot - self.is_from_offline: Optional[bool] = is_from_offline - self.chat_background_set: Optional[ChatBackground] = chat_background_set - self.effect_id: Optional[str] = effect_id - self.show_caption_above_media: Optional[bool] = show_caption_above_media - self.paid_media: Optional[PaidMediaInfo] = paid_media - self.refunded_payment: Optional[RefundedPayment] = refunded_payment - - self._effective_attachment = DEFAULT_NONE - - self._id_attrs = (self.message_id, self.chat) - - @property - def chat_id(self) -> int: - """:obj:`int`: Shortcut for :attr:`telegram.Chat.id` for :attr:`chat`.""" - return self.chat.id - - @property - def id(self) -> int: - """ - :obj:`int`: Shortcut for :attr:`message_id`. - - .. versionadded:: 20.0 - """ - return self.message_id - - @property - def link(self) -> Optional[str]: - """:obj:`str`: Convenience property. If the chat of the message is not - a private chat or normal group, returns a t.me link of the message. - - .. versionchanged:: 20.3 - For messages that are replies or part of a forum topic, the link now points - to the corresponding thread view. - """ - if self.chat.type not in [Chat.PRIVATE, Chat.GROUP]: - # the else block gets rid of leading -100 for supergroups: - to_link = self.chat.username if self.chat.username else f"c/{str(self.chat.id)[4:]}" - baselink = f"https://t.me/{to_link}/{self.message_id}" - - # adds the thread for topics and replies - if (self.is_topic_message and self.message_thread_id) or self.reply_to_message: - baselink = f"{baselink}?thread={self.message_thread_id}" - return baselink - return None - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Message"]: - """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["from_user"] = User.de_json(data.pop("from", None), bot) - data["sender_chat"] = Chat.de_json(data.get("sender_chat"), bot) - data["entities"] = MessageEntity.de_list(data.get("entities"), bot) - data["caption_entities"] = MessageEntity.de_list(data.get("caption_entities"), bot) - data["reply_to_message"] = Message.de_json(data.get("reply_to_message"), bot) - data["edit_date"] = from_timestamp(data.get("edit_date"), tzinfo=loc_tzinfo) - data["audio"] = Audio.de_json(data.get("audio"), bot) - data["document"] = Document.de_json(data.get("document"), bot) - data["animation"] = Animation.de_json(data.get("animation"), bot) - data["game"] = Game.de_json(data.get("game"), bot) - data["photo"] = 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["voice"] = Voice.de_json(data.get("voice"), bot) - data["video_note"] = VideoNote.de_json(data.get("video_note"), bot) - data["contact"] = Contact.de_json(data.get("contact"), bot) - data["location"] = Location.de_json(data.get("location"), bot) - data["venue"] = Venue.de_json(data.get("venue"), bot) - data["new_chat_members"] = User.de_list(data.get("new_chat_members"), bot) - data["left_chat_member"] = User.de_json(data.get("left_chat_member"), bot) - data["new_chat_photo"] = PhotoSize.de_list(data.get("new_chat_photo"), bot) - data["message_auto_delete_timer_changed"] = MessageAutoDeleteTimerChanged.de_json( - data.get("message_auto_delete_timer_changed"), bot - ) - data["pinned_message"] = MaybeInaccessibleMessage.de_json(data.get("pinned_message"), bot) - data["invoice"] = Invoice.de_json(data.get("invoice"), bot) - data["successful_payment"] = SuccessfulPayment.de_json(data.get("successful_payment"), bot) - data["passport_data"] = PassportData.de_json(data.get("passport_data"), bot) - data["poll"] = Poll.de_json(data.get("poll"), bot) - data["dice"] = Dice.de_json(data.get("dice"), bot) - data["via_bot"] = User.de_json(data.get("via_bot"), bot) - data["proximity_alert_triggered"] = ProximityAlertTriggered.de_json( - data.get("proximity_alert_triggered"), bot - ) - data["reply_markup"] = InlineKeyboardMarkup.de_json(data.get("reply_markup"), bot) - data["video_chat_scheduled"] = VideoChatScheduled.de_json( - data.get("video_chat_scheduled"), bot - ) - data["video_chat_started"] = VideoChatStarted.de_json(data.get("video_chat_started"), bot) - data["video_chat_ended"] = VideoChatEnded.de_json(data.get("video_chat_ended"), bot) - data["video_chat_participants_invited"] = VideoChatParticipantsInvited.de_json( - data.get("video_chat_participants_invited"), bot - ) - data["web_app_data"] = WebAppData.de_json(data.get("web_app_data"), bot) - data["forum_topic_closed"] = ForumTopicClosed.de_json(data.get("forum_topic_closed"), bot) - data["forum_topic_created"] = ForumTopicCreated.de_json( - data.get("forum_topic_created"), bot - ) - data["forum_topic_reopened"] = ForumTopicReopened.de_json( - data.get("forum_topic_reopened"), bot - ) - data["forum_topic_edited"] = ForumTopicEdited.de_json(data.get("forum_topic_edited"), bot) - data["general_forum_topic_hidden"] = GeneralForumTopicHidden.de_json( - data.get("general_forum_topic_hidden"), bot - ) - data["general_forum_topic_unhidden"] = GeneralForumTopicUnhidden.de_json( - data.get("general_forum_topic_unhidden"), bot - ) - data["write_access_allowed"] = WriteAccessAllowed.de_json( - data.get("write_access_allowed"), bot - ) - data["users_shared"] = UsersShared.de_json(data.get("users_shared"), bot) - data["chat_shared"] = ChatShared.de_json(data.get("chat_shared"), bot) - data["chat_background_set"] = ChatBackground.de_json(data.get("chat_background_set"), bot) - data["paid_media"] = PaidMediaInfo.de_json(data.get("paid_media"), bot) - data["refunded_payment"] = RefundedPayment.de_json(data.get("refunded_payment"), bot) - - # Unfortunately, this needs to be here due to cyclic imports - from telegram._giveaway import ( # pylint: disable=import-outside-toplevel - Giveaway, - GiveawayCompleted, - GiveawayCreated, - GiveawayWinners, - ) - from telegram._messageorigin import ( # pylint: disable=import-outside-toplevel - MessageOrigin, - ) - from telegram._reply import ( # pylint: disable=import-outside-toplevel - ExternalReplyInfo, - TextQuote, - ) - - data["giveaway"] = Giveaway.de_json(data.get("giveaway"), bot) - data["giveaway_completed"] = GiveawayCompleted.de_json(data.get("giveaway_completed"), bot) - data["giveaway_created"] = GiveawayCreated.de_json(data.get("giveaway_created"), bot) - data["giveaway_winners"] = GiveawayWinners.de_json(data.get("giveaway_winners"), bot) - data["link_preview_options"] = LinkPreviewOptions.de_json( - data.get("link_preview_options"), bot - ) - data["external_reply"] = ExternalReplyInfo.de_json(data.get("external_reply"), bot) - data["quote"] = TextQuote.de_json(data.get("quote"), bot) - data["forward_origin"] = MessageOrigin.de_json(data.get("forward_origin"), bot) - data["reply_to_story"] = Story.de_json(data.get("reply_to_story"), bot) - data["boost_added"] = ChatBoostAdded.de_json(data.get("boost_added"), bot) - data["sender_business_bot"] = User.de_json(data.get("sender_business_bot"), 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 - for key in ( - "user_shared", - "forward_from", - "forward_from_chat", - "forward_from_message_id", - "forward_signature", - "forward_sender_name", - "forward_date", - ): - if entry := data.get(key): - api_kwargs = {key: entry} - - return super()._de_json( # type: ignore[return-value] - data=data, bot=bot, api_kwargs=api_kwargs - ) - - @property - def effective_attachment( - self, - ) -> Union[ - Animation, - Audio, - Contact, - Dice, - Document, - Game, - Invoice, - Location, - PassportData, - Sequence[PhotoSize], - PaidMediaInfo, - Poll, - Sticker, - Story, - SuccessfulPayment, - Venue, - Video, - VideoNote, - Voice, - None, - ]: - """If the message is a user generated content which is not a plain text message, this - property is set to this content. It may be one of - - * :class:`telegram.Audio` - * :class:`telegram.Dice` - * :class:`telegram.Contact` - * :class:`telegram.Document` - * :class:`telegram.Animation` - * :class:`telegram.Game` - * :class:`telegram.Invoice` - * :class:`telegram.Location` - * :class:`telegram.PassportData` - * list[:class:`telegram.PhotoSize`] - * :class:`telegram.PaidMediaInfo` - * :class:`telegram.Poll` - * :class:`telegram.Sticker` - * :class:`telegram.Story` - * :class:`telegram.SuccessfulPayment` - * :class:`telegram.Venue` - * :class:`telegram.Video` - * :class:`telegram.VideoNote` - * :class:`telegram.Voice` - - Otherwise :obj:`None` is returned. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.0 - :attr:`dice`, :attr:`passport_data` and :attr:`poll` are now also considered to be an - attachment. - - .. versionchanged:: 21.4 - :attr:`paid_media` is now also considered to be an attachment. - - .. deprecated:: 21.4 - :attr:`successful_payment` will be removed in future major versions. - - """ - if not isinstance(self._effective_attachment, DefaultValue): - return self._effective_attachment - - for attachment_type in MessageAttachmentType: - if self[attachment_type]: - self._effective_attachment = self[attachment_type] # type: ignore[assignment] - if attachment_type == MessageAttachmentType.SUCCESSFUL_PAYMENT: - warn( - PTBDeprecationWarning( - "21.4", - "successful_payment will no longer be considered an attachment in" - " future major versions", - ), - stacklevel=2, - ) - break - else: - self._effective_attachment = None - - return self._effective_attachment # type: ignore[return-value] - - def _quote( - self, quote: Optional[bool], reply_to_message_id: Optional[int] = None - ) -> Optional[ReplyParameters]: - """Modify kwargs for replying with or without quoting.""" - if reply_to_message_id is not None: - return ReplyParameters(reply_to_message_id) - - if quote is not None: - if quote: - return ReplyParameters(self.message_id) - - else: - # Unfortunately we need some ExtBot logic here because it's hard to move shortcut - # logic into ExtBot - if hasattr(self.get_bot(), "defaults") and self.get_bot().defaults: # type: ignore - default_quote = self.get_bot().defaults.quote # type: ignore[attr-defined] - else: - default_quote = None - if (default_quote is None and self.chat.type != Chat.PRIVATE) or default_quote: - return ReplyParameters(self.message_id) - - return None - - def compute_quote_position_and_entities( - self, quote: str, index: Optional[int] = None - ) -> tuple[int, Optional[tuple[MessageEntity, ...]]]: - """ - Use this function to compute position and entities of a quote in the message text or - caption. Useful for filling the parameters - :paramref:`~telegram.ReplyParameters.quote_position` and - :paramref:`~telegram.ReplyParameters.quote_entities` of :class:`telegram.ReplyParameters` - when replying to a message. - - Example: - - Given a message with the text ``"Hello, world! Hello, world!"``, the following code - will return the position and entities of the second occurrence of ``"Hello, world!"``. - - .. code-block:: python - - message.compute_quote_position_and_entities("Hello, world!", 1) - - .. versionadded:: 20.8 - - Args: - quote (:obj:`str`): Part of the message which is to be quoted. This is - expected to have plain text without formatting entities. - index (:obj:`int`, optional): 0-based index of the occurrence of the quote in the - message. If not specified, the first occurrence is used. - - Returns: - tuple[:obj:`int`, :obj:`None` | tuple[:class:`~telegram.MessageEntity`, ...]]: On - success, a tuple containing information about quote position and entities is returned. - - Raises: - RuntimeError: If the message has neither :attr:`text` nor :attr:`caption`. - ValueError: If the requested index of quote doesn't exist in the message. - """ - if not (text := (self.text or self.caption)): - raise RuntimeError("This message has neither text nor caption.") - - # Telegram wants the position in UTF-16 code units, so we have to calculate in that space - utf16_text = text.encode(TextEncoding.UTF_16_LE) - utf16_quote = quote.encode(TextEncoding.UTF_16_LE) - effective_index = index or 0 - - matches = list(re.finditer(re.escape(utf16_quote), utf16_text)) - if (length := len(matches)) < effective_index + 1: - raise ValueError( - f"You requested the {index}-th occurrence of '{quote}', but this text appears " - f"only {length} times." - ) - - position = len(utf16_text[: matches[effective_index].start()]) // 2 - length = len(utf16_quote) // 2 - end_position = position + length - - entities = [] - for entity in self.entities or self.caption_entities: - if position <= entity.offset + entity.length and entity.offset <= end_position: - # shift the offset by the position of the quote - offset = max(0, entity.offset - position) - # trim the entity length to the length of the overlap with the quote - e_length = min(end_position, entity.offset + entity.length) - max( - position, entity.offset - ) - if e_length <= 0: - continue - - # create a new entity with the correct offset and length - # looping over slots rather manually accessing the attributes - # is more future-proof - kwargs = {attr: getattr(entity, attr) for attr in entity.__slots__} - kwargs["offset"] = offset - kwargs["length"] = e_length - entities.append(MessageEntity(**kwargs)) - - return position, tuple(entities) or None - - def build_reply_arguments( - self, - quote: Optional[str] = None, - quote_index: Optional[int] = None, - target_chat_id: Optional[Union[int, str]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: ODVInput[int] = DEFAULT_NONE, - ) -> _ReplyKwargs: - """ - Builds a dictionary with the keys ``chat_id`` and ``reply_parameters``. This dictionary can - be used to reply to a message with the given quote and target chat. - - Examples: - - Usage with :meth:`telegram.Bot.send_message`: - - .. code-block:: python - - await bot.send_message( - text="This is a reply", - **message.build_reply_arguments(quote="Quoted Text") - ) - - Usage with :meth:`reply_text`, replying in the same chat: - - .. code-block:: python - - await message.reply_text( - "This is a reply", - do_quote=message.build_reply_arguments(quote="Quoted Text") - ) - - Usage with :meth:`reply_text`, replying in a different chat: - - .. code-block:: python - - await message.reply_text( - "This is a reply", - do_quote=message.build_reply_arguments( - quote="Quoted Text", - target_chat_id=-100123456789 - ) - ) - - .. versionadded:: 20.8 - - Args: - quote (:obj:`str`, optional): Passed in :meth:`compute_quote_position_and_entities` - as parameter :paramref:`~compute_quote_position_and_entities.quote` to compute - quote entities. Defaults to :obj:`None`. - quote_index (:obj:`int`, optional): Passed in - :meth:`compute_quote_position_and_entities` as parameter - :paramref:`~compute_quote_position_and_entities.quote_index` to compute quote - position. Defaults to :obj:`None`. - target_chat_id (:obj:`int` | :obj:`str`, optional): |chat_id_channel| - Defaults to :attr:`chat_id`. - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Will be applied only if the reply happens in the same chat and forum topic. - message_thread_id (:obj:`int`, optional): |message_thread_id| - - Returns: - :obj:`dict`: - """ - target_chat_is_self = target_chat_id in (None, self.chat_id, f"@{self.chat.username}") - - if target_chat_is_self and message_thread_id in ( - None, - self.message_thread_id, - ): - # defaults handling will take place in `Bot._insert_defaults` - effective_aswr: ODVInput[bool] = allow_sending_without_reply - else: - effective_aswr = None - - quote_position, quote_entities = ( - self.compute_quote_position_and_entities(quote, quote_index) if quote else (None, None) - ) - return { # type: ignore[typeddict-item] - "reply_parameters": ReplyParameters( - chat_id=None if target_chat_is_self else self.chat_id, - message_id=self.message_id, - quote=quote, - quote_position=quote_position, - quote_entities=quote_entities, - allow_sending_without_reply=effective_aswr, - ), - "chat_id": target_chat_id or self.chat_id, - } - - async def _parse_quote_arguments( - self, - do_quote: Optional[Union[bool, _ReplyKwargs]], - quote: Optional[bool], - reply_to_message_id: Optional[int], - reply_parameters: Optional["ReplyParameters"], - ) -> tuple[Union[str, int], ReplyParameters]: - if quote and do_quote: - raise ValueError("The arguments `quote` and `do_quote` are mutually exclusive") - - if reply_to_message_id is not None and reply_parameters is not None: - raise ValueError( - "`reply_to_message_id` and `reply_parameters` are mutually exclusive." - ) - - if quote is not None: - warn( - PTBDeprecationWarning( - "20.8", - "The `quote` parameter is deprecated in favor of the `do_quote` parameter. " - "Please update your code to use `do_quote` instead.", - ), - stacklevel=2, - ) - - effective_do_quote = quote or do_quote - chat_id: Union[str, int] = self.chat_id - - # reply_parameters and reply_to_message_id overrule the do_quote parameter - if reply_parameters is not None: - effective_reply_parameters = reply_parameters - elif reply_to_message_id is not None: - effective_reply_parameters = ReplyParameters(message_id=reply_to_message_id) - elif isinstance(effective_do_quote, dict): - effective_reply_parameters = effective_do_quote["reply_parameters"] - chat_id = effective_do_quote["chat_id"] - else: - effective_reply_parameters = self._quote(effective_do_quote) - - return chat_id, effective_reply_parameters - - def _parse_message_thread_id( - self, - chat_id: Union[str, int], - message_thread_id: ODVInput[int] = DEFAULT_NONE, - ) -> Optional[int]: - # values set by user have the highest priority - if not isinstance(message_thread_id, DefaultValue): - return message_thread_id - - # self.message_thread_id can be used for send_*.param.message_thread_id only if the - # thread is a forum topic. It does not work if the thread is a chain of replies to a - # message in a normal group. In that case, self.message_thread_id is just the message_id - # of the first message in the chain. - if not self.is_topic_message: - return None - - # Setting message_thread_id=self.message_thread_id only makes sense if we're replying in - # the same chat. - return self.message_thread_id if chat_id in {self.chat_id, self.chat.username} else None - - async def reply_text( - 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: ODVInput[int] = DEFAULT_NONE, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_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, - disable_web_page_preview: Optional[bool] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_message( - chat_id=chat_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_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_markdown( - self, - text: str, - 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: ODVInput[int] = DEFAULT_NONE, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_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, - disable_web_page_preview: Optional[bool] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - parse_mode=ParseMode.MARKDOWN, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - Sends a message with Markdown version 1 formatting. - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`reply_markdown_v2` instead. - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_message( - chat_id=chat_id, - text=text, - parse_mode=ParseMode.MARKDOWN, - disable_web_page_preview=disable_web_page_preview, - link_preview_options=link_preview_options, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_markdown_v2( - self, - text: str, - 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: ODVInput[int] = DEFAULT_NONE, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_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, - disable_web_page_preview: Optional[bool] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - parse_mode=ParseMode.MARKDOWN_V2, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - Sends a message with markdown version 2 formatting. - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_message( - chat_id=chat_id, - text=text, - parse_mode=ParseMode.MARKDOWN_V2, - disable_web_page_preview=disable_web_page_preview, - link_preview_options=link_preview_options, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_html( - self, - text: str, - 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: ODVInput[int] = DEFAULT_NONE, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_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, - disable_web_page_preview: Optional[bool] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - parse_mode=ParseMode.HTML, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - Sends a message with HTML formatting. - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_message( - chat_id=chat_id, - text=text, - parse_mode=ParseMode.HTML, - disable_web_page_preview=disable_web_page_preview, - link_preview_options=link_preview_options, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - tuple[:class:`telegram.Message`]: An array of the sent Messages. - - Raises: - :class:`telegram.error.TelegramError` - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_media_group( - chat_id=chat_id, - media=media, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_NONE, - has_spoiler: Optional[bool] = None, - reply_parameters: Optional["ReplyParameters"] = 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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_photo( - chat_id=chat_id, - photo=photo, - caption=caption, - disable_notification=disable_notification, - reply_parameters=effective_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=self.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 reply_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: ODVInput[int] = DEFAULT_NONE, - thumbnail: Optional[FileInput] = 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, - filename: Optional[str] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_audio( - chat_id=chat_id, - audio=audio, - duration=duration, - performer=performer, - title=title, - caption=caption, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_NONE, - thumbnail: Optional[FileInput] = 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, - filename: Optional[str] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_document( - chat_id=chat_id, - document=document, - filename=filename, - caption=caption, - disable_notification=disable_notification, - reply_parameters=effective_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, - 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, - thumbnail=thumbnail, - business_connection_id=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_NONE, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = 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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().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_parameters=effective_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=self.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 reply_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: ODVInput[int] = DEFAULT_NONE, - emoji: Optional[str] = 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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_sticker( - chat_id=chat_id, - sticker=sticker, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_NONE, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - reply_parameters: Optional["ReplyParameters"] = 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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_video( - chat_id=chat_id, - video=video, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_parameters=effective_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, - 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=self.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 reply_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: ODVInput[int] = DEFAULT_NONE, - thumbnail: Optional[FileInput] = 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, - filename: Optional[str] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_video_note( - chat_id=chat_id, - video_note=video_note, - duration=duration, - length=length, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_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, - filename: Optional[str] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_voice( - chat_id=chat_id, - voice=voice, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_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, - location: Optional[Location] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_location( - chat_id=chat_id, - latitude=latitude, - longitude=longitude, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_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, - venue: Optional[Venue] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_venue( - chat_id=chat_id, - latitude=latitude, - longitude=longitude, - title=title, - address=address, - foursquare_id=foursquare_id, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_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, - contact: Optional[Contact] = None, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_contact( - chat_id=chat_id, - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_poll( - self, - 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: ODVInput[int] = DEFAULT_NONE, - reply_parameters: Optional["ReplyParameters"] = 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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().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_parameters=effective_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=self.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 reply_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: ODVInput[int] = DEFAULT_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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_dice( - chat_id=chat_id, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_chat_action( - self, - action: str, - message_thread_id: ODVInput[int] = 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, - ) -> bool: - """Shortcut for:: - - await bot.send_chat_action( - update.effective_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - .. versionadded:: 13.2 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().send_chat_action( - chat_id=self.chat_id, - message_thread_id=self._parse_message_thread_id(self.chat_id, message_thread_id), - action=action, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - business_connection_id=self.business_connection_id, - ) - - async def reply_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: ODVInput[int] = DEFAULT_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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - business_connection_id=self.business_connection_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - .. versionadded:: 13.2 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().send_game( - chat_id=chat_id, # type: ignore[arg-type] - game_short_name=game_short_name, - disable_notification=disable_notification, - reply_parameters=effective_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=self.business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def reply_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: ODVInput[int] = DEFAULT_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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_message.chat_id, - message_thread_id=update.effective_message.message_thread_id, - *args, - **kwargs, - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - 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. - - .. versionadded:: 13.2 - - .. versionchanged:: 13.5 - As of Bot API 5.2, the parameter - :paramref:`start_parameter ` is optional. - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().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_parameters=effective_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 forward( - self, - chat_id: Union[int, str], - 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_message.chat_id, - message_id=update.effective_message.message_id, - *args, - **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`. - - Note: - Since the release of Bot API 5.5 it can be impossible to forward messages from - some chats. Use the attributes :attr:`telegram.Message.has_protected_content` and - :attr:`telegram.ChatFullInfo.has_protected_content` to check this. - - As a workaround, it is still possible to use :meth:`copy`. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, instance representing the message forwarded. - - """ - return await self.get_bot().forward_message( - chat_id=chat_id, - from_chat_id=self.chat_id, - message_id=self.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=api_kwargs, - ) - - async def copy( - self, - chat_id: Union[int, str], - 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=chat_id, - from_chat_id=update.effective_message.chat_id, - message_id=update.effective_message.message_id, - *args, - **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Returns: - :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. - - """ - return await self.get_bot().copy_message( - chat_id=chat_id, - from_chat_id=self.chat_id, - message_id=self.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 reply_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: ODVInput[int] = DEFAULT_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, - quote: Optional[bool] = None, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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=message.chat.id, - message_thread_id=update.effective_message.message_thread_id, - message_id=message_id, - *args, - **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - .. versionchanged:: 21.1 - |reply_same_thread| - - Keyword Args: - quote (:obj:`bool`, optional): |reply_quote| - - .. versionadded:: 13.1 - .. deprecated:: 20.8 - This argument is deprecated in favor of :paramref:`do_quote` - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - .. versionadded:: 20.8 - - Returns: - :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, quote, reply_to_message_id, reply_parameters - ) - message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id) - return await self.get_bot().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_parameters=effective_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 reply_paid_media( - self, - 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, - payload: Optional[str] = None, - allow_paid_broadcast: Optional[bool] = None, - *, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - do_quote: Optional[Union[bool, _ReplyKwargs]] = 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_paid_media( - chat_id=message.chat.id, - business_connection_id=message.business_connection_id, - *args, - **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_paid_media`. - - .. versionadded:: 21.7 - - Keyword Args: - do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| - Mutually exclusive with :paramref:`quote`. - - Returns: - :class:`telegram.Message`: On success, the sent message is returned. - - """ - chat_id, effective_reply_parameters = await self._parse_quote_arguments( - do_quote, None, reply_to_message_id, reply_parameters - ) - return await self.get_bot().send_paid_media( - chat_id=chat_id, - caption=caption, - star_count=star_count, - media=media, - payload=payload, - business_connection_id=self.business_connection_id, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_parameters=effective_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, - show_caption_above_media=show_caption_above_media, - allow_paid_broadcast=allow_paid_broadcast, - ) - - async def edit_text( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - entities: Optional[Sequence["MessageEntity"]] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_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, - ) -> Union["Message", bool]: - """Shortcut for:: - - await bot.edit_message_text( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.edit_message_text`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - .. versionchanged:: 21.4 - Now also passes :attr:`business_connection_id`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise ``True`` is returned. - - """ - return await self.get_bot().edit_message_text( - chat_id=self.chat_id, - message_id=self.message_id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - link_preview_options=link_preview_options, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - entities=entities, - inline_message_id=None, - business_connection_id=self.business_connection_id, - ) - - async def edit_caption( - self, - 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, - *, - 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, - ) -> Union["Message", bool]: - """Shortcut for:: - - await bot.edit_message_caption( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_caption`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - .. versionchanged:: 21.4 - Now also passes :attr:`business_connection_id`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise ``True`` is returned. - - """ - return await self.get_bot().edit_message_caption( - chat_id=self.chat_id, - message_id=self.message_id, - caption=caption, - 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, - caption_entities=caption_entities, - inline_message_id=None, - show_caption_above_media=show_caption_above_media, - business_connection_id=self.business_connection_id, - ) - - async def edit_media( - self, - media: "InputMedia", - reply_markup: Optional["InlineKeyboardMarkup"] = 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, - ) -> Union["Message", bool]: - """Shortcut for:: - - await bot.edit_message_media( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_media`. - - Note: - You can only edit messages that the bot sent itself(i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - .. versionchanged:: 21.4 - Now also passes :attr:`business_connection_id`. - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited Message is returned, otherwise ``True`` is returned. - - """ - return await self.get_bot().edit_message_media( - media=media, - chat_id=self.chat_id, - message_id=self.message_id, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - business_connection_id=self.business_connection_id, - ) - - async def edit_reply_markup( - self, - reply_markup: Optional["InlineKeyboardMarkup"] = 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, - ) -> Union["Message", bool]: - """Shortcut for:: - - await bot.edit_message_reply_markup( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_reply_markup`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - .. versionchanged:: 21.4 - Now also passes :attr:`business_connection_id`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise ``True`` is returned. - """ - return await self.get_bot().edit_message_reply_markup( - chat_id=self.chat_id, - message_id=self.message_id, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - business_connection_id=self.business_connection_id, - ) - - async def edit_live_location( - self, - 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, - *, - 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, - ) -> Union["Message", bool]: - """Shortcut for:: - - await bot.edit_message_live_location( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_live_location`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - .. versionchanged:: 21.4 - Now also passes :attr:`business_connection_id`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - """ - return await self.get_bot().edit_message_live_location( - chat_id=self.chat_id, - message_id=self.message_id, - latitude=latitude, - longitude=longitude, - location=location, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - live_period=live_period, - inline_message_id=None, - business_connection_id=self.business_connection_id, - ) - - async def stop_live_location( - self, - reply_markup: Optional["InlineKeyboardMarkup"] = 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, - ) -> Union["Message", bool]: - """Shortcut for:: - - await bot.stop_message_live_location( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.stop_message_live_location`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - .. versionchanged:: 21.4 - Now also passes :attr:`business_connection_id`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - """ - return await self.get_bot().stop_message_live_location( - chat_id=self.chat_id, - message_id=self.message_id, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - business_connection_id=self.business_connection_id, - ) - - async def set_game_score( - self, - user_id: int, - score: int, - 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, - ) -> Union["Message", bool]: - """Shortcut for:: - - await bot.set_game_score( - chat_id=message.chat_id, message_id=message.message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.set_game_score`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - """ - return await self.get_bot().set_game_score( - chat_id=self.chat_id, - message_id=self.message_id, - user_id=user_id, - score=score, - 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=api_kwargs, - inline_message_id=None, - ) - - async def get_game_high_scores( - 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, - ) -> tuple["GameHighScore", ...]: - """Shortcut for:: - - await bot.get_game_high_scores( - chat_id=message.chat_id, message_id=message.message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_game_high_scores`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - tuple[:class:`telegram.GameHighScore`] - """ - return await self.get_bot().get_game_high_scores( - chat_id=self.chat_id, - message_id=self.message_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - ) - - async def delete( - 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.delete_message( - chat_id=message.chat_id, message_id=message.message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.delete_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().delete_message( - chat_id=self.chat_id, - message_id=self.message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def stop_poll( - self, - reply_markup: Optional["InlineKeyboardMarkup"] = 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, - ) -> Poll: - """Shortcut for:: - - await bot.stop_poll( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.stop_poll`. - - .. versionchanged:: 21.4 - Now also passes :attr:`business_connection_id`. - - Returns: - :class:`telegram.Poll`: On success, the stopped Poll with the final results is - returned. - - """ - return await self.get_bot().stop_poll( - chat_id=self.chat_id, - message_id=self.message_id, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - business_connection_id=self.business_connection_id, - ) - - async def pin( - self, - disable_notification: 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, - ) -> bool: - """Shortcut for:: - - await bot.pin_chat_message( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. - - .. versionchanged:: 21.5 - Now also passes :attr:`business_connection_id` to - :meth:`telegram.Bot.pin_chat_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().pin_chat_message( - chat_id=self.chat_id, - message_id=self.message_id, - business_connection_id=self.business_connection_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, - ) - - async def unpin( - 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_chat_message( - chat_id=message.chat_id, - message_id=message.message_id, - business_connection_id=message.business_connection_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. - - .. versionchanged:: 21.5 - Now also passes :attr:`business_connection_id` to - :meth:`telegram.Bot.pin_chat_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().unpin_chat_message( - chat_id=self.chat_id, - message_id=self.message_id, - business_connection_id=self.business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def edit_forum_topic( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.edit_forum_topic( - chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args, - **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().edit_forum_topic( - chat_id=self.chat_id, - message_thread_id=self.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=api_kwargs, - ) - - async def close_forum_topic( - 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.close_forum_topic( - chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args, - **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.close_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().close_forum_topic( - chat_id=self.chat_id, - message_thread_id=self.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 reopen_forum_topic( - 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.reopen_forum_topic( - chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args, - **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.reopen_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().reopen_forum_topic( - chat_id=self.chat_id, - message_thread_id=self.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 delete_forum_topic( - 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.delete_forum_topic( - chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args, - **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.delete_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().delete_forum_topic( - chat_id=self.chat_id, - message_thread_id=self.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 unpin_all_forum_topic_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_forum_topic_messages( - chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args, - **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_all_forum_topic_messages`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().unpin_all_forum_topic_messages( - chat_id=self.chat_id, - message_thread_id=self.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 set_reaction( - self, - reaction: Optional[ - Union[Sequence["ReactionType"], "ReactionType", Sequence[str], 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, - ) -> bool: - """Shortcut for:: - - await bot.set_message_reaction(chat_id=message.chat_id, message_id=message.message_id, - *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_message_reaction`. - - .. versionadded:: 20.8 - - Returns: - :obj:`bool` On success, :obj:`True` is returned. - """ - return await self.get_bot().set_message_reaction( - chat_id=self.chat_id, - message_id=self.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=api_kwargs, - ) - - def parse_entity(self, entity: MessageEntity) -> str: - """Returns the text from a given :class:`telegram.MessageEntity`. - - 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 this message. - - Returns: - :obj:`str`: The text of the given entity. - - Raises: - RuntimeError: If the message has no text. - - """ - if not self.text: - raise RuntimeError("This Message has no 'text'.") - - return parse_message_entity(self.text, entity) - - def parse_caption_entity(self, entity: MessageEntity) -> str: - """Returns the text from a given :class:`telegram.MessageEntity`. - - 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.caption`` 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 this message. - - Returns: - :obj:`str`: The text of the given entity. - - Raises: - RuntimeError: If the message has no caption. - - """ - if not self.caption: - raise RuntimeError("This Message has no 'caption'.") - - return parse_message_entity(self.caption, 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 message filtered by their - :attr:`telegram.MessageEntity.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:`entities` attribute, since it - calculates the correct substring from the message text based on UTF-16 codepoints. - See :attr:`parse_entity` for more info. - - Args: - types (list[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as - strings. If the ``type`` attribute of an entity is contained in this list, it will - be returned. Defaults to a list of all types. All types can be found as constants - in :class:`telegram.MessageEntity`. - - 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.entities, types=types) - - def parse_caption_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 message's caption filtered by their - :attr:`telegram.MessageEntity.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:`caption_entities` attribute, - since it calculates the correct substring from the message text based on UTF-16 - codepoints. See :attr:`parse_entity` for more info. - - Args: - types (list[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as - strings. If the ``type`` attribute of an entity is contained in this list, it will - be returned. Defaults to a list of all types. All types can be found as constants - in :class:`telegram.MessageEntity`. - - 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.caption, self.caption_entities, types=types) - - @classmethod - def _parse_html( - cls, - message_text: Optional[str], - entities: dict[MessageEntity, str], - urled: bool = False, - offset: int = 0, - ) -> Optional[str]: - if message_text is None: - return None - - utf_16_text = message_text.encode(TextEncoding.UTF_16_LE) - html_text = "" - last_offset = 0 - - sorted_entities = sorted(entities.items(), key=lambda item: item[0].offset) - parsed_entities = [] - - for entity, text in sorted_entities: - if entity in parsed_entities: - continue - - nested_entities = { - e: t - for (e, t) in sorted_entities - if e.offset >= entity.offset - and e.offset + e.length <= entity.offset + entity.length - and e != entity - } - parsed_entities.extend(list(nested_entities.keys())) - - if nested_entities: - escaped_text = cls._parse_html( - text, nested_entities, urled=urled, offset=entity.offset - ) - else: - escaped_text = escape(text) - - if entity.type == MessageEntity.TEXT_LINK: - insert = f'{escaped_text}' - elif entity.type == MessageEntity.TEXT_MENTION and entity.user: - insert = f'{escaped_text}' - elif entity.type == MessageEntity.URL and urled: - insert = f'{escaped_text}' - elif entity.type == MessageEntity.BLOCKQUOTE: - insert = f"

{escaped_text}
" - elif entity.type == MessageEntity.EXPANDABLE_BLOCKQUOTE: - insert = f"
{escaped_text}
" - elif entity.type == MessageEntity.BOLD: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.ITALIC: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.CODE: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.PRE: - if entity.language: - insert = f'
{escaped_text}
' - else: - insert = f"
{escaped_text}
" - elif entity.type == MessageEntity.UNDERLINE: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.STRIKETHROUGH: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.SPOILER: - insert = f'{escaped_text}' - elif entity.type == MessageEntity.CUSTOM_EMOJI: - insert = f'{escaped_text}' - else: - insert = escaped_text - - # Make sure to escape the text that is not part of the entity - # if we're in a nested entity, this is still required, since in that case this - # text is part of the parent entity - html_text += ( - escape( - utf_16_text[last_offset * 2 : (entity.offset - offset) * 2].decode( - TextEncoding.UTF_16_LE - ) - ) - + insert - ) - - last_offset = entity.offset - offset + entity.length - - # see comment above - html_text += escape(utf_16_text[last_offset * 2 :].decode(TextEncoding.UTF_16_LE)) - - return html_text - - @property - def text_html(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message. - - Use this if you want to retrieve the message text with the entities formatted as HTML in - the same way the original message was formatted. - - Warning: - |text_html| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as HTML. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message text with entities formatted as HTML. - - """ - return self._parse_html(self.text, self.parse_entities(), urled=False) - - @property - def text_html_urled(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message. - - Use this if you want to retrieve the message text with the entities formatted as HTML. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_html| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as HTML. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message text with entities formatted as HTML. - - """ - return self._parse_html(self.text, self.parse_entities(), urled=True) - - @property - def caption_html(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message's - caption. - - Use this if you want to retrieve the message caption with the caption entities formatted as - HTML in the same way the original message was formatted. - - Warning: - |text_html| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as HTML. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message caption with caption entities formatted as HTML. - """ - return self._parse_html(self.caption, self.parse_caption_entities(), urled=False) - - @property - def caption_html_urled(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message's - caption. - - Use this if you want to retrieve the message caption with the caption entities formatted as - HTML. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_html| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as HTML. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message caption with caption entities formatted as HTML. - """ - return self._parse_html(self.caption, self.parse_caption_entities(), urled=True) - - @classmethod - def _parse_markdown( - cls, - message_text: Optional[str], - entities: dict[MessageEntity, str], - urled: bool = False, - version: MarkdownVersion = 1, - offset: int = 0, - ) -> Optional[str]: - if version == 1: - for entity_type in ( - MessageEntity.EXPANDABLE_BLOCKQUOTE, - MessageEntity.BLOCKQUOTE, - MessageEntity.CUSTOM_EMOJI, - MessageEntity.SPOILER, - MessageEntity.STRIKETHROUGH, - MessageEntity.UNDERLINE, - ): - if any(entity.type == entity_type for entity in entities): - name = entity_type.name.title().replace("_", " ") # type:ignore[attr-defined] - raise ValueError(f"{name} entities are not supported for Markdown version 1") - - if message_text is None: - return None - - utf_16_text = message_text.encode(TextEncoding.UTF_16_LE) - markdown_text = "" - last_offset = 0 - - sorted_entities = sorted(entities.items(), key=lambda item: item[0].offset) - parsed_entities = [] - - for entity, text in sorted_entities: - if entity in parsed_entities: - continue - - nested_entities = { - e: t - for (e, t) in sorted_entities - if e.offset >= entity.offset - and e.offset + e.length <= entity.offset + entity.length - and e != entity - } - parsed_entities.extend(list(nested_entities.keys())) - - if nested_entities: - if version < 2: - raise ValueError("Nested entities are not supported for Markdown version 1") - - escaped_text = cls._parse_markdown( - text, - nested_entities, - urled=urled, - offset=entity.offset, - version=version, - ) - else: - escaped_text = escape_markdown(text, version=version) - - if entity.type == MessageEntity.TEXT_LINK: - if version == 1: - url = entity.url - else: - # Links need special escaping. Also can't have entities nested within - url = escape_markdown( - entity.url, version=version, entity_type=MessageEntity.TEXT_LINK - ) - insert = f"[{escaped_text}]({url})" - elif entity.type == MessageEntity.TEXT_MENTION and entity.user: - insert = f"[{escaped_text}](tg://user?id={entity.user.id})" - elif entity.type == MessageEntity.URL and urled: - link = text if version == 1 else escaped_text - insert = f"[{link}]({text})" - elif entity.type == MessageEntity.BOLD: - insert = f"*{escaped_text}*" - elif entity.type == MessageEntity.ITALIC: - insert = f"_{escaped_text}_" - elif entity.type == MessageEntity.CODE: - # Monospace needs special escaping. Also can't have entities nested within - insert = f"`{escape_markdown(text, version, MessageEntity.CODE)}`" - elif entity.type == MessageEntity.PRE: - # Monospace needs special escaping. Also can't have entities nested within - code = escape_markdown(text, version=version, entity_type=MessageEntity.PRE) - if entity.language: - prefix = f"```{entity.language}\n" - elif code.startswith("\\"): - prefix = "```" - else: - prefix = "```\n" - insert = f"{prefix}{code}```" - elif entity.type == MessageEntity.UNDERLINE: - insert = f"__{escaped_text}__" - elif entity.type == MessageEntity.STRIKETHROUGH: - insert = f"~{escaped_text}~" - elif entity.type == MessageEntity.SPOILER: - insert = f"||{escaped_text}||" - elif entity.type in (MessageEntity.BLOCKQUOTE, MessageEntity.EXPANDABLE_BLOCKQUOTE): - insert = ">" + "\n>".join(escaped_text.splitlines()) - if entity.type == MessageEntity.EXPANDABLE_BLOCKQUOTE: - insert = f"{insert}||" - elif entity.type == MessageEntity.CUSTOM_EMOJI: - # This should never be needed because ids are numeric but the documentation - # specifically mentions it so here we are - custom_emoji_id = escape_markdown( - entity.custom_emoji_id, - version=version, - entity_type=MessageEntity.CUSTOM_EMOJI, - ) - insert = f"![{escaped_text}](tg://emoji?id={custom_emoji_id})" - else: - insert = escaped_text - - # Make sure to escape the text that is not part of the entity - # if we're in a nested entity, this is still required, since in that case this - # text is part of the parent entity - markdown_text += ( - escape_markdown( - utf_16_text[last_offset * 2 : (entity.offset - offset) * 2].decode( - TextEncoding.UTF_16_LE - ), - version=version, - ) - + insert - ) - - last_offset = entity.offset - offset + entity.length - - # see comment above - markdown_text += escape_markdown( - utf_16_text[last_offset * 2 :].decode(TextEncoding.UTF_16_LE), - version=version, - ) - - return markdown_text - - @property - def text_markdown(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.constants.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown - in the same way the original message was formatted. - - Warning: - |text_markdown| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`text_markdown_v2` instead. - - .. versionchanged:: 20.5 - |custom_emoji_no_md1_support| - - .. versionchanged:: 20.8 - |blockquote_no_md1_support| - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - - Raises: - :exc:`ValueError`: If the message contains underline, strikethrough, spoiler, - blockquote or nested entities. - - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=False) - - @property - def text_markdown_v2(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.constants.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown - in the same way the original message was formatted. - - Warning: - |text_markdown| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as Markdown V2. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=False, version=2) - - @property - def text_markdown_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.constants.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_markdown| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`text_markdown_v2_urled` - instead. - - .. versionchanged:: 20.5 - |custom_emoji_no_md1_support| - - .. versionchanged:: 20.8 - |blockquote_no_md1_support| - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - - Raises: - :exc:`ValueError`: If the message contains underline, strikethrough, spoiler, - blockquote or nested entities. - - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=True) - - @property - def text_markdown_v2_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.constants.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_markdown| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as Markdown V2. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=True, version=2) - - @property - def caption_markdown(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.constants.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown in the same way the original message was formatted. - - Warning: - |text_markdown| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`caption_markdown_v2` - .. versionchanged:: 20.5 - |custom_emoji_no_md1_support| - - .. versionchanged:: 20.8 - |blockquote_no_md1_support| - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - - Raises: - :exc:`ValueError`: If the message contains underline, strikethrough, spoiler, - blockquote or nested entities. - - """ - return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=False) - - @property - def caption_markdown_v2(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.constants.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown in the same way the original message was formatted. - - Warning: - |text_markdown| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as Markdown V2. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - """ - return self._parse_markdown( - self.caption, self.parse_caption_entities(), urled=False, version=2 - ) - - @property - def caption_markdown_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.constants.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_markdown| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use - :meth:`caption_markdown_v2_urled` instead. - - .. versionchanged:: 20.5 - |custom_emoji_no_md1_support| - - .. versionchanged:: 20.8 - |blockquote_no_md1_support| - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - - Raises: - :exc:`ValueError`: If the message contains underline, strikethrough, spoiler, - blockquote or nested entities. - - """ - return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=True) - - @property - def caption_markdown_v2_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.constants.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_markdown| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as Markdown V2. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - """ - return self._parse_markdown( - self.caption, self.parse_caption_entities(), urled=True, version=2 - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_messageautodeletetimerchanged.py b/venv/lib/python3.11/site-packages/telegram/_messageautodeletetimerchanged.py deleted file mode 100755 index 1653c05..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messageautodeletetimerchanged.py +++ /dev/null @@ -1,60 +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 change in the Telegram message auto -deletion. -""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class MessageAutoDeleteTimerChanged(TelegramObject): - """This object represents a service message about a change in auto-delete timer settings. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_auto_delete_time` is equal. - - .. versionadded:: 13.4 - - Args: - message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the - chat. - - Attributes: - message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the - chat. - - """ - - __slots__ = ("message_auto_delete_time",) - - def __init__( - self, - message_auto_delete_time: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.message_auto_delete_time: int = message_auto_delete_time - - self._id_attrs = (self.message_auto_delete_time,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_messageentity.py b/venv/lib/python3.11/site-packages/telegram/_messageentity.py deleted file mode 100755 index 852c496..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messageentity.py +++ /dev/null @@ -1,414 +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 MessageEntity.""" - -import copy -import itertools -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional, Union - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils import enum -from telegram._utils.strings import TextEncoding -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - -_SEM = Sequence["MessageEntity"] - - -class MessageEntity(TelegramObject): - """ - This object represents one special entity in a text message. For example, hashtags, - usernames, URLs, etc. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type`, :attr:`offset` and :attr:`length` are equal. - - Args: - type (:obj:`str`): Type of the entity. Can be :attr:`MENTION` (``@username``), - :attr:`HASHTAG` (``#hashtag`` or ``#hashtag@chatusername``), :attr:`CASHTAG` (``$USD`` - or ``USD@chatusername``), :attr:`BOT_COMMAND` (``/start@jobs_bot``), :attr:`URL` - (``https://telegram.org``), :attr:`EMAIL` (``do-not-reply@telegram.org``), - :attr:`PHONE_NUMBER` (``+1-212-555-0123``), - :attr:`BOLD` (**bold text**), :attr:`ITALIC` (*italic text*), :attr:`UNDERLINE` - (underlined text), :attr:`STRIKETHROUGH`, :attr:`SPOILER` (spoiler message), - :attr:`BLOCKQUOTE` (block quotation), :attr:`CODE` (monowidth string), :attr:`PRE` - (monowidth block), :attr:`TEXT_LINK` (for clickable text URLs), :attr:`TEXT_MENTION` - (for users without usernames), :attr:`CUSTOM_EMOJI` (for inline custom emoji stickers). - - .. versionadded:: 20.0 - Added inline custom emoji - - .. versionadded:: 20.8 - Added block quotation - offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity. - length (:obj:`int`): Length of the entity in UTF-16 code units. - url (:obj:`str`, optional): For :attr:`TEXT_LINK` only, url that will be opened after - user taps on the text. - user (:class:`telegram.User`, optional): For :attr:`TEXT_MENTION` only, the mentioned - user. - language (:obj:`str`, optional): For :attr:`PRE` only, the programming language of - the entity text. - custom_emoji_id (:obj:`str`, optional): For :attr:`CUSTOM_EMOJI` only, unique identifier - of the custom emoji. Use :meth:`telegram.Bot.get_custom_emoji_stickers` to get full - information about the sticker. - - .. versionadded:: 20.0 - Attributes: - type (:obj:`str`): Type of the entity. Can be :attr:`MENTION` (``@username``), - :attr:`HASHTAG` (``#hashtag`` or ``#hashtag@chatusername``), :attr:`CASHTAG` (``$USD`` - or ``USD@chatusername``), :attr:`BOT_COMMAND` (``/start@jobs_bot``), :attr:`URL` - (``https://telegram.org``), :attr:`EMAIL` (``do-not-reply@telegram.org``), - :attr:`PHONE_NUMBER` (``+1-212-555-0123``), - :attr:`BOLD` (**bold text**), :attr:`ITALIC` (*italic text*), :attr:`UNDERLINE` - (underlined text), :attr:`STRIKETHROUGH`, :attr:`SPOILER` (spoiler message), - :attr:`BLOCKQUOTE` (block quotation), :attr:`CODE` (monowidth string), :attr:`PRE` - (monowidth block), :attr:`TEXT_LINK` (for clickable text URLs), :attr:`TEXT_MENTION` - (for users without usernames), :attr:`CUSTOM_EMOJI` (for inline custom emoji stickers). - - .. versionadded:: 20.0 - Added inline custom emoji - - .. versionadded:: 20.8 - Added block quotation - offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity. - length (:obj:`int`): Length of the entity in UTF-16 code units. - url (:obj:`str`): Optional. For :attr:`TEXT_LINK` only, url that will be opened after - user taps on the text. - user (:class:`telegram.User`): Optional. For :attr:`TEXT_MENTION` only, the mentioned - user. - language (:obj:`str`): Optional. For :attr:`PRE` only, the programming language of - the entity text. - custom_emoji_id (:obj:`str`): Optional. For :attr:`CUSTOM_EMOJI` only, unique identifier - of the custom emoji. Use :meth:`telegram.Bot.get_custom_emoji_stickers` to get full - information about the sticker. - - .. versionadded:: 20.0 - - """ - - __slots__ = ("custom_emoji_id", "language", "length", "offset", "type", "url", "user") - - def __init__( - self, - type: str, # pylint: disable=redefined-builtin - offset: int, - length: int, - url: Optional[str] = None, - user: Optional[User] = None, - language: Optional[str] = None, - custom_emoji_id: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.type: str = enum.get_member(constants.MessageEntityType, type, type) - self.offset: int = offset - self.length: int = length - # Optionals - self.url: Optional[str] = url - self.user: Optional[User] = user - self.language: Optional[str] = language - self.custom_emoji_id: Optional[str] = custom_emoji_id - - self._id_attrs = (self.type, self.offset, self.length) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MessageEntity"]: - """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) - - return super().de_json(data=data, bot=bot) - - @staticmethod - def adjust_message_entities_to_utf_16(text: str, entities: _SEM) -> _SEM: - """Utility functionality for converting the offset and length of entities from - Unicode (:obj:`str`) to UTF-16 (``utf-16-le`` encoded :obj:`bytes`). - - Tip: - Only the offsets and lengths calulated in UTF-16 is acceptable by the Telegram Bot API. - If they are calculated using the Unicode string (:obj:`str` object), errors may occur - when the text contains characters that are not in the Basic Multilingual Plane (BMP). - For more information, see `Unicode `_ and - `Plane (Unicode) `_. - - .. versionadded:: 21.4 - - Examples: - Below is a snippet of code that demonstrates how to use this function to convert - entities from Unicode to UTF-16 space. The ``unicode_entities`` are calculated in - Unicode and the `utf_16_entities` are calculated in UTF-16. - - .. code-block:: python - - text = "𠌕 bold 𝄢 italic underlined: 𝛙𝌢𑁍" - unicode_entities = [ - MessageEntity(offset=2, length=4, type=MessageEntity.BOLD), - MessageEntity(offset=9, length=6, type=MessageEntity.ITALIC), - MessageEntity(offset=28, length=3, type=MessageEntity.UNDERLINE), - ] - utf_16_entities = MessageEntity.adjust_message_entities_to_utf_16( - text, unicode_entities - ) - await bot.send_message( - chat_id=123, - text=text, - entities=utf_16_entities, - ) - # utf_16_entities[0]: offset=3, length=4 - # utf_16_entities[1]: offset=11, length=6 - # utf_16_entities[2]: offset=30, length=6 - - Args: - text (:obj:`str`): The text that the entities belong to - entities (Sequence[:class:`telegram.MessageEntity`]): Sequence of entities - with offset and length calculated in Unicode - - Returns: - Sequence[:class:`telegram.MessageEntity`]: Sequence of entities - with offset and length calculated in UTF-16 encoding - """ - # get sorted positions - positions = sorted(itertools.chain(*((x.offset, x.offset + x.length) for x in entities))) - accumulated_length = 0 - # calculate the length of each slice text[:position] in utf-16 accordingly, - # store the position translations - position_translation: dict[int, int] = {} - for i, position in enumerate(positions): - last_position = positions[i - 1] if i > 0 else 0 - text_slice = text[last_position:position] - accumulated_length += len(text_slice.encode(TextEncoding.UTF_16_LE)) // 2 - position_translation[position] = accumulated_length - # get the final output entities - out = [] - for entity in entities: - translated_positions = position_translation[entity.offset] - translated_length = ( - position_translation[entity.offset + entity.length] - translated_positions - ) - new_entity = copy.copy(entity) - with new_entity._unfrozen(): - new_entity.offset = translated_positions - new_entity.length = translated_length - out.append(new_entity) - return out - - @staticmethod - def shift_entities(by: Union[str, int], entities: _SEM) -> _SEM: - """Utility functionality for shifting the offset of entities by a given amount. - - Examples: - Shifting by an integer amount: - - .. code-block:: python - - text = "Hello, world!" - entities = [ - MessageEntity(offset=0, length=5, type=MessageEntity.BOLD), - MessageEntity(offset=7, length=5, type=MessageEntity.ITALIC), - ] - shifted_entities = MessageEntity.shift_entities(1, entities) - await bot.send_message( - chat_id=123, - text="!" + text, - entities=shifted_entities, - ) - - Shifting using a string: - - .. code-block:: python - - text = "Hello, world!" - prefix = "𝄢" - entities = [ - MessageEntity(offset=0, length=5, type=MessageEntity.BOLD), - MessageEntity(offset=7, length=5, type=MessageEntity.ITALIC), - ] - shifted_entities = MessageEntity.shift_entities(prefix, entities) - await bot.send_message( - chat_id=123, - text=prefix + text, - entities=shifted_entities, - ) - - Tip: - The :paramref:`entities` are *not* modified in place. The function returns a sequence - of new objects. - - .. versionadded:: 21.5 - - Args: - by (:obj:`str` | :obj:`int`): Either the amount to shift the offset by or - a string whose length will be used as the amount to shift the offset by. In this - case, UTF-16 encoding will be used to calculate the length. - entities (Sequence[:class:`telegram.MessageEntity`]): Sequence of entities - - Returns: - Sequence[:class:`telegram.MessageEntity`]: Sequence of entities with the offset shifted - """ - effective_shift = by if isinstance(by, int) else len(by.encode("utf-16-le")) // 2 - - out = [] - for entity in entities: - new_entity = copy.copy(entity) - with new_entity._unfrozen(): - new_entity.offset += effective_shift - out.append(new_entity) - return out - - @classmethod - def concatenate( - cls, - *args: Union[tuple[str, _SEM], tuple[str, _SEM, bool]], - ) -> tuple[str, _SEM]: - """Utility functionality for concatenating two text along with their formatting entities. - - Tip: - This function is useful for prefixing an already formatted text with a new text and its - formatting entities. In particular, it automatically correctly handles UTF-16 encoding. - - Examples: - This example shows a callback function that can be used to add a prefix and suffix to - the message in a :class:`~telegram.ext.CallbackQueryHandler`: - - .. code-block:: python - - async def prefix_message(update: Update, context: ContextTypes.DEFAULT_TYPE): - prefix = "𠌕 bold 𝄢 italic underlined: 𝛙𝌢𑁍 | " - prefix_entities = [ - MessageEntity(offset=2, length=4, type=MessageEntity.BOLD), - MessageEntity(offset=9, length=6, type=MessageEntity.ITALIC), - MessageEntity(offset=28, length=3, type=MessageEntity.UNDERLINE), - ] - suffix = " | 𠌕 bold 𝄢 italic underlined: 𝛙𝌢𑁍" - suffix_entities = [ - MessageEntity(offset=5, length=4, type=MessageEntity.BOLD), - MessageEntity(offset=12, length=6, type=MessageEntity.ITALIC), - MessageEntity(offset=31, length=3, type=MessageEntity.UNDERLINE), - ] - - message = update.effective_message - first = (prefix, prefix_entities, True) - second = (message.text, message.entities) - third = (suffix, suffix_entities, True) - - new_text, new_entities = MessageEntity.concatenate(first, second, third) - await update.callback_query.edit_message_text( - text=new_text, - entities=new_entities, - ) - - Hint: - The entities are *not* modified in place. The function returns a - new sequence of objects. - - .. versionadded:: 21.5 - - Args: - *args (tuple[:obj:`str`, Sequence[:class:`telegram.MessageEntity`]] | \ - tuple[:obj:`str`, Sequence[:class:`telegram.MessageEntity`], :obj:`bool`]): - Arbitrary number of tuples containing the text and its entities to concatenate. - If the last element of the tuple is a :obj:`bool`, it is used to determine whether - to adjust the entities to UTF-16 via - :meth:`adjust_message_entities_to_utf_16`. UTF-16 adjustment is disabled by - default. - - Returns: - tuple[:obj:`str`, Sequence[:class:`telegram.MessageEntity`]]: The concatenated text - and its entities - """ - output_text = "" - output_entities: list[MessageEntity] = [] - for arg in args: - text, entities = arg[0], arg[1] - - if len(arg) > 2 and arg[2] is True: - entities = cls.adjust_message_entities_to_utf_16(text, entities) - - output_entities.extend(cls.shift_entities(output_text, entities)) - output_text += text - - return output_text, output_entities - - ALL_TYPES: Final[list[str]] = list(constants.MessageEntityType) - """list[:obj:`str`]: A list of all available message entity types.""" - BLOCKQUOTE: Final[str] = constants.MessageEntityType.BLOCKQUOTE - """:const:`telegram.constants.MessageEntityType.BLOCKQUOTE` - - .. versionadded:: 20.8 - """ - BOLD: Final[str] = constants.MessageEntityType.BOLD - """:const:`telegram.constants.MessageEntityType.BOLD`""" - BOT_COMMAND: Final[str] = constants.MessageEntityType.BOT_COMMAND - """:const:`telegram.constants.MessageEntityType.BOT_COMMAND`""" - CASHTAG: Final[str] = constants.MessageEntityType.CASHTAG - """:const:`telegram.constants.MessageEntityType.CASHTAG`""" - CODE: Final[str] = constants.MessageEntityType.CODE - """:const:`telegram.constants.MessageEntityType.CODE`""" - CUSTOM_EMOJI: Final[str] = constants.MessageEntityType.CUSTOM_EMOJI - """:const:`telegram.constants.MessageEntityType.CUSTOM_EMOJI` - - .. versionadded:: 20.0 - """ - EMAIL: Final[str] = constants.MessageEntityType.EMAIL - """:const:`telegram.constants.MessageEntityType.EMAIL`""" - EXPANDABLE_BLOCKQUOTE: Final[str] = constants.MessageEntityType.EXPANDABLE_BLOCKQUOTE - """:const:`telegram.constants.MessageEntityType.EXPANDABLE_BLOCKQUOTE` - - .. versionadded:: 21.3 - """ - HASHTAG: Final[str] = constants.MessageEntityType.HASHTAG - """:const:`telegram.constants.MessageEntityType.HASHTAG`""" - ITALIC: Final[str] = constants.MessageEntityType.ITALIC - """:const:`telegram.constants.MessageEntityType.ITALIC`""" - MENTION: Final[str] = constants.MessageEntityType.MENTION - """:const:`telegram.constants.MessageEntityType.MENTION`""" - PHONE_NUMBER: Final[str] = constants.MessageEntityType.PHONE_NUMBER - """:const:`telegram.constants.MessageEntityType.PHONE_NUMBER`""" - PRE: Final[str] = constants.MessageEntityType.PRE - """:const:`telegram.constants.MessageEntityType.PRE`""" - SPOILER: Final[str] = constants.MessageEntityType.SPOILER - """:const:`telegram.constants.MessageEntityType.SPOILER` - - .. versionadded:: 13.10 - """ - STRIKETHROUGH: Final[str] = constants.MessageEntityType.STRIKETHROUGH - """:const:`telegram.constants.MessageEntityType.STRIKETHROUGH`""" - TEXT_LINK: Final[str] = constants.MessageEntityType.TEXT_LINK - """:const:`telegram.constants.MessageEntityType.TEXT_LINK`""" - TEXT_MENTION: Final[str] = constants.MessageEntityType.TEXT_MENTION - """:const:`telegram.constants.MessageEntityType.TEXT_MENTION`""" - UNDERLINE: Final[str] = constants.MessageEntityType.UNDERLINE - """:const:`telegram.constants.MessageEntityType.UNDERLINE`""" - URL: Final[str] = constants.MessageEntityType.URL - """:const:`telegram.constants.MessageEntityType.URL`""" diff --git a/venv/lib/python3.11/site-packages/telegram/_messageid.py b/venv/lib/python3.11/site-packages/telegram/_messageid.py deleted file mode 100755 index ac550fc..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messageid.py +++ /dev/null @@ -1,54 +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 an instance of a Telegram MessageId.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class MessageId(TelegramObject): - """This object represents a unique message identifier. - - 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. - - Args: - message_id (:obj:`int`): Unique message identifier. In specific instances - (e.g., message containing a video sent to a big chat), the server might automatically - schedule a message instead of sending it immediately. In such cases, this field will be - ``0`` and the relevant message will be unusable until it is actually sent. - - Attributes: - message_id (:obj:`int`): Unique message identifier. In specific instances - (e.g., message containing a video sent to a big chat), the server might automatically - schedule a message instead of sending it immediately. In such cases, this field will be - ``0`` and the relevant message will be unusable until it is actually sent. - """ - - __slots__ = ("message_id",) - - def __init__(self, message_id: int, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.message_id: int = message_id - - self._id_attrs = (self.message_id,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_messageorigin.py b/venv/lib/python3.11/site-packages/telegram/_messageorigin.py deleted file mode 100755 index 0982d65..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messageorigin.py +++ /dev/null @@ -1,286 +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 that represent Telegram MessageOigin.""" -import datetime as dtm -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._chat import Chat -from telegram._telegramobject import TelegramObject -from telegram._user import User -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 MessageOrigin(TelegramObject): - """ - Base class for telegram MessageOrigin object, it can be one of: - - * :class:`MessageOriginUser` - * :class:`MessageOriginHiddenUser` - * :class:`MessageOriginChat` - * :class:`MessageOriginChannel` - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` and :attr:`date` are equal. - - .. versionadded:: 20.8 - - Args: - type (:obj:`str`): Type of the message origin, can be on of: - :attr:`~telegram.MessageOrigin.USER`, :attr:`~telegram.MessageOrigin.HIDDEN_USER`, - :attr:`~telegram.MessageOrigin.CHAT`, or :attr:`~telegram.MessageOrigin.CHANNEL`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - - Attributes: - type (:obj:`str`): Type of the message origin, can be on of: - :attr:`~telegram.MessageOrigin.USER`, :attr:`~telegram.MessageOrigin.HIDDEN_USER`, - :attr:`~telegram.MessageOrigin.CHAT`, or :attr:`~telegram.MessageOrigin.CHANNEL`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - """ - - __slots__ = ( - "date", - "type", - ) - - USER: Final[str] = constants.MessageOriginType.USER - """:const:`telegram.constants.MessageOriginType.USER`""" - HIDDEN_USER: Final[str] = constants.MessageOriginType.HIDDEN_USER - """:const:`telegram.constants.MessageOriginType.HIDDEN_USER`""" - CHAT: Final[str] = constants.MessageOriginType.CHAT - """:const:`telegram.constants.MessageOriginType.CHAT`""" - CHANNEL: Final[str] = constants.MessageOriginType.CHANNEL - """:const:`telegram.constants.MessageOriginType.CHANNEL`""" - - def __init__( - self, - type: str, # pylint: disable=W0622 - date: dtm.datetime, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required by all subclasses - self.type: str = enum.get_member(constants.MessageOriginType, type, type) - self.date: dtm.datetime = date - - self._id_attrs = ( - self.type, - self.date, - ) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MessageOrigin"]: - """Converts JSON data to the appropriate :class:`MessageOrigin` object, i.e. takes - care of selecting the correct subclass. - """ - data = cls._parse_data(data) - - if not data: - return None - - _class_mapping: dict[str, type[MessageOrigin]] = { - cls.USER: MessageOriginUser, - cls.HIDDEN_USER: MessageOriginHiddenUser, - cls.CHAT: MessageOriginChat, - cls.CHANNEL: MessageOriginChannel, - } - if cls is MessageOrigin and data.get("type") in _class_mapping: - return _class_mapping[data.pop("type")].de_json(data=data, bot=bot) - - loc_tzinfo = extract_tzinfo_from_defaults(bot) - data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo) - - if "sender_user" in data: - data["sender_user"] = User.de_json(data.get("sender_user"), bot) - - if "sender_chat" in data: - data["sender_chat"] = Chat.de_json(data.get("sender_chat"), bot) - - if "chat" in data: - data["chat"] = Chat.de_json(data.get("chat"), bot) - - return super().de_json(data=data, bot=bot) - - -class MessageOriginUser(MessageOrigin): - """ - The message was originally sent by a known user. - - .. versionadded:: 20.8 - - Args: - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_user (:class:`telegram.User`): User that sent the message originally. - - Attributes: - type (:obj:`str`): Type of the message origin. Always - :tg-const:`~telegram.MessageOrigin.USER`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_user (:class:`telegram.User`): User that sent the message originally. - """ - - __slots__ = ("sender_user",) - - def __init__( - self, - date: dtm.datetime, - sender_user: User, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.USER, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.sender_user: User = sender_user - - -class MessageOriginHiddenUser(MessageOrigin): - """ - The message was originally sent by an unknown user. - - .. versionadded:: 20.8 - - Args: - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_user_name (:obj:`str`): Name of the user that sent the message originally. - - Attributes: - type (:obj:`str`): Type of the message origin. Always - :tg-const:`~telegram.MessageOrigin.HIDDEN_USER`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_user_name (:obj:`str`): Name of the user that sent the message originally. - """ - - __slots__ = ("sender_user_name",) - - def __init__( - self, - date: dtm.datetime, - sender_user_name: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.HIDDEN_USER, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.sender_user_name: str = sender_user_name - - -class MessageOriginChat(MessageOrigin): - """ - The message was originally sent on behalf of a chat to a group chat. - - .. versionadded:: 20.8 - - Args: - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_chat (:class:`telegram.Chat`): Chat that sent the message originally. - author_signature (:obj:`str`, optional): For messages originally sent by an anonymous chat - administrator, original message author signature - - Attributes: - type (:obj:`str`): Type of the message origin. Always - :tg-const:`~telegram.MessageOrigin.CHAT`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_chat (:class:`telegram.Chat`): Chat that sent the message originally. - author_signature (:obj:`str`): Optional. For messages originally sent by an anonymous chat - administrator, original message author signature - """ - - __slots__ = ( - "author_signature", - "sender_chat", - ) - - def __init__( - self, - date: dtm.datetime, - sender_chat: Chat, - author_signature: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.CHAT, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.sender_chat: Chat = sender_chat - self.author_signature: Optional[str] = author_signature - - -class MessageOriginChannel(MessageOrigin): - """ - The message was originally sent to a channel chat. - - .. versionadded:: 20.8 - - Args: - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - chat (:class:`telegram.Chat`): Channel chat to which the message was originally sent. - message_id (:obj:`int`): Unique message identifier inside the chat. - author_signature (:obj:`str`, optional): Signature of the original post author. - - Attributes: - type (:obj:`str`): Type of the message origin. Always - :tg-const:`~telegram.MessageOrigin.CHANNEL`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - chat (:class:`telegram.Chat`): Channel chat to which the message was originally sent. - message_id (:obj:`int`): Unique message identifier inside the chat. - author_signature (:obj:`str`): Optional. Signature of the original post author. - """ - - __slots__ = ( - "author_signature", - "chat", - "message_id", - ) - - def __init__( - self, - date: dtm.datetime, - chat: Chat, - message_id: int, - author_signature: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.CHANNEL, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.chat: Chat = chat - self.message_id: int = message_id - self.author_signature: Optional[str] = author_signature diff --git a/venv/lib/python3.11/site-packages/telegram/_messagereactionupdated.py b/venv/lib/python3.11/site-packages/telegram/_messagereactionupdated.py deleted file mode 100755 index 105362a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messagereactionupdated.py +++ /dev/null @@ -1,209 +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 MessageReaction Update.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._chat import Chat -from telegram._reaction import ReactionCount, ReactionType -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 MessageReactionCountUpdated(TelegramObject): - """This class represents reaction changes on a message with anonymous reactions. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if the :attr:`chat`, :attr:`message_id`, :attr:`date` and :attr:`reactions` - is equal. - - .. versionadded:: 20.8 - - Args: - chat (:class:`telegram.Chat`): The chat containing the message. - message_id (:obj:`int`): Unique message identifier inside the chat. - date (:class:`datetime.datetime`): Date of the change in Unix time - |datetime_localization| - reactions (Sequence[:class:`telegram.ReactionCount`]): List of reactions that are present - on the message - - Attributes: - chat (:class:`telegram.Chat`): The chat containing the message. - message_id (:obj:`int`): Unique message identifier inside the chat. - date (:class:`datetime.datetime`): Date of the change in Unix time - |datetime_localization| - reactions (tuple[:class:`telegram.ReactionCount`]): List of reactions that are present on - the message - """ - - __slots__ = ( - "chat", - "date", - "message_id", - "reactions", - ) - - def __init__( - self, - chat: Chat, - message_id: int, - date: dtm.datetime, - reactions: Sequence[ReactionCount], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.chat: Chat = chat - self.message_id: int = message_id - self.date: dtm.datetime = date - self.reactions: tuple[ReactionCount, ...] = parse_sequence_arg(reactions) - - self._id_attrs = (self.chat, self.message_id, self.date, self.reactions) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MessageReactionCountUpdated"]: - """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"), tzinfo=loc_tzinfo) - data["chat"] = Chat.de_json(data.get("chat"), bot) - data["reactions"] = ReactionCount.de_list(data.get("reactions"), bot) - - return super().de_json(data=data, bot=bot) - - -class MessageReactionUpdated(TelegramObject): - """This class represents a change of a reaction on a message performed by a user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if the :attr:`chat`, :attr:`message_id`, :attr:`date`, :attr:`old_reaction` - and :attr:`new_reaction` is equal. - - .. versionadded:: 20.8 - - Args: - chat (:class:`telegram.Chat`): The chat containing the message. - message_id (:obj:`int`): Unique message identifier inside the chat. - date (:class:`datetime.datetime`): Date of the change in Unix time. - |datetime_localization| - old_reaction (Sequence[:class:`telegram.ReactionType`]): Previous list of reaction types - that were set by the user. - new_reaction (Sequence[:class:`telegram.ReactionType`]): New list of reaction types that - were set by the user. - user (:class:`telegram.User`, optional): The user that changed the reaction, if the user - isn't anonymous. - actor_chat (:class:`telegram.Chat`, optional): The chat on behalf of which the reaction was - changed, if the user is anonymous. - - Attributes: - chat (:class:`telegram.Chat`): The chat containing the message. - message_id (:obj:`int`): Unique message identifier inside the chat. - date (:class:`datetime.datetime`): Date of the change in Unix time. - |datetime_localization| - old_reaction (tuple[:class:`telegram.ReactionType`]): Previous list of reaction types - that were set by the user. - new_reaction (tuple[:class:`telegram.ReactionType`]): New list of reaction types that - were set by the user. - user (:class:`telegram.User`): Optional. The user that changed the reaction, if the user - isn't anonymous. - actor_chat (:class:`telegram.Chat`): Optional. The chat on behalf of which the reaction was - changed, if the user is anonymous. - """ - - __slots__ = ( - "actor_chat", - "chat", - "date", - "message_id", - "new_reaction", - "old_reaction", - "user", - ) - - def __init__( - self, - chat: Chat, - message_id: int, - date: dtm.datetime, - old_reaction: Sequence[ReactionType], - new_reaction: Sequence[ReactionType], - user: Optional[User] = None, - actor_chat: Optional[Chat] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.chat: Chat = chat - self.message_id: int = message_id - self.date: dtm.datetime = date - self.old_reaction: tuple[ReactionType, ...] = parse_sequence_arg(old_reaction) - self.new_reaction: tuple[ReactionType, ...] = parse_sequence_arg(new_reaction) - - # Optional - self.user: Optional[User] = user - self.actor_chat: Optional[Chat] = actor_chat - - self._id_attrs = ( - self.chat, - self.message_id, - self.date, - self.old_reaction, - self.new_reaction, - ) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MessageReactionUpdated"]: - """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"), tzinfo=loc_tzinfo) - data["chat"] = Chat.de_json(data.get("chat"), bot) - data["old_reaction"] = ReactionType.de_list(data.get("old_reaction"), bot) - data["new_reaction"] = ReactionType.de_list(data.get("new_reaction"), bot) - data["user"] = User.de_json(data.get("user"), bot) - data["actor_chat"] = Chat.de_json(data.get("actor_chat"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_paidmedia.py b/venv/lib/python3.11/site-packages/telegram/_paidmedia.py deleted file mode 100755 index b649c7e..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_paidmedia.py +++ /dev/null @@ -1,341 +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 represent paid media in Telegram.""" - -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._files.photosize import PhotoSize -from telegram._files.video import Video -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 - -if TYPE_CHECKING: - from telegram import Bot - - -class PaidMedia(TelegramObject): - """Describes the paid media added to a message. Currently, it can be one of: - - * :class:`telegram.PaidMediaPreview` - * :class:`telegram.PaidMediaPhoto` - * :class:`telegram.PaidMediaVideo` - - 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`): Type of the paid media. - - Attributes: - type (:obj:`str`): Type of the paid media. - """ - - __slots__ = ("type",) - - PREVIEW: Final[str] = constants.PaidMediaType.PREVIEW - """:const:`telegram.constants.PaidMediaType.PREVIEW`""" - PHOTO: Final[str] = constants.PaidMediaType.PHOTO - """:const:`telegram.constants.PaidMediaType.PHOTO`""" - VIDEO: Final[str] = constants.PaidMediaType.VIDEO - """:const:`telegram.constants.PaidMediaType.VIDEO`""" - - def __init__( - self, - type: str, # pylint: disable=redefined-builtin - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.type: str = enum.get_member(constants.PaidMediaType, type, type) - - self._id_attrs = (self.type,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMedia"]: - """Converts JSON data to the appropriate :class:`PaidMedia` object, i.e. takes - care of selecting the correct subclass. - - Args: - data (dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`, optional): The bot associated with this object. - - Returns: - The Telegram object. - - """ - data = cls._parse_data(data) - - if data is None: - return None - - if not data and cls is PaidMedia: - return None - - _class_mapping: dict[str, type[PaidMedia]] = { - cls.PREVIEW: PaidMediaPreview, - cls.PHOTO: PaidMediaPhoto, - cls.VIDEO: PaidMediaVideo, - } - - if cls is PaidMedia 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 PaidMediaPreview(PaidMedia): - """The paid media isn't available before the payment. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`width`, :attr:`height`, and :attr:`duration` - are equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PREVIEW`. - width (:obj:`int`, optional): Media width as defined by the sender. - height (:obj:`int`, optional): Media height as defined by the sender. - duration (:obj:`int`, optional): Duration of the media in seconds as defined by the sender. - - Attributes: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PREVIEW`. - width (:obj:`int`): Optional. Media width as defined by the sender. - height (:obj:`int`): Optional. Media height as defined by the sender. - duration (:obj:`int`): Optional. Duration of the media in seconds as defined by the sender. - """ - - __slots__ = ("duration", "height", "width") - - def __init__( - self, - width: Optional[int] = None, - height: Optional[int] = None, - duration: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=PaidMedia.PREVIEW, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.width: Optional[int] = width - self.height: Optional[int] = height - self.duration: Optional[int] = duration - - self._id_attrs = (self.type, self.width, self.height, self.duration) - - -class PaidMediaPhoto(PaidMedia): - """ - The paid media is a photo. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`photo` are equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PHOTO`. - photo (Sequence[:class:`telegram.PhotoSize`]): The photo. - - Attributes: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PHOTO`. - photo (tuple[:class:`telegram.PhotoSize`]): The photo. - """ - - __slots__ = ("photo",) - - def __init__( - self, - photo: Sequence["PhotoSize"], - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=PaidMedia.PHOTO, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.photo: tuple[PhotoSize, ...] = parse_sequence_arg(photo) - - self._id_attrs = (self.type, self.photo) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMediaPhoto"]: - data = cls._parse_data(data) - - if not data: - return None - - data["photo"] = PhotoSize.de_list(data.get("photo"), bot=bot) - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class PaidMediaVideo(PaidMedia): - """ - The paid media is a video. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`video` are equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.VIDEO`. - video (:class:`telegram.Video`): The video. - - Attributes: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.VIDEO`. - video (:class:`telegram.Video`): The video. - """ - - __slots__ = ("video",) - - def __init__( - self, - video: Video, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=PaidMedia.VIDEO, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.video: Video = video - - self._id_attrs = (self.type, self.video) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMediaVideo"]: - data = cls._parse_data(data) - - if not data: - return None - - data["video"] = Video.de_json(data.get("video"), bot=bot) - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class PaidMediaInfo(TelegramObject): - """ - Describes the paid media added to a message. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`star_count` and :attr:`paid_media` are equal. - - .. versionadded:: 21.4 - - Args: - star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access to - the media. - paid_media (Sequence[:class:`telegram.PaidMedia`]): Information about the paid media. - - Attributes: - star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access to - the media. - paid_media (tuple[:class:`telegram.PaidMedia`]): Information about the paid media. - """ - - __slots__ = ("paid_media", "star_count") - - def __init__( - self, - star_count: int, - paid_media: Sequence[PaidMedia], - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.star_count: int = star_count - self.paid_media: tuple[PaidMedia, ...] = parse_sequence_arg(paid_media) - - self._id_attrs = (self.star_count, self.paid_media) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMediaInfo"]: - data = cls._parse_data(data) - - if not data: - return None - - data["paid_media"] = PaidMedia.de_list(data.get("paid_media"), bot=bot) - return super().de_json(data=data, bot=bot) - - -class PaidMediaPurchased(TelegramObject): - """This object contains information about a paid media purchase. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`from_user` and :attr:`paid_media_payload` are equal. - - Note: - In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - - .. versionadded:: 21.6 - - Args: - from_user (:class:`telegram.User`): User who purchased the media. - paid_media_payload (:obj:`str`): Bot-specified paid media payload. - - Attributes: - from_user (:class:`telegram.User`): User who purchased the media. - paid_media_payload (:obj:`str`): Bot-specified paid media payload. - """ - - __slots__ = ("from_user", "paid_media_payload") - - def __init__( - self, - from_user: "User", - paid_media_payload: str, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.from_user: User = from_user - self.paid_media_payload: str = paid_media_payload - - self._id_attrs = (self.from_user, self.paid_media_payload) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMediaPurchased"]: - data = cls._parse_data(data) - - if not data: - return None - - data["from_user"] = User.de_json(data=data.pop("from"), bot=bot) - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__init__.py b/venv/lib/python3.11/site-packages/telegram/_passport/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 45e8674ca5c05a8168ecd68b72279a73ac2a0f5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmZ3^%ge<81UIM5$^y}kK?DpiLK&agfQ;!3DGb33nv8xc8H$*I{LdiCUt#(g`MIh3 zxrs%|`TAb@>G{U`i3J7vWvO{(`Z<|N`URCG8Tom}dWMGj#hE3kx&?{J*@@|?#rh?w zIjQMIiMjgm1&PJQ1^GoK`tk9Zd6^~g@p=W7zc_4i^HWN5QtgUZf!2T=Qp^t|J}@&f NGJary5k<^EF#r?{GCu$S diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/credentials.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/credentials.cpython-311.pyc deleted file mode 100755 index f75e047258ccd30af157b4a21209085dfde96c62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26810 zcmeHwX>43an%HaheK+q*Bp(kQEt5@&mnd4YO_91KN+VIW)IM6xeve|yeQ@7<)V0)D zFtod}qpanDCl<0ZSOUB2NHY#ba5k|L>>!@`WdsP)O}vDimoQKeIKTk;(Hhx+F-d@Y zU%k88q-cpwW`cd}uC97@d{tjnecxB#S5^Ece!qu;=Rbb*k1yUiM^XO`1M1^YJWr}B zDC%R1p%_bwisElY%95^#R#?z)O(cen`gB9I z0p5F~jhWU?if!tmxH<@1q8`TghMl6KzNkMMj8;ag8UGtL2-imIqV>@RCJ=2rM`di6 zsVmlV)MX3QESPFeZ;EarP(rDebZfMg_$yOwX*x<1e^shI-4X2|{_0d`x+~gcp;!m! zfc!P7&FL-CEf97wwKu6x0AW8@u}4L>!rQtPZ?{!Y2PvlhCdD+cn?A8Z4*1GXG)&?e zA+Bjf+;$Sz3~`%Q#Jxb`S|F}iXW3X{hE2Q;xq=Kk9iK}Hv8j0CZ8pP%DwiBcKPeKC6SaNoT z<-lhh-G3T?#`cYcZIbQuq0ya^1KhsBA@V!8vrn=eit{s*VfzF=VH>&!AWvYDO|cia zc>2WDMK&S8o2uD3$FnhBsdFsOU4XZ~N%o4cKLagFW-#nJa{9!?c#`C(KN;uw*(@iF zvkC4hY0!R-%aWSy%L)mtI{`U3g)sc&zmq8>fLDF^pkPSJSU$19P=K%eylW9)D65a) zRDD#*AQRlH#e7=v3Bde0eC6l5b>6yQC{uk;QS;Qi_KF?qeh)O+=M4a~4Nr1wf{x$b^*&%5U>Z<8^|)e3s& zQH*2W{TCGDoVWZ1^;4S}2k%y@@QxM%36ymb=h9t4y$nhm7s3-NWpBgup;4OAE#y&<5dlPOjOJ(bO-5U~fcT!N)l zXj3dLaBN%vJOLiL_+=8)O(!$Fz{VLmI}Pzy0e`fR)i6kqtnv#wDJZ>sDxTz7LqCrs zQZNig&aXmk&yUatlb6^GO*(|hvOJy13UoRyBxdAy09?TaR1a&c0%Cs zW(PRe>X5HNTjLx{+6!zeo@%GB z+35DYG>61K?3Y4gr_P<6JP|uQae8v}*s=ZNlJC@9Mo6Yv!l*c;y<7+#7dVn*ZWhqP zO0MZ7u;%17mh)nq4;?=ya4Y!8avYLyt`3~AM{>whQLV25Y?!bpVc^fU-=$wr%)VF;6&X3;7 z*KZT+x8-a#kLtJHv)-$^XBF$abCH)Ga$g*LI4?$y-Dbh+YiQ`A~-#>bP;Z;H_EmHZOXc?~doa z?V`7R;qX$|&|=q6zH3?c)dPr+gFg!9L+xUy{l?)( z&d{ClMQ20K+3;0hb8gGz!>i!H=SxQZ%?HkifipSRnMdB>9owBBeB`|2zT>|Aa?aND z1TajQ{C3mx_KAc)o6@ShsVjZg{b7_?Mf+-AD6v$Hcm0dGB%2dpu`5 z&hy^xSzux_ zEMZS82s%BUP0V3BC?%UAaN=|#o1RUv0sfsM$Tic&v&aKq}k^Q5|wCq_`@q;I-~@p))QHQ z)djQ38K}5i6B>L95&&p6le$V@#_5vfk{5u-kRF-lvT0I1B=ZU&m10NKUK&TXt(6or zkni(K9n8WZLH{;YbkK@345Rb(ydo^3=m-+cxIC|*o+R^S5E1FQOcIu`$m6-KyjDr9 zXeJ8_+ip22;t5$Xj5ZlVKnHkbG_E$@RJ7n|QpX0Ci%-cIfibPiqVjYga95W_p*8!6 z^xC6JucS#>PkD*}HcO!Bg()=7AXl4^1GRxdm1-zywbtqbUhNeaR>`S3kjC}#@%Mf6 z`_VUHyA+J+a|*jfsx-WiJD0E^nHeElnz(O~Jn`9N?Cr~-A>m76x!sT?VN=)%GH&Eu z_N4Q@YGk3kG3Ag;=TxK@H()>VCxpHw;O_ZpqHi!NON^ z#bQM2jg=rxa>tTP3<)sL?SdTK5IB-EHqEi@H5SDNo=r`cWFnY`oH4>7Vlf`8OsK~V zA}4TrA$+YxBR>Yp7g6i+=a7WI2+p@4IfN*8;63MU=aQ>o(bceUBi$or_N^(Wzl$-h4L!1lM^T;m>i7kJb+bjv2XS_?xX_`B(m%lCor zecyY5+kso;k4PMn0~YSE^hy{z9Q8S5p!_Mk{TMqAUdYdlzZJAjgc=8pav)Qp^?29f zhP>q^LGy6a2S9nPkAO=a<$>C0gTO2+8ueF3eU(tF<}Do_pIS>wST!YM`P62XaLt-L z7^oVMOh+dr;Cf7XKp9?p-D1?{%$H1~dCR*X)m^vz&~n+Ls=|#}2MNr6?SE@b&!|`# zp^wF{C4reM)Pt}-xla`isE~ggkfrN+e5WyF78RyCmzP;E@Ijchqx@?qo~c{sOJKh$Mb4DHK(l0$-26Ndj;RS*((W_ zh?YD~0(BV>(h0Xrr>|`;JJ(B-{S}nK{~K^_P{k@(EWpYz=M67ccfu;yU$tD<0ju2F zVOZtXSHUW`z6w^kl~u(Wr~i>+A6*O|U9M@l%lzc+e9d;T zX8UqY!%rvw>G=HvpB~7y^ygdp#g_hG3jgxb-(C80GFNjdUvo;VIrZ3X-Ht_XuexIs zLtAp8E#H3QqH0=;R0Y5=x?k1x+)L)`hQ+$!hsj*%;J5G;?U)KZ4k}b51~=zioB0N4 z&R>p>>}#Ta-Q?M~+xqLS(7plduLtblm%IkbSDxVf7P6NRoQp<+vtS@TkW_h$s(6?- z8aEM8XQDjtUgIPslir+a72;x^{OjXBtCNV5$!&@M5GbuazZEr`HZ=`+10CDy6F#9Y z&1A6@l&;zWKr0^SCYgM&2$5HAu<#&)HO!bzUFBD56A2B30_g zV*h{%OxR7BJ$DQS3@V}YMLl;EUdhy=6MbFi90Vt9A#{O9-l?br0%iwF3&Ks5du zvhxXWfDY6VI?$H$Ze8w-EOibob`C9vHr<^RTl)U_;fKuMCG!J^#DPQqHk_M0D^9+d zKk}A%Qv-@;YNPL#JY?oL3wp)=&Dblf;x+(d1U6#doq`XZ$|j{=oNI|dw7u&U@ppNp!jDZ0_;qiS33o)v4h zlw{Jg%f9WDBT%f^WZ$x|xk$l}?mV_a)XlRbvbcvN3);JilI*%J_z3bz3$eGg zM>U^4`A6_-EkzIGD68ag7?nI=-4BAI$D{^gysU%q>1rXy4`E6VPs=3)Zu-q)S=2)m zKwc0(LS(R9yGzKyXqlBHaK1T?jjghvJWXQ9VX))!-ayXC8dzV%Vs?$<$RxA^H@C+Q`xp(e7}&%FV7l{|VKxYyx@ygsrjy?|2~{rG)y2b^bGA6dWS`iNT4 zcol%u9&<0qYZ&fDhz{GiJ@7-O8flf>l9%PES1=0Os<%&`W4NF~>TFz&)EGKJTZQ}= zNXWke4otjn0&A^8w)WwoqM^{#25SvZ`LzWhl#&&MFAlA(gyxtu%~&sj@JHZ5gacaz z-^!;{UcPRbx9}h_pQfHJ9L!tFuRuyyEAthw8UXP^x6aR7mK5Vh;s|QPVYOf? z3nlp9b)#N$B+UvlBj+{VK55$h0E#ujc+N*ANLK=x#D&HE3YqJmA9Mv?u%6%!37jt6 zoA8dC07tTdtV;&SeVb%Wq!f(+=8?w%4mN!lV3upu#$lkqM)d$c4GxTgqK67qfAG%x z@7xvg!7ee_b<6fBSY4zn?uJ5j{hfiYTDL8=?pSQy@u24OhR+%v_T+aS5_cZ@GLdWD zk#9XEww}6WyY*(?)%;bk=Do|eFJn;) zh0bYoCeb;AP6?~=5-AC>nPo`(xwDw+95_aWV;(z3>ywfAP>7rdtO492NGMCDmuNNy;iIL?Xnin*-6dg9N!VKw_LYSFCE-9xI9L)6m4qu< zJ8P)VbOT|IRX2lCC+h;{*vM3yQ!q79Lam_%br4?39P3vwM>k=P9+=rpWDdq#VIe`7 zkwNIDId+y~d9YUSsNScI61p%0J1#E6T31$4>pKNVN;6ZG7s8{d6b;gO3d~rj_s=Rj zx5%2GVP|2B7AW@B6ngP!lYvDxEZNI#-T-k8%vbRgs2gE5km6x`LFxKKW}ReJ3?>N` z>{^^$W8%nnR0yD>AQ1Fby=nyB5SX-DnqGb~1J)UAn;NwtfJ}{3L6m{cfbxUoVxah7 zGq5#b!|^JYPb=jcT21Wf!qr$J&M_MTmOeZVIvY;c@5C7fhV}O_R-ja{i;?XBv;stL z*qo3|fq^YHm4u0~;pkLKr?GS$=2SfMb`1862*ftI@ldgRuu?1K>u@==aHeAM3!r*N zYv;y8mLbp@1Rb_ITVfo0AqlHI+0we<2sf3Ewns3h%Ja3%WCHxd2G2Nm^?RdW3M$yk_0KEb9^BJIS5dC}x$Qw&PpQ!>mfug?``uPl%T8)09 zAQ<*aPKBvU0W)Kj0_NE+`DHOckz%Aul}>1+2y~6go@A+3^_h5s6jBMNN}8omDOZ*1 zwECL!`i!!MqDSIjEhTvk!Z0@rZ@4TvX>>B^yp7HrIw^E`bp8k(JZT_noqXWK$E0-% zK;B@^BxGHqJ=!L#oTC>cR@(AxX(KwgzIcMr2|5mJ!IYvATs23jVb-Yg3K(==1cd~d1g!+Y1l0uT z1pTBVNSBb#!9L@Nf-Jzjf`0Pi+4@b^q6DB69L(BdRI63%T1HK)_9ApF|32hGts1?C zRt*#kFHKrdvDR7G^8@_tDC|0jzb%EqG5l>V^uLV1jfKb{DBgU9fl&-LY0<-nG2B|{ z-38HpHTN3&Iig;Anttv}&>a09>*utAPEo6ATS_cf*bHZ@11BUxKVR+U7!}FXlyz7ABeNGs@b-?gF zCk+2OVE73Pjop;8i`8a5jM2afJ$#Uh11+AA+3^&zgzwH!P{j(y7zT4+LI;)U9E%Rt zltb+~Uq;9dw5_eyk{}Ir{D{HaOnL*x!Rt*FCzLP55|gC zYWv>DRK<2U5dqFETh6~Z@7e;p&>_#Z7ZbA++UP^m2RmQv1MS`@nd7}9 z6`PJi!gKEhm+2Rl=>A2z|H1g@hdw*>FqR)UE)E>eoqjb(_vh)?MEW&I7|Xj_zEeG+ z{aw2jyLLUa{cG31a^*%R^TTJv;WN3{-^z9E%6G-Yt{Aq7&b!)|o3|`AM;4nS_k>?u z`Pr3+o_z0^*gN)Rb*?#*Z$2(IABPG=^R5QXpuY~JKE+xR_Tu4L<>6*vu!X&=8&Ax3 z6E2AZl#JK1_7Y-FLg#Vi+h3*{%aQlV|I|mCd z^cHpupnqVvuzPP|R8w-Htj6h@r{E5+sIzADqM78&_!+P zS^)I*72O#0P>t;iEn-7&(ThPJ)j%)!#d_EQfWZJ&)pWNgg8UZAH79l%&@k&D66>ylm>hJ~EklD&Yk_Pimmko@VM{s@E{^ z7>|;oLB|+IgN`u_1|8TJ!K3vRVxfN`YwiALagI2!wQ5bO*Yt2a|yQ%%39R*S!&QCgeUItj0v&psA@*j z>DpEHRN!t3gY|Zuh8bG5H=DFZCzX}7vTJPg5*UKW`4&9I(^0yN?&yYhN)Gg!SMD9% zrlLDc>v&AAz0k@a2CNQ6Gtfa$0;h1)1r}&FGC~Z^0%dgI2Vg7ecgKQOHo}07P2@b$ zRvwioplL@?5xNu!Yc$x<-b7ae;0I2No#c;CVQjTS1v%D1tkBjs+< zx{EYTuQu+4Pi|b7z;0zM&xATWtE_HKB!__FT4#ao9QF{yf!=t@SY4x=Ol9lCkhDu_ zYpK1^&`n?l$?z$~6p{k7$m=WYq@{!L%{7gs@r9uW-VRm+%8q887YHFpVlGcx4g2=fMh)14pzmDK(B^R6B-DB6IQX7E5tY%7As>e4P+^7YE{u3IgJfFbt z&(#1}6!E~Tyjk31Fq|Q-32F_Ptj2dbI*F0YEgQ+oCD&8##*Cxj@K_^tq!`U$H3lQ8 zW(WIc&__I)=Rl$KP2C!HutIM?Sg+iLL9lh*4iy2vKzr|d!(K?(bNY~|8SuivAU>)BzHj_`83>18X| zv%@Hz9pzv+_P_u$-ZNAFMDePp0@iQkGPXmT^#ELZR)w*CE0@7kZl33BSUlV-EFK=k z;z4FLv3MYnHBbV5Y7@hTQ#Ne8gNby*#tjIPgK@YxTieW`Si#ALVf94AmpJ?T!GYQT z)KdlZTbAl0i}k8b-I4EoS?qoJi_^LKNWT8CSPxe2Td%(7TW;xIY8hB;QEU$nQ~AN8 z;vlgnv<&21&WJ5&Pk1BmYFciKEVT_SwhhV3_b&qZT_?m{#7NOLly5sHwttTI<$Edgi zEffvC`G%un16n9vd(Xez+OyO;xY#=Qfcbppvzdq2^FznQA!4Cu9n81BCbpu5VjV{$ z!VX#CFYEi)I4nW*{Wk2pT6FfJ^Ax2&v0*kJ|ctt7Cg@+gOxi(x5~Z_Gff->>4$7KLipq%*OA~% zkVB?RM|4RI4rA*%4BMX=kfj*POig9^s*~CY=H1H`@}Ks5eN?uM~@`3}ia~Y71 zudx{e+Wr(OM6e7-AaPNCoH*20jY~gS-kh!uJ%|F33==^6y z(G~CjiqyY?ZEw!D_fcq%cJ?b^2ZX2&IZ=!O2c9E#qR(*lOHHMxU)v{B1FT8{zS{G> zPy-IxcRU46CabHwxNL^O7U=d0J1{`v+r*hBN7+y5Z&!y4+WrnM*RC&0E#C)|ZXjWi#fiG9)BH7BR zQptT=-!pKWtM_4J$uJDGc1Dk0uTP%VSdRpJwdebp);FO1_(#t%t%=4) z-Y$;DHC=Nf+ii{7n{GunOXLJ4pM3lf?mb-p^w$K5bxnUv{oSWO$@Tox|2cr;^ymHo z^o~LS2#?oT`tKhF;Qk@hmHTsWR3XG%<29!F0kd{ao96W}&AAV-*dBDs&er_UKuw^u ziCl-6g?}e7J99NM6Tb$RPe+tHn|b+a<(=h{z~xZsqyWb?0R(?F4X4VvWFj&PTM`fm zs<}Aa-Y#uXvLEYo~7>f0g1p}Ei5lz2fg_zS>$^$$@Nz9 zebFIo63Sd$3%1L97*E#;q`O#J(|ptLu*AuJ!KeLi_H#trfys;KJ;#NA;WJ z?BEu?kP)T%0A(4-QT@hGfqE%t{uHPkIrFDLZO@rM1*$J+{yegV;D!lA9l$kxKn$-4 z7Atxz%|!|vSbbLnZ??!U&Ra-ag=GS-E(2GKC9ga)77N_fQ{KJ%(qj_ywK4uxYo`VD z11p_7k;nM>jXITVQRn(z)}) z$N2VZJ*vCP0&>nuCs()SF~0s4lQ2UOej(% zsdOBuMHT_-6akvW6cY@x&?<$IqVqRqSGNdIl`8{97hRR9Q=pht&$$#Idf0hvy2+Jz zc+NfddG6(R&b_}M8cGvLfBWo3BK4K?<3FVlxHK z=5N$3Mb{)1_}oWSrCWwnyRmtbRxH$B+qkj5rc|s-r(5qjy>jJ_;EP_PZAy;o)kQ3crp}nz2*p!vpw=qkDTj~he1vT^{bP+ zq{_)7_lC>-F8P!zr(mjM_VACWVd5Ous3j??Dg7})NLqmO(Y9g=I-9Lv(7HiQs#&H` z@01s0w?Z+^O0ODQ=4HlV-Kt`kmZ(WJD$HMoHZFf+TE-`Z%ffr85Y|Ca^b6M%Syt(w z(w_Z`1M8{M;66Tp{GKj06~o#VWy$It&l+awRe=={6irxLD_*}|{3#@%sv9-Q3dXrb zHJKVc6MCOzE($eCg@z2FN|6gHRrH2t89QP{mwWrZqFBlus+rqLU6{YRaYI;He)rv_ zWkFKw+tSh{p;Hy!GA#rx!a^uA)hZO)Ji2XHg;Vp(AJ>V$7`S>p9R`aDYh)?6d*>0X zDH_n)rh+PITMcQ8Sr+AnNsaTSKOw!^)tx`UV2+_JF}TlQXIy8yhpqSV-FNlr**0vS zpnHF34es3EV8?g(3iD-STD2@g*=$(!?FaPs1A6-by*6MJ(snukcsm=0MLQj!mpvNr zoe$eixS(#Q{7>E<@ma4>CIm7|8R!HM#l4j-)+!N3| z^|c&na!n#eyfV!QNPaBUOo0^hby1MKSdBDeAVIj`re++Zq%S2v!fCS9OoD_{btN7o z77L=-OoQajku*sQ?b4UJ=Z2Bs2HA_O8)HziFl5Kg1_UNHFN%t$SfUuRHM8dN21i@l zNwI2BdWS-5F_Ws*P!q@3?p`iCC5jc;LZ&F1xYp=Uy>$2M4@=v6jh1SXQPE4+^eug* zB-QJs+f=(-OIx>T1cx4@B_C94yDmc%-=UDpk(1mTQStnV08 z(94~CPaIeDEb#$o&0hlf?_KhrIg-lVPd-TgmCyf$&$q7a^Z7sXrDuF;pD!JpF6_o0 z47cab!zwoWxqoh04c=QA?>AcnJ_jKMLR8uHC=8%_$S&~QT%yBQahTYD9U;TvcaCF zs#{=BI|@;xfm_qSJ;)|*4|U94p{gp1dz>*1Die424~!WsgQsEnnI;QGX9hXqk%RFmCyqjb0GC9LClh%m zgR{;o5M(ioX}r?v8U$vJ`2IGLP#RQc>@ z&IC%6WcFNZ|Ab26ZH7obrrN0me_b?=cI1bw z;jk0yY4s&Xg`kbP4hN(G2anDo2&iYlzGv70foRA+Z_SIgd?WMXZYw108150~^6iwr zIN-Z*>FsRT)Lqgg*UcFh;43v2k<24mK*HjO0&*-?@cb|09|9#lhhG7CqgWyNny~^# z2SKcW(LoR^U~~|~3K$)DV@02j9=0zH^7+OD6f2~RNq8{_@Di)QMH3dsdytouMEkkU z18wTz!(G>jFdsY94`jZZy$^NFkAa|@ojlIXdM?y^pPU8Hnrcsks@gVUc6X{^AMV_Mm*%~y8ZH$qNevi zx7W9zHENsG2(W~HT36tf2)gRMT?sq{44B=hxMdfQxUD+!O5y)HDh7ZNI};j&oe534 zgK!sNt&L?Q49yU|Fm<8XL&$g|G>g6_nvs@|Wo#53ax^N%L#PzYgdtGeMW7%zKpTWe zG*1|5rnlxYhWFc8ms@7Dp660~n1X~ARSg?tx~q!CDv

H`%|^v+2K$uN#H4H(T5=jYG(GC17$O${ylxgQo9R(Tt=>e|IXP1px zwIC+1)8!>qQ)cxO>7t<~8nQOV{V7yHG7YJmrCLVS@<0KQgt!950>d~eF3o1s zvp620RbV{osDnNM2wfI9k1lmgq2@_A5#(?Ts~}~&t+*uXqM{ZU{6Hz*5LpXxQZ2v~ zA}d2}NPsiu41hz^C0-wVtb~sX0-F=UVE?|vffj05vFMPJa%vh-zapc^#YVk0D7x~s z%z-_vYz#HJm{nmhqB_>{jG8FVs0+A@FuC2;iTv?tgY0K0C8uH0wP!yuVXgzf)SM82>Mo7La$0>x8`*HtCn&LZ#Kx-`{4X^<6vq|Dv>7 zG#2b7-(P9P1q|0Nd0Gz~O|&Qmy%-E&fM+qS4}(DrVi;_OART}JA2^~BJaO~zdz^sOUvTde19R(7 z>!D|@sl=&4NHOp!_aT&g(kSIfkt-6(@n+BV>`vUw7~Z`-bp_re*3>rk%$ zB?M1yk>6}4fykYXyB%K%u}4B|?NnKaRfI897%K~7>zjv4-n)V7_TBJ_REI}cYHzaS zHHEEJ=lj|vOz*Dw$>F0MMq|}|uj6+cWQBX~o~(wt?@nQWF*79EVXf1@If!&?-6Rlx zH}uocoygrtiTyo>&Jnh9Ws8S{lNQ0WU!%r?R!BEs1epjIwoFz5Xt+!OD3G=BDYh+! zn_Q98!TWKZ7)|twp4KIElQ$aRB+UTk)*1kA=B2c?2YS%2PuxWSPO~G>z-R(<)3V^! z8t`wS$}3zOosD$8jBc0PuK27z`dVcy@}K(KsDuB9QA6!je_DF^blE%F=x*#|$M>Kr zJeR7#sG^d6@xBJ0OEti#I({>t+^TBUno#5L1vSMLJ)Z_!M-voM=gR1L3ND5`HD;TR z_^qzLghHh`T`f!}rkIMcytrq%n+Le{{I)BwZ5xSuw4Kle?PUl+Np(u#$J z&NKv-)lnyJ@zjAgH0zr8}Xo zw~8N}zTfu`v0ua~iT}Wi|KN*gW$STs>v5=ZwIXc#dhq2n<)hi3&)#3Gj2t#c z4nJHe51y(Fo-zkd)u{}Rn!^VlT=@L*XP3(pXDWxznupGo&t0qxUowY5!Ii^96=D0= zFIH=4)EuhQdYG>qI&B_0{bjl`bj}<)2i)GS2wQ&H)puv4aMQ$K4DR|?pAJ@- zn3!M(x4OGsa?C`xd%NQ;hc0aN$Gg%Cx&gOMM%KvDT}g5GF6cBka4|J1?t=AOPsDG! zEL$D$NaunoDip6CvIW|3+SNzFv0<5?+qP2^=+A@Ua8#c-3%*D=!+|GS85Q?{FHu|G z)6!YDYTc{NJc3KvTn+{un$q-jxV3Y;xY5Z6_XmgE@^j3e2UR?NoEfw!#*XP+Ov%_ZU|mTKicPDTX55@vK4K z#;4ux|8vjXP3MW0gqm?qJB%M*dksEpgJN5ijw9!oHs1t~AOP?>ZDM8L3kuw5@gG1* zk3#^4Pq`;;zhAz3FTQ%=t8K46+V>%2r z7Ozvo^1*R1uWP>#8BkTkd;t-Hb*(VQ5Dj)xK)l!m7;_7Pjn$*$(F!ksbTk2{MfTVm zbI_g8m95_<{b$fpe*^)Vcn3*e%#7~(DmwNkI#!8}o6+%-P>qRy9r{^l?NTK+YQ{!O zVKDceU#TXLfvX(A;_oLP2%kqji&XZ#Zti=%GJ4b;J^C+`Ukd*g`PWG0#AWlu<;t-u z=CLc4(JN59(w{Q>Q>Ea#Gw3+LmuDcX^rX$6bje@sjIF-)s54&fj8}(-&7u9~(C3T~{U9LR=z>21*Q+F1K}oXzw*cZHNy6LJ zdP#>QDPS~9=mF4ks-c7T0r6Wmy%i&G3C;zTZGWRl#Efvui}xQ|7}I!|w>p^%0Z$LA z!fb7TfuUJGrim=St%4Ys;n0kD!L3(2iA}?G|3jMQa*_m)e+hDRG(ldsP4{lBiop&n z_#8@L2A#i}C+QPv1cMt~pvQmfWNjxIKU6)OtnMAFMTdQZwE?mxQ5(bk~h$@loG_8iAl1-LiVZjK0irs-p)VT>SJ5 zi?0WI%Dpd}fsvZesmmI;!LN8AcKd40gXMcVeX$2X5BRqoe3AN1FJK%+*U8!(u%nT&7J-ojZui@_NP;NZB7dyj^iO=CDigjkWrF3dbh z_CYb$nrVAW@ruyKW?yTu?R{bZwwhWxmFmz$!?2kfY9V_eG__eUvN^qR?Q0)h@pNkS zJJb@AT?eG0I$Ix>;FK{R5fh&&cY8F3q4_t$5qpVFXfh-b`g$LPFvJ{J8zJ0zu1wBV z$w1k8t7N?V?021PFSou`a-iJ$R>|IS>-)4i8|nN(nLOpKl0D_tcb)HsgABK=>fKsy ZeQW+j4+n60dbk?-6)XAmGs@Yh{V%dh5rY5# diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatpermissions.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatpermissions.cpython-311.pyc deleted file mode 100755 index 319156c3b37d2abfc971a0689ef6a831a8df33bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10314 zcmeGi%WfOj^$uSm^&s`KB|jvMEy)QLdT7T=lM1Pk*iK?QfNaES)3RwtBhHmHG&#f0 z45e6LP!}*zB`}&SS|n(-&>~0^#EYVvcF|=&fKCO39Tcd5qKj?{25x~OtDbX*^OT&} zlKWU>MBSNlALpKX?s?5U^UI!|P6F2-fBN&%@23d)3j)p+Z$I4oK0LfjWKtk9Cr8R$ zB~pk~qJ=1jaI_q�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 N%x?Y17j$B)`8Q*ldlLWv diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_choseninlineresult.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_choseninlineresult.cpython-311.pyc deleted file mode 100755 index 566eaaff52f36c4093abdb6cabbfdd0b754d7297..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4620 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 R&NuJ;hqe6okaouV{{cOG{_y|+ diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_forcereply.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_forcereply.cpython-311.pyc deleted file mode 100755 index ac0293e8f3912ffd84063eaeabf67ab497ac76ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4370 zcmeHKTW=f36`tiqTv8XuNnI;R?M#yn`y`-GePiJiDDsqZW_NjU?4*6q zaydJfGiT0x=X`Vd-Rx|M!1IsyKHU7%Q9}NSh4jfMnMZZVyiY7rCzfJm9L3GlGj6t? zRj{0Oa&Eq!m-(DC)1DzL(XEFll!A3ybyrQRgv;@!&| z9Xq71Z*?6;P2UrS?S<6vsNdXVrl6u@2+CQ&S;#yAEp&r9tj!IVUh%ofZm_`VY5zj4 zzrFN)Muijj*U9wGKCYH%hF)2Ly3uJx? z2ryDt0ENsgn0GyEW$L*iDH3bi%38UP6f4j2Z0h-;25Sn+g|Tu0%Ic`xn%X5T#Zuon zQZKU7=5*R|b0*EzXV@&88}(pEtm1iSERqTNXNL06d`Z59^1I}YQa=hv&qSpWUdA6` zf+Y&it-$vHUX$5dw$}!9T^5E$o6&7sbO3ztP3(xp5$>jAOIK{$jzcXw3>>2eJ;6y% zkJ_GKyk(e-3SW*OI*fKh#_4GT+-Zc=Zh_vUt^?%|{Amhi$=aqbPC+;%Mi?H{8bJV! zr=+7#l{G2@#)JrIGC2UdBRF#zj19xIx(*J|^Sg8#d=5rXlQToa<1Mu~m~Me+C|I!6 z>@DGUWOFE|?RN$37>Gwa0iTA3$?cX6lWGLq-ZIP{Ml7S}J3<6uwNf#C&NPt(rsnf@ z1tt@2gC^G0-kEJ zj^VVZ-x}w^#cpVOfEYDQ)9-phD@oOHh=czSZ}6k(7%0P$W^Q0`qX~?IQNdrXlwv>c z8jdY`0P(h;xcv#;rE(;dZ7~jp%WjK_TWwCOh7i2kh}~*$u?B^~rBGs+rqM0NLm((l zxXr9;m7YDLoso($C^sNHPIo=aH@hxOoLOZsyDjsy(Ewmfrpst+G{DOtM4sz!fh7nV ztR8|HR%*q#@K8V43UOX-Z164^3_97JAdbprPX^{iU(l87tH~5r zcsr~P^$n*=PsduCzV9>^sh_SwReCD~LZBBAc$Wd@kB6zWG$B!o`|eOXA`*fz7=V&V z;1dtlJh}m(FadT1MaA2E@ z6WYNfpajHUVk`Bz-NvOqrA*={G~M=suFzXHb1WT}DwB152YV*I3I(5Z6-M8<9GKYz z!#e)9C+PysQssm}Qa#=7uy`8DT8NYsK!G1m$W}#rNp4DGSY8?JW!F|~`fBa^tquLk z>gBad`t`MypIm-peeKfa8;zy^OVP?(PgOLb2k_=#ClgSAdrDp^!K1hsF?;E;(nQmXpH;fm2{s+2Efd38MV%#A8D!P@k(exO- zqT^4&IVuhVzV?X{m5jjF-`<9uBIJ0uNbphMk9qt*`ZFZIRo*88Ym?^z zd>^I-vNzT;tRy?xKPV5N<>9auZUUJdqGwW>9R*71m}Cdra>F*VIc#a6TzdZ?J7jMv zl^Xv}+5}?}IOAq(d=`W@%7rKo2P?)SRo89L7P`*yt}{X)D(beS<3S~i3VMq(c9)g& zQ4X+cjie+_AgarqPuD{<3%zyk^Yu!{cUi?Xxan7}`fdMQ1F!z4r8nh*s0BR^H!yPdxv^~^wfs$J2sa@4?>+LLIZ~W^ zw{XAkcXj@+>ipi-zB>P@TG>}CeYJA%-B)*W`|A8b`Rs1){@lS2u3_9G@pe%vl2y|4sfxE?;?b?FRV-v^&o!tDZ%WZ@;wh6kj;@y#ehg|ujL6sdw;|j)@Pm7wK=Hhc5M*>F2(n?M53fl=a(8t2q zWeDphBpwuT{#-pDN5KWY07Y~__#q^NtfDA`*NC#F^vTZ-$;PJeUq-?HVir?gAkzW_7lz diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_forumtopic.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_forumtopic.cpython-311.pyc deleted file mode 100755 index 4a1e7aac9075265f9536bafa47b1898b556628a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9005 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 R_G!KWV+uC!b(v4he*m_lZyx{v diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_gifts.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_gifts.cpython-311.pyc deleted file mode 100755 index 15e8d2080c1dcabaac4776f61a3453eb57932320..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6292 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 BB>MmW diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbutton.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbutton.cpython-311.pyc deleted file mode 100755 index e3bf8e64d8a434457c5e4d047ab984c45831b1dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9251 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 JI*qs{{tJDUeFp#l diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonpolltype.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonpolltype.cpython-311.pyc deleted file mode 100755 index 324d515c8f57620ad6de901f566be7dbfe15287c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2648 zcma)8&5ImG6tAAop2=i`nvH9WreGy;!ls9i9ApU51Vge>cJr|TX~Eu_>6+Qz^jE5C zvYBNMK?FClpa&&Ea>zj87sef?M*+W?4fSbOzbQPmrzC+`TM958xL!bBA5JgsSDm$(cEaV=u5f zF2&8j7sT;7CO!@t^Ry|jm?Hu+8ZyeMFMxwZH>5ad0X0Ki+GfPV=L6R@{*aohTBJ{h z!U=rh0zHz7Oe<|LlcRpelTzm{O;5e+G=-$)`WaB$OsrF%Vlr622*js=21TX@h-7Td z%-R_OgW3}c&km;yFF0UAgANQ+&~F4KjtCBXw~M7|TtNrH zxY}_RW&Ts+nHyg`edhA}Cojsqhqg%VP>LCCcU;1f4HApe)G+Wg0L&H~PPdz#3PJu1 zsZY!%N~Jn=epj79Ly4V)P&tr5nrI9;w=^q*#!B$DcheD*m&0= zJx>jCiZx_~4A-+!9a8yx2q(uADwxcK?WoE!B~hHZuSI1NI@Xm10_n?S-DVZ&nwg~3 zXz-Oa8wv(m{|UOUv|C8X*`(cr?}K!J?r!1?Cec#nJMA8D9t^k|66s98)NEp_xQU6-absDv>E9L_KsBz>-jXQ!K4oUM0X;WTH zt3=JZlGOCLtjYk(P#R&E?Sfqv_dmJj8>wH%K!{&}?w=dz?+Pl7+$^pXf6>Q&*2nIi z>*-?;_1Yu7*3)ahjUW8x?eE|EVdlqU5690w8b7<7TPdyWef>`L_C6p-*7VBfmCq_S zM^;9b)w2#t;eMQ|mL-Zl@u+1*Wy^~1UZ5+MB`bKsDO#2tG+`QW;%*=~U@j9O%0j_p zGMvhxXlDXrle(^DRW-I7SX`#kJ8V=+!GDan+b09YQbcy)oI> z(f;v%en`zj-~N5tdxrHVkT21+LcZkR!2B4kCSn9%d8;-&lObBivymzRtWr+i4#_$b05X_ zNVp#B$K!yUU~j-s;>hnn*UxI2)<1x>^I8v0ucB9b!|xh8+8cgX5$+AYtLRW~_+3Q@ Zd&6(PFs=dM+q>Hz{V8YvdIC#X{~zF1;kf_+ diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonrequest.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonrequest.cpython-311.pyc deleted file mode 100755 index bbdf38e5308b6602901efae1c5e34dce87bd9b74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12646 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 diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_loginurl.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_loginurl.cpython-311.pyc deleted file mode 100755 index c588d593f27530e7cb939650e41c2b53a6f87c29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5017 zcmeHL&2JmW6`$pYxS}N`Y3)Wy&}NDNcIZf41a4tK2!a?X&{%L~Ba-{U9+u19AvxCW z&Sqv-3SwKu^7~a0?VU^}X2-iH?H!Q1ntS z$=#WqnK$qK-tWDc;qMn0n*^@Ee)79pOJ@oB8&-;|o);dkL*Y{rkPZo~pb}b9rBku6 zTn(#Hty44QT3Ccv#_ZZTg|J@hn{ERjsHSVIflVj&wyFQV7PfX6pw*#0}pY*`cgdZM|Ay%5Sv zMYrol4z{juUf=iu_qCtvU>=Kk)WL8VihC-@1@1l6E+&kE|S z4%W=E`b(vhpz%cAhI->f`#jX`<9ffjPx@BS{OGyP{66{6>NEj~g^69*<6Q=&3@kYY zGv+5A*v>SQRP+HIMtL0an9*%E?g>u@w3livVwx%zP%WsJY7u#w`(7B1n-ng1GZd2V zG5`~L$u`|&a)$x72=73$4DrzOSp=BVzK~|30?`b3`V$@un5Ls4i%m0%qFk9Nd=c?@ zK>JcerN7$rN*EsZj2R0QDi{bDMYWeWe#rf8P$9R#ivwgtpUVh_fl^@Yn2x+yn>k=; zCFu@N!1@lPcafEK_fm{yYFd3O%?1R(`xgLYU zBasvQl;JsovEl)f;6yWQg>vI=F6o-5wOs3_GVCI9ra3oeLuj^U#-pQuCQ=%uN>eW! zd1Fv;$N*pD%+OQAf4gl3sJK>%H# zKU(}j%48Nr2rynC98D_2ASW+426Gk!VVhpf0@VbFWPNxV;wMtN@Py zecuq}%l<>TGYXfH^K}l*sP`q0uA)S6YrB*Rc8(yoxte{bPkMC)Jea5aHM+q@5NpsO zPmF~pV$5JT9NZXzOS}P7$D$$BU4$$~`%e&NM)b|11BizFB=ib6oclvyPKGl`2uz|x zQKi}l+YDDR)v}r9?k3Y3F-?<9^3#Wd%0{lH$*Q*sI$z^Z~fJt4yG40&$gvXEt>Et#?|=8{~3fh&Rafh$~=$_dbg=ssgS zn2SST|8vaWA|D~$^4xy~Rs{~6XU~%0|5p-(rLEZbw*SjXa7OgAB$(y;XGzekFkhPl zXUOwEN`kH0WC8MJxuQ=NPHr70XHQdlQiYXl<1=g0^b+oF!%ktKrTr-^ za$>tKkGXc;(=eILyF765K%yoMw=WsnWv#}frdZfNt-rw#2D#?2Renm%nrG^}E<*>BwIA&BCu2K3=-Bv~NC-K|EAKlJ9Z+6yT|5rvEe+QVgb%L)8Wjqypjd^Yg+$j+YPhM8=xJlr zWHHCjXJP2NEla}xHAEqY-jV097ouuzFJr?W;RePQpK0ZC-JTM>NsGL2!@7NS+9Vg= zI6Qyx(77}{^UeB;(Rt6oG;LtbE^6~wYm!$l+}HQw zLdv;s-~H*Mv*(`>bu9ENOY&QV2^%e2q8XDpJx*ZvmO-*y_`D5=g6t2W?B5cJ;W0T^ zyllIv#=S3$Wh#RZ!TF426Che&*l%TCd0V~)RfJLf5^mF~Wm(hn#9Frw$kjvg%E9dS jh+I0D{T`Bw2eaSl+;z(W5Kq7F|KcB}<)2^CZgl()`t{vU diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_menubutton.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_menubutton.cpython-311.pyc deleted file mode 100755 index 4196aa19c0e23fc1ce7932fa9de52d5e41af1ecf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9869 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 diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageautodeletetimerchanged.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageautodeletetimerchanged.cpython-311.pyc deleted file mode 100755 index 55f323c2004cd66367f3ee2c1f90dbf9e77d1607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1979 zcmcgt&2Jk;6rWkI?Tv8^1*)cn&{3sExFWlXf`qUTB2Yj?s(WY-$d}1_XPj)hA7*Bp zkdQ+Tl}J$}E}$aRLry_e_+t!;MA-|GIB_!yNT?^?>_529+U@&p$=l0837KBj)Apa3QD2bF;m?P%3-Bb!N@=# zB38bKScRK=C4~0j&043*s&`P++Mo-|z9eDH1_38t94Xh2Byl4WcUQQlh+1|P5xg(B zhF6lf2iyVeUf@cgRA}bIzAM}=Bta9)MVQXw zpA6it<<4Lbl#Ta)fRBrTJ$5e*ldwDUrP()G&`gh zi(CwFH!FRvtpxslJ<3Y4(e2@3QvVUyFXcKQDT6jU5XysV%X^Zxk zwoSBa7W(P$S-)^?AUGgKTa3Y^W;rR#L7$7nqSTLkMQI8x8KXX8r9Hv<25*{) zDS6O4!49)%TG*6I?HV$<^`z@8$02t@S9q~AA1}qTj@$1$t2|nD0>A6@*VS?y&Dt|F zj`S6u?z`SyxJ{&^^83Z1c@lK-X0@9hvFtWtc7I)rgR_mPTmN;!?E=pX%#|O2_-hOO zSw~}y`_-N5Pu9eb*2M1o(3<$catrnm zO`jr3#&a4y9t4y&vA6&xsY~D;@w}b|e-fFP)CL6tz!blc@od=|AuX<<3-;DWqdK}_ zkH(%UUmBr89A3LVD(jAgE>3>)@xhBz|Cn$x^;}K7P=wKLTH+FPl8RdI!>yMBN+ya7 z+O*KJ+g0e|NG=wGHXSHGkT$I4GNVBQe1tLw8u1hBt&G#R#Z~BPD&%J%MkS2#Xv)Cm s2x(y<{PGaJbox0&v%|B`V{~J9_8C>KVj$<=Vz>Rf9{uAfrZl*}0fn+1DgXcg diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageentity.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageentity.cpython-311.pyc deleted file mode 100755 index bdef1b0d5be814caff842222e14d9bf2b430badd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19813 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 diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageid.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageid.cpython-311.pyc deleted file mode 100755 index f9be475e0858ee561feb8421c9243b4b4f9518e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2324 zcmeHI&1)n@6tAAo&XA1mifq<^TL+OHjnlj2APgcZf+Vj9l=G zL8)1?P!4^7yy89Nm0008kI)Icuam;b62^kPv%of2WRhr@F`$rsA&P-oM$!jUand2@?PQ4@`|hos7kDSb+Wrt z*hd}9E8nX&?R~UuHD@%!WM<+R{Q>YByeYVgxNtw@cl!(nV;GowfR}eT6ZJ|3LmN9T zHEN|fbA2j-520xbVk&4G7~~;VOax{XyW6KeSA#m<*osm4$MoiD42)Mwnfaf z8O8-}P^CnpmHI`v*TP`ktV%t5S9E2=9Had_Ux=?a0BEDdL)EG^@W=lM5HE*V#>@q{ zE>K6`9Q7qyzlm~OC^)q9&iIe z^F6%9eIK{kl#N#FMymzc?HR`er0ymKud|q^TObws(uA`QDc~EM5NTIIJpF+InlTTd z;qAU+|MUM}^RJTp=+v}OKXG$Unl|QJv#*9E9(JL zdNysx@IA=}=;(rGGKqF`-&)6@IhklJv}^4ml378!==MbJXpOdM+AcaOWb(!Dv|T9T z2ufFORlq%fYQ>}|`!N%VO$ZOUBE&#TW}p@jT^wXmCLO`p4yzTCf@FT@96PKcrcx0i zwP|2&@9C=3ivs2ZRJf6|5_O{`hsLq9$-+&?=WQn*s9qE<)on7VhMv`Yv6 zbEeokB&D5u^>`rW;NYFhw#rI!z#;nmkcuAbVnpU-|ad%t>6-8a88I0e-znuCxAjF6;4$oSd< zd6p1eY*S5{5HE6J8n8=0QWC^G6hWcmAoN{oJWl3PYFy^~gw!l?2~<*t^&N3puPSHV zf>wmk0g&uB$~|ASM@Vf-Ij~x@ z#T6JNB{hhl4jL%Qd=`&7$)xekCUmHi7qiJa=|dfpb=b?~m;ep!AsQRdSfAQ&joEx# zT!Wz|L2g4g%3GE-dKFnsYluEMMGM2}=M*gsr=Q2@wc+$LDlJ&R%HO*$s!#OnAJ0%3 G&;9}c>y8`% diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageorigin.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageorigin.cpython-311.pyc deleted file mode 100755 index 240d94801695343e2171278282c8818c9741900d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13051 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 G@&5&bZ?=5^ diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messagereactionupdated.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messagereactionupdated.cpython-311.pyc deleted file mode 100755 index a466b4685324f03ef1078f81b5152443dc968968..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9313 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 a*S4Q|1x#tMryOl2@xd%+of4T}AV>|9|S* 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 LoYgGEnB@Nf>>Ow# diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_poll.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_poll.cpython-311.pyc deleted file mode 100755 index b372dfd4edcd372429c4289e1127784235bf4dc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29336 zcmeHwYit}xerL~chMb{D4qp;qqS%rsk(9}yUZ%aYB%6{bi?&3`BI&ip)(wZ#O>yXX zFx^AR)Nyx(#L3bdA*%omRtOXvaacHV)0a9{4m zkQZ1OIN*N&s(#K4AF}MVz3VnzQ{DBi>guY0{pOpt_#AbBKj(i8FGw<1}Q@|QR*&R9&QwssYE~P(WgC; zJs!a;yevo!?+Q|*T>n9ZAp8RV^DDBKl{KNPxumR{m2F4aj*_x{tgHoPttDmqCGUjL z*LLH@$+?6orZUoEQWoQxbT*bqt70rIW@hH)cvj5L#j>IzFDSAqr?V&#C*`DkRf(m< zi<9!}IFd_fJqMVM)eHD7`uBHjzON z&_TRP&Bo9oZhWWk68zSlmsK@(RUS=e6WJv^s59SnfpvyJr&L*?Upc*)!f)e3Oi|^i zYP>rdQ?B-T^_}uNStSDf$lR>`EIk~|w*OlDQRj@@PxDH%OTEufW})1zlb zrp`@9$1jYJqW%uvDgdZEQG9qJn~+t#xyeyL*CD^*CoyB^6eS4x#~m0a0owINl> z0XZmF+fVGA6hPTF`+hdCBFuWE;Jcwnja(ZPq>xnYhLE<&0jb8WA=TnuuTCh!?JAZE`$N#mp=a6L=d>##G>>La3X<rm#49J!9Z>nd+=@Ldk?AE3zcAYW-q@ULz+IaX6OED#O!R;MKH< z_p)-MPvNk5O;%LGY)O)(;bHOcq3~he-x1}iI?NiU5uxg0?=Z$>cv{UW(|yAtA2e3d zZ^04laQ5l|TO;&VzTm?4D2LCFjYrRoj=wy4c6wkl(2+MxP}dvca~Q8UMoJA^w| z1IaUz?Cfm6F+Etm!{V|HvustSZl79I6iiog3E=7Ek{Dl9vze4Ar!w;i(OgGt!eYr} z=DI8uz1srmHOa}F!)%fr!{DM4(^p&_n^=(JiCEHlm8)}%mccv(7#Mgu0u)ZnEN1236^yi&Pb?Y!Mqwm6_8lIU!$ZPium?UO zGkPr}Hs*rYLq)V_{6mjk9a~65-@cAbT~%7K|0wO0&<>^SL=yKQp$p8QKnKbJA9}}?4gmE9bicZ|AS-$x8cn1V*=W=; zG_`Yza$lwHQ|08W1Kt`+z(*OKjYd`KAI+3_^YgL6xlBqP zOvRLVX7H8F)y$DW(9gkZa{Ag}GBGo_u#}z4q>qFT9U4>n{VXtFPn&t@*&978uM0 z2G`m;SA4gEYvJQ7J}t2G;q$M2ayF)0&^uyjORt zZiW5#7|jd1Pl{z@dc{m8t8AzHN=42tD(Sd2uXspv=fWk-6dsjc%S9OT1JANY1v@t( zWF76<^S|s_bv(D*le|UvefQtE51jerh?!Jwyrg`+&=m%aX=HFy)XUK+~3bV_)&i7f;My^_u6D$ zoYKUp72irUAL#s5sQJC?x2{twtEcb9SALWa9o9mJbAiLke!S&F&p4P{EU|PfB}b!r zbu`LlB;;$NQQ|6%lB#G_%Ea*)D@aXdvMLs2JzCH!z~U**$SJg-6q_ky)-;CBDQQhXH^5~rNJQH$ zNy`sOs}j-`ldo(E$j(8!s&dL*4(V!}T*KO`c0)kAsw$GMsyzr= z^+oE?&jz#|lKpmn>>MELArty%z4kNIY<$-rX^v6(q$VOR zLBR!28!o#dZ6)x{1ka?vc1VFc^lDo)i9HWW#Q5W<7XZIWQeP}BnPT9z45X%LJhPaF zG)TgyQyl!ZiF}TaF~z+Ez6(6;_+n~?r1DvD5lR=8tAYqz5+THM0i28MwwUAM>BQfz z5J&G0Ke+@7vCbvVG0lUail8PT9=pmnl=r`tGS*j$0@=ldq`avR|HVb7uWr_f1vans zWp5}wRi@6`O#U{T+6aI8DmZgaq+H+Tm>16c^TLxT+)N1iAAtF$3PBKvEGBrCL@MHs z*!3g=k+KU_`T~s4WZaZva4a!M*$p6N4?$KcdnwPvNcRYG9*a7`rpVw%Mcm(LviCJh zRQWR$s0JsxB~e9uhD4LrvZBiBq_*$bT-#7tfrT?S7Sqk-6{Qca|9uixlxOh4N|=%( zH1cI+hDOIM8REi!A^2x0A#Pr;WNL<`xFt~GAvHvJ__!a5TU`JQC6=3A5b;pU7RA8t zcw+yEN0*q~NZX>!6>!iyJN3lYra|TgF(zJ3Kx`H_(Pq+a>uAI>JwTIawKt9}*j6eN z&NAx6#R$?38pawZFXJ(6-L}Oh9!tg-lQF0OS+6s*v#Okh_FWQ_a{6j^u6Qe)nmjXb zXb1{LNnXf+D-aiA2}SJ}ug@jobD|2>fT{XsI`xZ88z4%VbWc{CL$grE#}=Xgg}xuJ zPA=Je0`wuL7N@5TMQ@l${PeVVJ%Jw5XqWUm+-Hx@ zM&y;=>gLbr3C9gEKN~BWu|-Yd>OG%EJ4(;4Weub_G0~7V{ER)n8?ROf-POO!qFvRIAf8 zO>fJvl+XgC8#aHe({c>!%Rm(emc;nFy%tL@(kft;93Q-88llc*7L$?~OJ0vHsf3uI z5>E35Z`ihZ*<{G-JYlr;RsEuxfaOvW{)o3WY2O&~F4|Y; zz$z^E8*SyOABz5!s**+?^sis2-@hvTJaNBSJ9O&fseI^FE%a(G@G2*Q)wZ!#uRd>C zW0fIP?(0yV!;eD5Q28Du!<4*03F%n$3T(UUDiD?91V?&PsTW=?+CMh`~G<*-5$r|CCqJR!Fy%#nVnO~=K zLuThr!qy1Wu!JoVu0Pqt4EgymKEQnQ7wNg#`gL?uf!oS8+E>{_x8Pt5ys0uZ+3Rh+#+X%&$y6pfGS?`GO7Xc2{GkjMlObqW zJRe&!yUq4|@C35cJ%px&xCG|z!&pu5rleeQ@JUp0oe@9iYMcO3bMu6>F}A6SINIOq?uRH>xt7K)BEEWzY@(+$;9LdM5Sd^vimJUAy-gx+3y=FKl4uPcXH!C`QqcUoRoFgSoCEWJL!BirGbdth;cL(pMxVB^R}j~N{75#5dI z-0D!pb!_X6I5#~|cQ}fc*d93FYS|ukVlLEc0EcY#>&A`Tq;~FwNug%#z)}2!9zJvY z!F>LiG3}W#x?St;#ZM3}AGHm)&aKtd-?~7_7|Ruc{`P7V*A?o7V6EGOic1b#Hc0du znDb5ao^oK#dOlgjK7FM=SrsIrXH91lIN44&w z_v87NVXb8t4pgtdSM#uQ_uaSdb^l%O-}K%;mOt>4cHpIt_vSm#Xq{&O@K!$1zKMrb zpLcwmt3c{ER)KKOsSEVQw4(V?umK?77H;~p^&n++6W=F5N`8g^RX@hTp_?dp50i9E z$sC-fUh**AgxI~dudlFe2YjLG$ZIM@IY{w5dDPHc@Y7AD0H3Id_s20++~LuiK@0HS{o;U_@|_9M*s^#sn&0$31xM5tFyb9GNKvE zh>%<_4M^MFZ8FqV*={7rR<+ zmN8C64qcsa=-TdRYZuzu@dexJLR&3z>%8^Sd2*~~SEOC;aP~{yDTzeo;2h?J?=--L zNM{NBZVR4F^z51^Z%}qcx&ZH(d9=T$47_N73lXsdes39g6K93U?h^R!GVpt>_V<*) z?<)hp*Mi?$0>8fue76PPT>{@z27aFfzpn(ow+#G#3x0nId|w%O+Oyde=_!FfPzJu& zg6}PXe}>?h^Isn&H+5sb_}hJdXytBgDDi-&l9Gqh+>pphW! zbmJR+CzgWal0!Tlj-{7|r|DZo1onx?WCJ2h>^9uVPfQ!4tt;j$Aw8jr$TBCo1I5^T z%`#~F)(H<|fnl#rjZQdJ{L=$2k!<~{(DoNsB}uX*N{q`Is#Aq!=o@}$`u#g%)tFYx zG?>v?8H&F3{pws&+>>da5-P$NpdqtHeI}Dhk~1T>WOb(X4N%+#HdBhT%49$(3f)q^ET0@kYcOvVuTO zW{0zto~C`;v;gxSx-gNq9TrEf#S%#ty2)Y&$+^^+M4BNY9!wGV2aAat6se4X;|?hJ zVjdmpYPFYQ;Lrx?hGnU*-_(_2iPCsNs|eDgB(A{?hOnFLsD@t&Anciw-&sh;(mYbt zu@qgOK1mK2On(L}f>Hf?8a;z{*03BvR|`~R(bO=Hb4$3Zt9(pYugFUQF|njCNrLi- z36M^1dZ5o9P_s*LrlH|*t3nU18~qt37c)~MP z2Es|)G{fkk>0JO1CpfOTzArXQmYcXDv(;fQ8MbJn2ne!B9_8r`VKd_<9T%BX87*(> zMK7!;@31V7%jateE5h}1cjuhmWhNaLPi4{=Lh@6${Cdpy+a1~3%pP&Qo5p|HY$}?} zz}Y2ngAIbMu{HPTFKZoHo)WH}FrwpH9_B`2z8~x1iG#6SufVjhu{IlAf4{cW`*z&B ziT4iv>35nFa(lV|cG#eGjRslxa3rG+?{Vke4PI!H%0(QYv0iwGvEkD6+pGIK){5Dc zzGBwOWmfq8Vy#@C{yWZEx#`7vd=*Ay!-E8#f}1k83l|6FqW@3FOUbIyL&Uppo@g(!)Qk83fTvk|?N&FZVuTh`G8=+!nit~ZoO^ZGW&!q=M}Hx}Qj zdlQmgcJpUS(*6^nm$!dV`s>+iNJ{OK=hh^dN>+T836pnWrQ{3AvFf zS1FmLBt^+IB{P(e!9tNJnWH2|$=j6dL=q1np$mo{`z(k5j=L`u5*OOkj{U{X1@XD; z*nXE?x)OI}<6>8q3|+=G&ko0+!wSJH+RkX~{^3LVVB+Y?qD zUuixqwzE3z^DPehyp2&b0Aa ze)rR2Gxrgo0XIp4`Rnu+sHHAjeggjhTvz`CRel3Mf&Cl#3AD7q)?c;Oxeq_J4+lp+ z?#U0nq7A-++nTlg&r#&!uC*@m7pPm?6QwDqByxM_h>9_Uai?6NKh@Vz?U-DFcCQwR`cf)r24B{REuy*(u>W3a48_!*s z&L4|u$6~AjI?Sc#PCLE3^fbVc|#w)lVS{TUoXRxvK6*Vc}5d9TPZIMa4ZbD+mu|A&%J2ycDNMSv508Z$69r`AgtS# z-`&=7#YdGTt@*z|AFJH$mg!>^Yt;xRO0)?V+bj|10$4Ko+4xcA(@N+Q@pNsG@rX^BOAY(%OFZ4vEFy7zX6mspC`QL+U ze>ME?9Rt7Y7`QhJPm7LWtz+0Ke=Jg1EmFVg2%j?x3mmq)KgM~(9`ImIDNMTnB?bep~{qepzeBIZi8=-wQqLIjZ#>docMg zZ~XHcxifF&k6+P_U&%#h@;z~_C%)p#)$Yv)x*v8vbMN%uo&B4$_utC*pVazKelncv zd_CX!y4Lx+;fC_C`;gZCy$9X@()-W7xl^y_hrh24e?NEmt$gx-xgaW4E)L(apWq@p9D{?Oy30nU15B8|PVUt__W(T&8pvlv0> zXUZtRd1&3%1C1@lzqBojX>*2xeHV9J953yRJ9dW$&=$>X2uskt6+2_QttXJzCNZ%F zG&I&%wGKJQ{e6cHT6k~6>_2V_qeL470z=rzt4@bKoB@!S>G*J_0I*>B<)zI3CL zQMC1n{|}KkqL(0Wy+VDn7V4s7#!h-3Htx!Gy_9bp(Hci`H6yHM|?NL!fsB@%As1}IyfkE>|@ zGx9w4n&_SKDiRlAZeNG;QtWltMx+@4RbY)&3Y-RUKDr@s-nS}g`-dL*wC7*TO}vp0 zUDiUEbAii@M7yXn2;~<(6XxTMIWC3yJ!C$HRSV zdAJSdy(|^lIs-?jL6>E&_obL?%sM6K@~kzCeUYP3W@9ZnDMFeCr2;2&WPcU`YOlS#e=&JY$dpB zgx)|AUb>ImYj~VjknSs_Y)TK9E_e3P*^ZNMmZ|bZN?xPnhm_o;B`lu9T$O-h6R3n3qBQTxAw z_e~GQnX&YSH`GvxII|(4{~+Sb)=r+Gbl}k1i>C@*J%}CKLosK2DJPi8qnc2`PdAl9 z(~d$FK16Iwb7AO1#qwVo5&t``e!^sL>4=%BluEcos2 zTUzshLMJ`gMa`YP2gT|OTE{W-OU$@8_vhFj#&efE2z)DeLlpIfz$M zl~#}3O=#PD`SVA?+LhFuiCmqi1$P(xHYl%Pq$e8vFWfs%XaBtLAkKb@lLPEcZT?BT ziBk8Q=t$obmujN-8OS8_h&C-S}t^B|${bK1a5+Q6GR z->y~vYW(LoY6$r^^FAEG&W{?}+pq0;R@*ar^TO?^J4fEf+eh)2_l<5Dpy!~r|9jg0 z^EqG3o$YtjyX`q2^5^ru^JWv9L+lIV5GAd9Ea%&Pdl3PcH*!AY$MU{0vyI;dgmt76 zJ6wrt{D=bd_3&f7eo7?a&yeV$IP{o^h{6GAYB)9%XF;tn;4CfROgsh5szI8_l%)qu ze=u&1t}}1L>~s$n{HwRv4-Mybu0UpHAHCHsHFG>7OR1(8I9jA50$4~b{R1q^Z8xmhdB6h*cteP?k?#y`l$PBY~HWP+pH zyczaQ*gLrjf!qxA?ZwS7brjzj$fJOtlG{Q#wym((Uq+i%dbXdEeMmkJ9OM6@!wKcD za0{9(s7=_S3l$!Zr?6k}oblv@(KTU5&iq>wx^wQoHQ`Wh{l7=TuAKXCP3X$G|4Lg} z6OQEEf8}b4Il=X}CY;E*|JH=pa^?QkglBW^zx5%H=7chTk1Fb+1ow2V`F7^qe}&2s zj|cR-e0n?mDJ%KRS$@`g&EvtgSU$bI>r+aJY@Mk!crMfFsN>y>_%_yx@aq63~*N*v6+iS<(w=-|v zd-LY^-kaIS@pu$L`}v!PGox(?{l*4<3)VYZGthZ}43tBLV2GBG7jt4>%1HtnOI9Es z%msNrV1@GGT$uNRmYk2|A_Br934vV5issvLZ2}U}1!RQpAVbE%H3^}0cxo*dGa^?| zD!Mp4Hf_2}-Z5q^tmuwSHPdz#%~qU=8LU%c^x|XJE)S{aE)Jdh&&2+-LEzKM*t}EEl=rA}^2m+h%+Tgo=UZ!Wzu1H)aJ?6pBa{ zeVL*NBeo82MF~c}2dIcDS?Kax;F7 zWz@#8!>g%LVCljF*#QeJHm{A=6Ef}ZtRJM@9FV_mqd(hGByl&q9R5k}`cdv$9WKdT z8*-*BXG(IWvj6Z>U^!mtJqWK@rS}jUZFcW}bo|NA=lfpJA8wZR4goK*DaY=|?#1pV zmJ>_-w*}Ub7cexcdD4VKiOj|!g6S-=^+phZ$->6QTSp;1Sb9PDVEAq;zLi8bg`(iX z{d5J{PQEFSp4%SQ6YggaJXqjIjFi+IZQs$T$Xv#f#UE0v%hHs-}b*e(X3rQv;8Eei23(itevK z03iQY6+41*6)|!cb@bo9RBcDc($#n}xTlJIvbke-HOK}b1idip$*6O8HNtu^w5xaJ zv+~ZvZz(m^YrT(9sAKc=U{#6*PgN0+N@vf?#d7B%&Z+eEzqtB*l=n9y9i<%~mm_`E zpfAf6n&hK7mk?~)b!HRJyA Jo+-YUzX5qnVD$h1 diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_reaction.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_reaction.cpython-311.pyc deleted file mode 100755 index 2481add0f24bb0ce910b990e2f499c5d5293591f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10020 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 eE4jIR4{Ptctiyvi;;rQ7ee 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 O;ghdPm@f*+=>LD(ZwO`p diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardmarkup.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardmarkup.cpython-311.pyc deleted file mode 100755 index 68d84e00423527175a9d9adcbe99a86a8560f656..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16580 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 MHTuV6RFP+Y1OIbaX#fBK diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_shared.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_shared.cpython-311.pyc deleted file mode 100755 index b3f40a7b9751df51697a9e4597d25cc8244e126f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12160 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 diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_story.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_story.cpython-311.pyc deleted file mode 100755 index 57c18ced5ba92500b92431bea94ddbfe49464a78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2923 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 B*YyAZ diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_update.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_update.cpython-311.pyc deleted file mode 100755 index a104bfa5cd97a058d47f35c00800d929c783ba1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33719 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 diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_user.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_user.cpython-311.pyc deleted file mode 100755 index f756fc432df9adef54c7bf13d89e3f9f48d1cd0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76811 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 diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_userprofilephotos.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_userprofilephotos.cpython-311.pyc deleted file mode 100755 index b3ced0b2412b2ef31ae72e9d2227ede816200094..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3783 zcmb^!OKcm*b$0n%k`ie}c1@{Gx(CNK9ee3mMpF}l(8M+p+l6dIa*)t)m#f{8w91mp z&MfU%U|=5vgbswJ1sYfgT0ke)frTQ+7D#~{dgzfV2vl950E@Ojdt;y$2z=^$vs_Y? zoKv%0KE9bZ@BiM+@YkcGDFV-5e(}l5Pt%0_9S7kP>mj?h0eMI)QX-aQ$&OT!OR|J` z#EDd*rD!EqiivU5iB}S(gur8tQc0GQ0*^bXO1hMm2#vBh@Fkp)%4lg+A~JcMSjrl) zk~H}!LdX;N22UwtrRGRJz51j1Wt*!N*Qz^IHQlOb*j26?Rn=Wsp{A#L%Z8^iT4R*c zss|Kxo;q}i85Q*gr|dd&7j1`LUv@p0YyU>!dC6Di=uhgjYSO&ykIuhy{gQs+jY}7< zUY>p3SFY7O+pQW7EK3TuIeV4DAQQ^HCKRKTD|6RoFWRODc;q$LGkdm+pJZ>a`x`($ zfcQ~Tk|2h%C6ywUT#8x|EBZ^xiqV)Ar}#-s^!W#vm7oeu4#tb|CRvmqW|>lorjx|V zKdl|0%I~5_auz2jXnZ>Px?AbBTe$2R2qe-XZ^7Qu`@KtjmSkW@Ix`L zL#V&U)mjj3wFW_{Lq@bzN`)tg7+2jzNEc+&bPNueVwliM&0xj?BwnZ7WRKa#iwNVYVnOZbFj}^lu!2y7j78hRU(R`I;yS zm;yrtYtP(Q*%B`b*=YP8ZuLYFoG+Gb5R@;f^C(xX)+-B?p>O-WM=Mm%U`y0fF+l3F z0TDr&_ypS36JaUd>?1`HAF#Vu$XdS)%eQWU-Z!y$xd#p((0Br(Sg-YUpdQav@0 zn5)z%c4C2(tSs1leAw zd-NL#+Q9&M^_oL(2Jrt5jR?n(Z{I{{gmFP!AQ)j_U~`EFS@zR=s%Z98$xj(ITYvWs zMv;v|3$hUeSpa6Z1xhf8!WYN8{{Zl@^pJQs+k1xFcXJOVTtP@9vL!tN%9B1-A`PiQ zbU9q(B|?l4OI{-l`63yXJj@TgXq9*xWTh_$@c#Uw46DN9gEYuyJmlE>JFEo`3IbbC zWR_)Mk=eHw1}Jw5zPslDTqP20rVVmy{C#O}G#dN-e2YAkB(i=OrG6^S!WJD9S%Rd< z+8IA4($3L*RekzaVcD(FLd9UFTe#vbxl;wBRx8}5)!PNfUMSS=ddqHgN_+X`0=GSS zx@MT~8cUQH!WJ#)*xwx{dbwBwqF!)LVq z@(W-W&ja`ueD0IhOc~$nH-2CL;>Pb9pEr6F!L)$8u$bf%;8?vznXiPxgYp^&qNp)H zsoR#0`y%%f`XZwg4!4*e<_v`Rm6S zg>$Id?`15J?Yb-H)5-&<|tK*73wYTIUR=YC7MO`74BBc+U!sh zVGCjv>=pswRM!R1c;XK~ z24s6;zCAJDj5gnXkojl!@Pj++cTmLU#m8pz-gfqEJA1aJoDJN24ix1x*xyy7LUr9w z>3VQG27E-<@#fT{By`VVE9~M23CM6a?7Pep>W9)|YEBblV^8 z?Exlr99_>#L42@Gei&>8@UMX|1Q>AsHvkZY@Y9u##FQ>UppmhY_b+!daNrc*;2oDTR$G;_93(g9-odr#m8_+{6 zxNb8%ru`$~q^8$B+u<50pj;%-S3;WD`b0|DF;t8@qsY}$Wjd&o8HO7)CXs&*pc|1S zse7DAb5e`ExkHY%hTk1>vh}RDLkg|ocZW>1hTns{oyZ|*2kH5p=yzJfZ#VvZ36ggZ PY-GN~+5bF)B)t0{BPrqn diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_version.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_version.cpython-311.pyc deleted file mode 100755 index 132f9cb23edd11fbf4ec15ecfc6802fbb56dbe40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1836 zcmZ`(%}*Og6rcU_+FpZcT0=+zT~Sl&M)5WRrBxI)QmYgRA}(zz)rXD-&loRR@4B-K z6^KfXl!H~}zyS%Aw2}`I{YWpp<^7+eUW~MO1Q7O)5z>xg<-7$|XfcvxqA95mlMI zt043Q-dIYijF?I_nt*vaMSmoBHSojR^J`3E>gdT3u>?)sfDz2nnYJqd7v5M(N#N>d zxM{(q#+Rs&c`ir=In=(eUE+l41yW=5tChOLz-VB+%D8WPF2>=|>A-d?9>(Q({TNS< ze)uhnw-G}niK3DWflDQYsZ67?*fi3VzNSW60=!z^mJk}%S)wA-5&|^%A7C}FBm2`3s$&W?&lmLP~jCx zIm`oWLmH?|6{`NEY@lVZ#By2{2uoWCB@#-Dq0Gw#CDe#huaZz*WC00NW#Uqsl7JN? zo`J~)DO7#tRD7|gd3@WddNpR%2rqlqoVVmnTclpMR++nMIrgGeUkj?9J6*hb)$;9t zU8$4uU9!Y{D}bPvIH_4Dl`huT!U4=3>{mS=RAJloTrbx5>5E4xb!ZGMsj)+#qBAKH>4{SGJ1E=e<-|OKgu%F<&`0QJd{{eWY0msCdaC|qKnJZkdypM&4svlT7YeB`iLnd61NipS z7}q?y;s`y1@pmi4>3MXFsaFQGV!J_@#hAFR7mxt{8NRSWXmK9KVbR}Ew00CXPl6!= zv7O%pXuR}vWm!vhk$@!1WE*phxqEXRWAIhwT&}H(wx{MgK$~yO-<$8Mnl`rMcM){2 z!l15=?7ZDY(ETsOhZN^~o)Zw2^%7_W?TvL7CFThM;@fT z4#siV5jiiMlLEvv{=NW_izq$E$s2LTKjq>ch!4U46QHX|lGObGNt11qe`7mHUuo#w z#Ha)Tz7Eah7s7gU>iPubFSkDKq%)hJ?T}xWo|3L2=j9g&;7C9l4Q)>D=vzgoh9pM- mPS6tQ;`q*c?eXH?1#AC;)i9cOHm4ty+Q@>o7a=H7NdE!hv$`_? diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_videochat.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_videochat.cpython-311.pyc deleted file mode 100755 index ce3a02c429a4b762ccb2fa978d9244bd8747d1d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8156 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 U;RqIO7dLi2z}$x$sQ8%t7f1lpivR!s diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_webappdata.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_webappdata.cpython-311.pyc deleted file mode 100755 index e214f1ad9871f03e2aec8641122b820d077c91df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2443 zcmeHJO>7%Q6rT0(#!VtYK{!-Yb1AB!?6wq8wW=!8AAVAl91>JyA&tj7V|&y6V`lQ> zDndO}B1Mtl04hQ~rQ#0sOMotg`ANYM3{!EcHBzgNUv89J^7ds2561Lmai2xvQ}1 zQH2GM1(!TjV8Kh==UqVqe2uqfS@K9|1a!ng$>&Fr!&yg=UErS?R99%DfCX%B;#OygD=5p;OsJ9fO&- zrkmy_S~r>#fNLVDjlHAg5<-`9Xbk+t8Vl}-C;&Vyn27-hKHpO+mX2+^k>HjZ!n7jM zwcC-B_8M=~IF=V$1gi*$;TY6bt%jjx7$uH6U;sj0pGqK0XikHe3fcyGy$~xdf^-)D zV1@dg>RWheEgF*jnC0o_5Ekh%E;z&KvQya8$8b+zhbkqUmIl>=sIgqpUQsFviQ?-D z^x#IiaOmunbsEGzmrlC7cHg04-_b+>KzuP$_&guZu`<+v^g=6xYFT)d3#r4*7-x=y zUp{S}&TO-ydtld;>XQy+lGBn(v>Fax0@k$J!WTKFYud9k!zgZ32CR8HFfODYM2Lao zZBGd*`stdKKOlGHwf4N@ai3Wu)dAf2Zzls4S$H^hbVLHdJ5KAvQJk;xemkOqT}-Ld zxCyY)!q zbZL=Em2?E>H+Z9*lqB~%<5?*`FqNdmju5Gx&;h&oXulwe7gCdQo`RI&;RBp5iaX)V)r-T-y2DXp^k&q_raMi)q;U#!+~^W`{RU?({h@ z$OY*Byor7>r*2obsy~_aAI`N`zRleee0rZ>~iK5U5^HO)>)15QX%BP6>fL7pT;*YBaFN(hTw zPy-jzhpPg_A{0EK<0UjJssG8;kSdq^J|PW5JP9VLQ{i=SRL`pB-7#%gfeujRpS?o8 zZ0;f5y@H-NdGqbv_uk(_X8DR@C|Pj9WPb*-e+xpVWb$;bw8)C`d}+a2E;Al9!uu#YKtq0Hp3g|VATSIy z7jhlCy`o_ld(R`|9b!x9tOWF+>>@ej6j|cIqkqOI3u=Qf;K|!aJjkAW)gO}t_poQHyQ^Q-t9tMKey{8G zcM}s81nsx4zumZ}BlL$FWUZJAXGP04vT?-iPbST49luhcAQ zD2MJMyZ8XvC001eBXkN+(wb$vyozf2?%lPnBd{0PJ(poC@FjJ8fvJy!_6D;gmR%|_ zXCY^T`4TjEjk#={QxAX2+PD#hc+u|!#-GY=O^fuEP&$E6U63cUr7N*5rCnNGS$^NK zq?N`Ize?%gYypJN0Utw64KU_xt(muT&4Qh`3rCt=WJN$yV&&_j-JQY#>S%WP!DLfE zK-*e#OreS@5F3Q1BBQSZ=n94wBTZqAkUFr0dsM}YX*=jiK-kKV&2^;=Mcp*5fHOm; zz>R>fo9#dfbBncU7>fB8F)Fc(1gOA42Z#e+Etd-5j4NurkaF4vmK`5U#=UqI`>aP@ zNA4JSZ7WDQf6n&UIK(U*n{j62c-t-PC^yXExK5?y^;VC&t=LCMuG^y&9@RnhJiO37b>N;&Fp#|zdd8jB)SG)zhD)dhqD2)NI^_Nqh2(OmLx`)gWaZK$r@Mve_7KUupgpuPk~>PHe8z1L9TzhB;`_2+sDlV9L2j9k!J=9*DvDmn zc%&1eQcg$=EgB<^P1M;DQJHi&W4o+Yhzf$aopbE4io^$*5TRTHUHi{g%x>T@)1%x9 z%%xyGm^IY#9_4_>`- zbn~$iCkOiYm*ZcIKb$&y==bEcTaP>cmBaS9gZY<`ygw!;C1yn-i^k0W8;aehmguN$!MDIbtYLHA{#= zGAa2-aFy%mm2A==J?Xf@fW1s41Sn`vP~t#geWuSPY|iu7V5mqC+t3a3nx+lkMB1{} pM;{K*RR8ilK(qbJ_pj)!{^fgE!Wyvh-|nj$f2rBOpQDN+`xi7dMM?kw diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_webhookinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_webhookinfo.cpython-311.pyc deleted file mode 100755 index f2ef2df4087112cc25963e3095c804bf16a2b631..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7570 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 VL;yhST)tiSjQ4!LOF!4ezX2`mVuSzy diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_writeaccessallowed.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_writeaccessallowed.cpython-311.pyc deleted file mode 100755 index 5c1f77fb2c77b197ecd95cef587917dc1f16d7ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3504 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⪼PW(|X%B>C?vutIT! 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 R-DIOo;~b}PcJify{x9deP!|9I diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/helpers.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/helpers.cpython-311.pyc deleted file mode 100755 index fe0fdc2e733847d3bdb8237731359245e11d9b07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7932 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 -# -# 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 Birthday.""" -import datetime as dtm -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class Birthdate(TelegramObject): - """ - This object describes the birthdate of a user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`day`, and :attr:`month` are equal. - - .. versionadded:: 21.1 - - Args: - day (:obj:`int`): Day of the user's birth; 1-31. - month (:obj:`int`): Month of the user's birth; 1-12. - year (:obj:`int`, optional): Year of the user's birth. - - Attributes: - day (:obj:`int`): Day of the user's birth; 1-31. - month (:obj:`int`): Month of the user's birth; 1-12. - year (:obj:`int`): Optional. Year of the user's birth. - - """ - - __slots__ = ("day", "month", "year") - - def __init__( - self, - day: int, - month: int, - year: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.day: int = day - self.month: int = month - # Optional - self.year: Optional[int] = year - - self._id_attrs = ( - self.day, - self.month, - ) - - self._freeze() - - def to_date(self, year: Optional[int] = None) -> dtm.date: - """Return the birthdate as a date object. - - .. versionchanged:: 21.2 - Now returns a :obj:`datetime.date` object instead of a :obj:`datetime.datetime` object, - as was originally intended. - - Args: - year (:obj:`int`, optional): The year to use. Required, if the :attr:`year` was not - present. - - Returns: - :obj:`datetime.date`: The birthdate as a date object. - """ - if self.year is None and year is None: - raise ValueError( - "The `year` argument is required if the `year` attribute was not present." - ) - - return dtm.date(year or self.year, self.month, self.day) # type: ignore[arg-type] diff --git a/venv/lib/python3.11/site-packages/telegram/_bot.py b/venv/lib/python3.11/site-packages/telegram/_bot.py deleted file mode 100755 index 1d684a7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_bot.py +++ /dev/null @@ -1,10224 +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.""" - -import asyncio -import contextlib -import copy -import datetime as dtm -import pickle -from collections.abc import Sequence -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Callable, - NoReturn, - Optional, - TypeVar, - Union, - cast, - no_type_check, -) - -try: - from cryptography.hazmat.backends import default_backend - from cryptography.hazmat.primitives import serialization - - CRYPTO_INSTALLED = True -except ImportError: - default_backend = None # type: ignore[assignment] - serialization = None # type: ignore[assignment] - CRYPTO_INSTALLED = False - -from telegram._botcommand import BotCommand -from telegram._botcommandscope import BotCommandScope -from telegram._botdescription import BotDescription, BotShortDescription -from telegram._botname import BotName -from telegram._business import BusinessConnection -from telegram._chatadministratorrights import ChatAdministratorRights -from telegram._chatboost import UserChatBoosts -from telegram._chatfullinfo import ChatFullInfo -from telegram._chatinvitelink import ChatInviteLink -from telegram._chatmember import ChatMember -from telegram._chatpermissions import ChatPermissions -from telegram._files.animation import Animation -from telegram._files.audio import Audio -from telegram._files.chatphoto import ChatPhoto -from telegram._files.contact import Contact -from telegram._files.document import Document -from telegram._files.file import File -from telegram._files.inputmedia import InputMedia, InputPaidMedia -from telegram._files.location import Location -from telegram._files.photosize import PhotoSize -from telegram._files.sticker import MaskPosition, Sticker, StickerSet -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._forumtopic import ForumTopic -from telegram._games.gamehighscore import GameHighScore -from telegram._gifts import Gift, Gifts -from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton -from telegram._inline.preparedinlinemessage import PreparedInlineMessage -from telegram._menubutton import MenuButton -from telegram._message import Message -from telegram._messageid import MessageId -from telegram._payment.stars.startransactions import StarTransactions -from telegram._poll import InputPollOption, Poll -from telegram._reaction import ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji -from telegram._reply import ReplyParameters -from telegram._sentwebappmessage import SentWebAppMessage -from telegram._telegramobject import TelegramObject -from telegram._update import Update -from telegram._user import User -from telegram._userprofilephotos import UserProfilePhotos -from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue -from telegram._utils.files import is_local_file, parse_file_input -from telegram._utils.logging import get_logger -from telegram._utils.repr import build_repr_with_selected_attrs -from telegram._utils.strings import to_camel_case -from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup -from telegram._utils.warnings import warn -from telegram._webhookinfo import WebhookInfo -from telegram.constants import InlineQueryLimit, ReactionEmoji -from telegram.error import EndPointNotFound, InvalidToken -from telegram.request import BaseRequest, RequestData -from telegram.request._httpxrequest import HTTPXRequest -from telegram.request._requestparameter import RequestParameter -from telegram.warnings import PTBDeprecationWarning, PTBUserWarning - -if TYPE_CHECKING: - from telegram import ( - InlineKeyboardMarkup, - InlineQueryResult, - InputFile, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - InputSticker, - LabeledPrice, - LinkPreviewOptions, - MessageEntity, - PassportElementError, - ShippingOption, - ) - -BT = TypeVar("BT", bound="Bot") - - -class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]): - """This object represents a Telegram Bot. - - Instances of this class can be used as asyncio context managers, where - - .. code:: python - - async with bot: - # code - - is roughly equivalent to - - .. code:: python - - try: - await bot.initialize() - # code - finally: - await bot.shutdown() - - .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. - - Note: - * Most bot methods have the argument ``api_kwargs`` which allows passing arbitrary keywords - to the Telegram API. This can be used to access new features of the API before they are - incorporated into PTB. The limitations to this argument are the same as the ones - described in :meth:`do_api_request`. - * Bots should not be serialized since if you for e.g. change the bots token, then your - serialized instance will not reflect that change. Trying to pickle a bot instance will - raise :exc:`pickle.PicklingError`. Trying to deepcopy a bot instance will raise - :exc:`TypeError`. - - Examples: - :any:`Raw API Bot ` - - .. seealso:: :wiki:`Your First Bot `, - :wiki:`Builder Pattern ` - - .. versionadded:: 13.2 - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`bot` is equal. - - .. versionchanged:: 20.0 - - * Removed the deprecated methods ``kick_chat_member``, ``kickChatMember``, - ``get_chat_members_count`` and ``getChatMembersCount``. - * Removed the deprecated property ``commands``. - * Removed the deprecated ``defaults`` parameter. If you want to use - :class:`telegram.ext.Defaults`, please use the subclass :class:`telegram.ext.ExtBot` - instead. - * Attempting to pickle a bot instance will now raise :exc:`pickle.PicklingError`. - * Attempting to deepcopy a bot instance will now raise :exc:`TypeError`. - * 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. - * For uploading files, file paths are now always accepted. If :paramref:`local_mode` is - :obj:`False`, the file contents will be read in binary mode and uploaded. Otherwise, - the file path will be passed in the - `file URI scheme `_. - - .. versionchanged:: 20.5 - Removed deprecated methods ``set_sticker_set_thumb`` and ``setStickerSetThumb``. - Use :meth:`set_sticker_set_thumbnail` and :meth:`setStickerSetThumbnail` instead. - - Args: - token (:obj:`str`): Bot's unique authentication token. - base_url (:obj:`str`, optional): Telegram Bot API service URL. - base_file_url (:obj:`str`, optional): Telegram Bot API file URL. - request (:class:`telegram.request.BaseRequest`, optional): Pre initialized - :class:`telegram.request.BaseRequest` instances. Will be used for all bot methods - *except* for :meth:`get_updates`. If not passed, an instance of - :class:`telegram.request.HTTPXRequest` will be used. - get_updates_request (:class:`telegram.request.BaseRequest`, optional): Pre initialized - :class:`telegram.request.BaseRequest` instances. Will be used exclusively for - :meth:`get_updates`. If not passed, an instance of - :class:`telegram.request.HTTPXRequest` will be used. - private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data. - private_key_password (:obj:`bytes`, optional): Password for above private key. - local_mode (:obj:`bool`, optional): Set to :obj:`True`, if the :paramref:`base_url` is - the URI of a `Local Bot API Server `_ that runs with the ``--local`` flag. Currently, the only effect of - this is that files are uploaded using their local path in the - `file URI scheme `_. - Defaults to :obj:`False`. - - .. versionadded:: 20.0. - - .. include:: inclusions/bot_methods.rst - - .. |removed_thumb_arg| replace:: Removed deprecated argument ``thumb``. Use - ``thumbnail`` instead. - - """ - - # This is a class variable since we want to override the logger name in ExtBot - # without having to change all places where this is used - _LOGGER = get_logger(__name__) - - __slots__ = ( - "_base_file_url", - "_base_url", - "_bot_user", - "_initialized", - "_local_mode", - "_private_key", - "_request", - "_token", - ) - - 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, - local_mode: bool = False, - ): - super().__init__(api_kwargs=None) - if not token: - raise InvalidToken("You must pass the token you received from https://t.me/Botfather!") - self._token: str = token - - self._base_url: str = base_url + self._token - self._base_file_url: str = base_file_url + self._token - self._local_mode: bool = local_mode - self._bot_user: Optional[User] = None - self._private_key: Optional[bytes] = None - self._initialized: bool = False - - self._request: tuple[BaseRequest, BaseRequest] = ( - HTTPXRequest() if get_updates_request is None else get_updates_request, - HTTPXRequest() if request is None else request, - ) - - # this section is about issuing a warning when using HTTP/2 and connect to a self hosted - # bot api instance, which currently only supports HTTP/1.1. Checking if a custom base url - # is set is the best way to do that. - - warning_string = "" - - if ( - isinstance(self._request[0], HTTPXRequest) - and self._request[0].http_version == "2" - and not base_url.startswith("https://api.telegram.org/bot") - ): - warning_string = "get_updates_request" - - if ( - isinstance(self._request[1], HTTPXRequest) - and self._request[1].http_version == "2" - and not base_url.startswith("https://api.telegram.org/bot") - ): - if warning_string: - warning_string += " and request" - else: - warning_string = "request" - - if warning_string: - self._warn( - f"You set the HTTP version for the {warning_string} HTTPXRequest instance to " - "HTTP/2. The self hosted bot api instances only support HTTP/1.1. You should " - "either run a HTTP proxy in front of it which supports HTTP/2 or use HTTP/1.1.", - PTBUserWarning, - stacklevel=2, - ) - - if private_key: - if not CRYPTO_INSTALLED: - raise RuntimeError( - "To use Telegram Passports, PTB must be installed via `pip install " - '"python-telegram-bot[passport]"`.' - ) - self._private_key = serialization.load_pem_private_key( - private_key, password=private_key_password, backend=default_backend() - ) - - self._freeze() - - async def __aenter__(self: BT) -> BT: - """ - |async_context_manager| :meth:`initializes ` the Bot. - - Returns: - The initialized Bot 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 Bot.""" - # 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 __reduce__(self) -> NoReturn: - """Customizes how :func:`copy.deepcopy` processes objects of this type. Bots can not - be pickled and this method will always raise an exception. - - .. versionadded:: 20.0 - - Raises: - :exc:`pickle.PicklingError` - """ - raise pickle.PicklingError("Bot objects cannot be pickled!") - - def __deepcopy__(self, memodict: dict[int, object]) -> NoReturn: - """Customizes how :func:`copy.deepcopy` processes objects of this type. Bots can not - be deepcopied and this method will always raise an exception. - - .. versionadded:: 20.0 - - Raises: - :exc:`TypeError` - """ - raise TypeError("Bot objects cannot be deepcopied!") - - def __eq__(self, other: object) -> bool: - """Defines equality condition for the :class:`telegram.Bot` object. - Two objects of this class are considered to be equal if their attributes - :attr:`bot` are equal. - - Returns: - :obj:`True` if both attributes :attr:`bot` are equal. :obj:`False` otherwise. - """ - if isinstance(other, Bot): - return self.bot == other.bot - return super().__eq__(other) - - def __hash__(self) -> int: - """See :meth:`telegram.TelegramObject.__hash__`""" - if self._bot_user is None: - return super().__hash__() - return hash((self.bot, Bot)) - - def __repr__(self) -> str: - """Give a string representation of the bot in the form ``Bot[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) - - @property - def token(self) -> str: - """:obj:`str`: Bot's unique authentication token. - - .. versionadded:: 20.0 - """ - return self._token - - @property - def base_url(self) -> str: - """:obj:`str`: Telegram Bot API service URL, built from :paramref:`Bot.base_url` and - :paramref:`Bot.token`. - - .. versionadded:: 20.0 - """ - return self._base_url - - @property - def base_file_url(self) -> str: - """:obj:`str`: Telegram Bot API file URL, built from :paramref:`Bot.base_file_url` and - :paramref:`Bot.token`. - - .. versionadded:: 20.0 - """ - return self._base_file_url - - @property - def local_mode(self) -> bool: - """:obj:`bool`: Whether this bot is running in local mode. - - .. versionadded:: 20.0 - """ - return self._local_mode - - # Proper type hints are difficult because: - # 1. cryptography doesn't have a nice base class, so it would get lengthy - # 2. we can't import cryptography if it's not installed - @property - def private_key(self) -> Optional[Any]: - """Deserialized private key for decryption of telegram passport data. - - .. versionadded:: 20.0 - """ - return self._private_key - - @property - def request(self) -> BaseRequest: - """The :class:`~telegram.request.BaseRequest` object used by this bot. - - Warning: - Requests to the Bot API are made by the various methods of this class. This attribute - should *not* be used manually. - """ - return self._request[1] - - @property - def bot(self) -> User: - """:class:`telegram.User`: User instance for the bot as returned by :meth:`get_me`. - - Warning: - This value is the cached return value of :meth:`get_me`. If the bots profile is - changed during runtime, this value won't reflect the changes until :meth:`get_me` is - called again. - - .. seealso:: :meth:`initialize` - """ - if self._bot_user is None: - raise RuntimeError( - f"{self.__class__.__name__} is not properly initialized. Call " - f"`{self.__class__.__name__}.initialize` before accessing this property." - ) - return self._bot_user - - @property - def id(self) -> int: - """:obj:`int`: Unique identifier for this bot. Shortcut for the corresponding attribute of - :attr:`bot`. - """ - return self.bot.id - - @property - def first_name(self) -> str: - """:obj:`str`: Bot's first name. Shortcut for the corresponding attribute of - :attr:`bot`. - """ - return self.bot.first_name - - @property - def last_name(self) -> str: - """:obj:`str`: Optional. Bot's last name. Shortcut for the corresponding attribute of - :attr:`bot`. - """ - return self.bot.last_name # type: ignore - - @property - def username(self) -> str: - """:obj:`str`: Bot's username. Shortcut for the corresponding attribute of - :attr:`bot`. - """ - return self.bot.username # type: ignore - - @property - def link(self) -> str: - """:obj:`str`: Convenience property. Returns the t.me link of the bot.""" - return f"https://t.me/{self.username}" - - @property - def can_join_groups(self) -> bool: - """:obj:`bool`: Bot's :attr:`telegram.User.can_join_groups` attribute. Shortcut for the - corresponding attribute of :attr:`bot`. - """ - return self.bot.can_join_groups # type: ignore - - @property - def can_read_all_group_messages(self) -> bool: - """:obj:`bool`: Bot's :attr:`telegram.User.can_read_all_group_messages` attribute. - Shortcut for the corresponding attribute of :attr:`bot`. - """ - return self.bot.can_read_all_group_messages # type: ignore - - @property - def supports_inline_queries(self) -> bool: - """:obj:`bool`: Bot's :attr:`telegram.User.supports_inline_queries` attribute. - Shortcut for the corresponding attribute of :attr:`bot`. - """ - return self.bot.supports_inline_queries # type: ignore - - @property - def name(self) -> str: - """:obj:`str`: Bot's @username. Shortcut for the corresponding attribute of :attr:`bot`.""" - return f"@{self.username}" - - @classmethod - def _warn( - cls, - message: Union[str, PTBUserWarning], - category: type[Warning] = PTBUserWarning, - stacklevel: int = 0, - ) -> None: - """Convenience method to issue a warning. This method is here mostly to make it easier - for ExtBot to add 1 level to all warning calls. - """ - warn(message=message, category=category, stacklevel=stacklevel + 1) - - def _parse_file_input( - self, - file_input: Union[FileInput, "TelegramObject"], - tg_type: Optional[type["TelegramObject"]] = None, - filename: Optional[str] = None, - attach: bool = False, - ) -> Union[str, "InputFile", Any]: - return parse_file_input( - file_input=file_input, - tg_type=tg_type, - filename=filename, - attach=attach, - local_mode=self._local_mode, - ) - - def _insert_defaults(self, data: dict[str, object]) -> None: - """This method is here to make ext.Defaults work. Because we need to be able to tell - e.g. `send_message(chat_id, text)` from `send_message(chat_id, text, parse_mode=None)`, the - default values for `parse_mode` etc are not `None` but `DEFAULT_NONE`. While this *could* - be done in ExtBot instead of Bot, shortcuts like `Message.reply_text` need to work for both - Bot and ExtBot, so they also have the `DEFAULT_NONE` default values. - - This makes it necessary to convert `DefaultValue(obj)` to `obj` at some point between - `Message.reply_text` and the request to TG. Doing this here in a centralized manner is a - rather clean and minimally invasive solution, i.e. the link between tg and tg.ext is as - small as possible. - See also _insert_defaults_for_ilq - ExtBot overrides this method to actually insert default values. - - If in the future we come up with a better way of making `Defaults` work, we can cut this - link as well. - """ - # We - # 1) set the correct parse_mode for all InputMedia objects - # 2) replace all DefaultValue instances with the corresponding normal value. - for key, val in data.items(): - # 1) - if isinstance(val, InputMedia): - # Copy object as not to edit it in-place - new = copy.copy(val) - with new._unfrozen(): - new.parse_mode = DefaultValue.get_value(new.parse_mode) - data[key] = new - elif ( - key == "media" - and isinstance(val, Sequence) - and not isinstance(val[0], InputPaidMedia) - ): - # Copy objects as not to edit them in-place - copy_list = [copy.copy(media) for media in val] - for media in copy_list: - with media._unfrozen(): - media.parse_mode = DefaultValue.get_value(media.parse_mode) - data[key] = copy_list - # 2) - else: - data[key] = DefaultValue.get_value(val) - - async def _post( - self, - endpoint: str, - data: Optional[JSONDict] = 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 know that the return type is Union[bool, JSONDict, list[JSONDict]], but it's hard - # to tell mypy which methods expects which of these return values and `Any` saves us a - # lot of `type: ignore` comments - if data is None: - data = {} - - if api_kwargs: - data.update(api_kwargs) - - # Insert is in-place, so no return value for data - self._insert_defaults(data) - - # Drop any None values because Telegram doesn't handle them well - data = {key: value for key, value in data.items() if value is not None} - - return await self._do_post( - endpoint=endpoint, - data=data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - - 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]]: - # This also converts datetimes into timestamps. - # We don't do this earlier so that _insert_defaults (see above) has a chance to convert - # to the default timezone in case this is called by ExtBot - request_data = RequestData( - parameters=[RequestParameter.from_input(key, value) for key, value in data.items()], - ) - - request = self._request[0] if endpoint == "getUpdates" else self._request[1] - - self._LOGGER.debug("Calling Bot API endpoint `%s` with parameters `%s`", endpoint, data) - result = await request.post( - url=f"{self._base_url}/{endpoint}", - request_data=request_data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - self._LOGGER.debug( - "Call to Bot API endpoint `%s` finished with return value `%s`", endpoint, result - ) - - return result - - 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, - *, - 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, - ) -> Any: - """Protected method to send or edit messages of any type. - - It is here to reduce repetition of if-else closes in the different bot methods, - i.e. this method takes care of adding its parameters to `data` if appropriate. - - Depending on the bot method, returns either `True` or the message. - However, it's hard to tell mypy which methods expects which of these return values and - using `Any` instead saves us a lot of `type: ignore` comments - """ - # We don't check if (DEFAULT_)None here, so that _post is able to insert the defaults - # correctly, if necessary: - if allow_sending_without_reply is not DEFAULT_NONE and reply_parameters is not None: - raise ValueError( - "`allow_sending_without_reply` and `reply_parameters` are mutually exclusive." - ) - - if reply_to_message_id is not None and reply_parameters is not None: - raise ValueError( - "`reply_to_message_id` and `reply_parameters` are mutually exclusive." - ) - - if reply_to_message_id is not None: - reply_parameters = ReplyParameters( - message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - ) - - data.update( - { - "allow_paid_broadcast": allow_paid_broadcast, - "business_connection_id": business_connection_id, - "caption": caption, - "caption_entities": caption_entities, - "disable_notification": disable_notification, - "link_preview_options": link_preview_options, - "message_thread_id": message_thread_id, - "message_effect_id": message_effect_id, - "parse_mode": parse_mode, - "protect_content": protect_content, - "reply_markup": reply_markup, - "reply_parameters": reply_parameters, - } - ) - - result = await self._post( - endpoint, - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - if result is True: - return result - - return Message.de_json(result, self) - - async def initialize(self) -> None: - """Initialize resources used by this class. Currently calls :meth:`get_me` to - cache :attr:`bot` and calls :meth:`telegram.request.BaseRequest.initialize` for - the request objects used by this bot. - - .. seealso:: :meth:`shutdown` - - .. versionadded:: 20.0 - """ - if self._initialized: - self._LOGGER.debug("This Bot is already initialized.") - return - - await asyncio.gather(self._request[0].initialize(), self._request[1].initialize()) - # Since the bot is to be initialized only once, we can also use it for - # verifying the token passed and raising an exception if it's invalid. - try: - await self.get_me() - except InvalidToken as exc: - raise InvalidToken(f"The token `{self._token}` was rejected by the server.") from exc - self._initialized = True - - async def shutdown(self) -> None: - """Stop & clear resources used by this class. Currently just calls - :meth:`telegram.request.BaseRequest.shutdown` for the request objects used by this bot. - - .. seealso:: :meth:`initialize` - - .. versionadded:: 20.0 - """ - if not self._initialized: - self._LOGGER.debug("This Bot is already shut down. Returning.") - return - - await asyncio.gather(self._request[0].shutdown(), self._request[1].shutdown()) - self._initialized = False - - 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, - ) -> Any: - """Do a request to the Telegram API. - - This method is here to make it easier to use new API methods that are not yet supported - by this library. - - Hint: - Since PTB does not know which arguments are passed to this method, some caution is - necessary in terms of PTBs utility functionalities. In particular - - * passing objects of any class defined in the :mod:`telegram` module is supported - * when uploading files, a :class:`telegram.InputFile` must be passed as the value for - the corresponding argument. Passing a file path or file-like object will not work. - File paths will work only in combination with :paramref:`~Bot.local_mode`. - * when uploading files, PTB can still correctly determine that - a special write timeout value should be used instead of the default - :paramref:`telegram.request.HTTPXRequest.write_timeout`. - * insertion of default values specified via :class:`telegram.ext.Defaults` will not - work (only relevant for :class:`telegram.ext.ExtBot`). - * The only exception is :class:`telegram.ext.Defaults.tzinfo`, which will be correctly - applied to :class:`datetime.datetime` objects. - - .. versionadded:: 20.8 - - Args: - endpoint (:obj:`str`): The API endpoint to use, e.g. ``getMe`` or ``get_me``. - api_kwargs (:obj:`dict`, optional): The keyword arguments to pass to the API call. - If not specified, no arguments are passed. - return_type (:class:`telegram.TelegramObject`, optional): If specified, the result of - the API call will be deserialized into an instance of this class or tuple of - instances of this class. If not specified, the raw result of the API call will be - returned. - - Returns: - The result of the API call. If :paramref:`return_type` is not specified, this is a - :obj:`dict` or :obj:`bool`, otherwise an instance of :paramref:`return_type` or a - tuple of :paramref:`return_type`. - - Raises: - :class:`telegram.error.TelegramError` - """ - if hasattr(self, endpoint): - self._warn( - ( - f"Please use 'Bot.{endpoint}' instead of " - f"'Bot.do_api_request(\"{endpoint}\", ...)'" - ), - stacklevel=2, - ) - - camel_case_endpoint = to_camel_case(endpoint) - try: - result = await self._post( - camel_case_endpoint, - api_kwargs=api_kwargs, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - except InvalidToken as exc: - # 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, that's why we have special handling for - # that here rather than in BaseRequest._request_wrapper - if self._initialized: - raise EndPointNotFound( - f"Endpoint '{camel_case_endpoint}' not found in Bot API" - ) from exc - - raise InvalidToken( - "Either the bot token was rejected by Telegram or the endpoint " - f"'{camel_case_endpoint}' does not exist." - ) from exc - - if return_type is None or isinstance(result, bool): - return result - - if isinstance(result, list): - return return_type.de_list(result, self) - return return_type.de_json(result, self) - - 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, - ) -> User: - """A simple method for testing your bot's auth token. Requires no parameters. - - Returns: - :class:`telegram.User`: A :class:`telegram.User` instance representing that bot if the - credentials are valid, :obj:`None` otherwise. - - Raises: - :class:`telegram.error.TelegramError` - - """ - result = await self._post( - "getMe", - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - self._bot_user = User.de_json(result, self) - return self._bot_user # type: ignore[return-value] - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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, - ) -> Message: - """Use this method to send text messages. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - text (:obj:`str`): Text of the message to be sent. Max - :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`): |parse_mode| - entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of special - entities that appear in message text, which can be specified instead of - :paramref:`parse_mode`. - - .. versionchanged:: 20.0 - |sequenceargs| - link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation - options for the message. Mutually exclusive with - :paramref:`disable_web_page_preview`. - - .. versionadded:: 20.8 - - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in - this message. Convenience parameter for setting :paramref:`link_preview_options`. - Mutually exclusive with :paramref:`link_preview_options`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`link_preview_options` replacing this - argument. PTB will automatically convert this argument to that one, but - for advanced options, please use :paramref:`link_preview_options` directly. - - .. versionchanged:: 21.0 - |keyword_only_arg| - - Returns: - :class:`telegram.Message`: On success, the sent message is returned. - - Raises: - :exc:`ValueError`: If both :paramref:`disable_web_page_preview` and - :paramref:`link_preview_options` are passed. - :class:`telegram.error.TelegramError`: For other errors. - - """ - data: JSONDict = {"chat_id": chat_id, "text": text, "entities": entities} - link_preview_options = parse_lpo_and_dwpp(disable_web_page_preview, link_preview_options) - - return await self._send_message( - "sendMessage", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, - message_thread_id=message_thread_id, - business_connection_id=business_connection_id, - parse_mode=parse_mode, - link_preview_options=link_preview_options, - reply_parameters=reply_parameters, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to delete a message, including service messages, with the following - limitations: - - - A message can only be deleted if it was sent less than 48 hours ago. - - Service messages about a supergroup, channel, or forum topic creation can't be deleted. - - A dice message in a private chat can only be deleted if it was sent more than 24 - hours ago. - - Bots can delete outgoing messages in private chats, groups, and supergroups. - - Bots can delete incoming messages in private chats. - - Bots granted :attr:`~telegram.ChatMemberAdministrator.can_post_messages` permissions - can delete outgoing messages in channels. - - If the bot is an administrator of a group, it can delete any message there. - - If the bot has :attr:`~telegram.ChatMemberAdministrator.can_delete_messages` - permission in a supergroup or a channel, it can delete any message there. - - .. - The method CallbackQuery.delete_message() will not be found when automatically - generating "Shortcuts" admonitions for Bot methods because it has no calls - to Bot methods in its return statement(s). So it is manually included in "See also". - - .. seealso:: - :meth:`telegram.CallbackQuery.delete_message` (calls :meth:`delete_message` - indirectly, via :meth:`telegram.Message.delete`) - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - message_id (:obj:`int`): Identifier of the message to delete. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "message_id": message_id} - return await self._post( - "deleteMessage", - data, - 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, - chat_id: Union[int, str], - 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: - """ - Use this method to delete multiple messages simultaneously. If some of the specified - messages can't be found, they are skipped. - - .. versionadded:: 20.8 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - message_ids (Sequence[:obj:`int`]): A list of - :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT`- - :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages - to delete. See :meth:`delete_message` for limitations on which messages can be - deleted. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = {"chat_id": chat_id, "message_ids": message_ids} - return await self._post( - "deleteMessages", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> Message: - """ - Use this method to forward messages of any kind. Service messages can't be forwarded. - - Note: - Since the release of Bot API 5.5 it can be impossible to forward messages from - some chats. Use the attributes :attr:`telegram.Message.has_protected_content` and - :attr:`telegram.ChatFullInfo.has_protected_content` to check this. - - As a workaround, it is still possible to use :meth:`copy_message`. However, this - behaviour is undocumented and might be changed by Telegram. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the - original message was sent (or channel username in the format ``@channelusername``). - message_id (:obj:`int`): Message identifier in the chat specified in - :paramref:`from_chat_id`. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "chat_id": chat_id, - "from_chat_id": from_chat_id, - "message_id": message_id, - } - - return await self._send_message( - "forwardMessage", - data, - 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( - 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, - ) -> tuple[MessageId, ...]: - """ - Use this method to forward messages of any kind. If some of the specified messages can't be - found or forwarded, they are skipped. Service messages and messages with protected content - can't be forwarded. Album grouping is kept for forwarded messages. - - .. versionadded:: 20.8 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the - original message was sent (or channel username in the format ``@channelusername``). - message_ids (Sequence[:obj:`int`]): A list of - :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT`- - :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages - in the chat :paramref:`from_chat_id` to forward. The identifiers must be specified - in a strictly increasing order. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - Returns: - tuple[:class:`telegram.Message`]: On success, a tuple of ``MessageId`` of sent messages - is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "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, - } - - result = await self._post( - "forwardMessages", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return MessageId.de_list(result, self) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """Use this method to send photos. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - photo (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \ - | :class:`pathlib.Path` | :class:`telegram.PhotoSize`): Photo to send. - |fileinput| - Lastly you can pass an existing :class:`telegram.PhotoSize` object to send. - - Caution: - * The photo must be at most 10MB in size. - * The photo's width and height must not exceed 10000 in total. - * Width and height ratio must be at most 20. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - .. versionchanged:: 20.0 - File paths as input is also accepted for bots *not* running in - :paramref:`~telegram.Bot.local_mode`. - caption (:obj:`str`, optional): Photo caption (may also be used when resending photos - by file_id), 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` - characters after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - - .. versionchanged:: 20.0 - |sequenceargs| - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - has_spoiler (:obj:`bool`, optional): Pass :obj:`True` if the photo needs to be covered - with a spoiler animation. - - .. versionadded:: 20.0 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - filename (:obj:`str`, optional): Custom file name for the photo, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "photo": self._parse_file_input(photo, PhotoSize, filename=filename), - "has_spoiler": has_spoiler, - "show_caption_above_media": show_caption_above_media, - } - - return await self._send_message( - "sendPhoto", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=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, - 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, - ) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """ - Use this method to send audio files, if you want Telegram clients to display them in the - music player. Your audio must be in the ``.mp3`` or ``.m4a`` format. - - Bots can currently send audio files of up to - :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, this limit may be - changed in the future. - - For sending voice messages, use the :meth:`send_voice` method instead. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_arg| - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - audio (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \ - :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.Audio`): Audio file to - send. |fileinput| - Lastly you can pass an existing :class:`telegram.Audio` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - .. versionchanged:: 20.0 - File paths as input is also accepted for bots *not* running in - :paramref:`~telegram.Bot.local_mode`. - caption (:obj:`str`, optional): Audio caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - - .. versionchanged:: 20.0 - |sequenceargs| - duration (:obj:`int`, optional): Duration of sent audio in seconds. - performer (:obj:`str`, optional): Performer. - title (:obj:`str`, optional): Track name. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstring| - - .. versionadded:: 20.2 - reply_parameters (:obj:`ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - filename (:obj:`str`, optional): Custom file name for the audio, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "audio": self._parse_file_input(audio, Audio, filename=filename), - "duration": duration, - "performer": performer, - "title": title, - "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None, - } - - return await self._send_message( - "sendAudio", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=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, - 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, - ) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """ - Use this method to send general files. - - Bots can currently send files of any type of up to - :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, this limit may be - changed in the future. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_arg| - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - document (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \ - :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.Document`): File to send. - |fileinput| - Lastly you can pass an existing :class:`telegram.Document` object to send. - - Note: - Sending by URL will currently only work ``GIF``, ``PDF`` & ``ZIP`` files. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - .. versionchanged:: 20.0 - File paths as input is also accepted for bots *not* running in - :paramref:`~telegram.Bot.local_mode`. - caption (:obj:`str`, optional): Document caption (may also be used when resending - documents by file_id), 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` - characters after entities parsing. - disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side - content type detection for files uploaded using multipart/form-data. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - - .. versionchanged:: 20.0 - |sequenceargs| - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstring| - - .. versionadded:: 20.2 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - filename (:obj:`str`, optional): Custom file name for the document, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "document": self._parse_file_input(document, Document, filename=filename), - "disable_content_type_detection": disable_content_type_detection, - "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None, - } - - return await self._send_message( - "sendDocument", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=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, - 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, - ) - - 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, - *, - 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, - ) -> Message: - """ - Use this method to send static ``.WEBP``, animated ``.TGS``, or video ``.WEBM`` stickers. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - sticker (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \ - :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.Sticker`): Sticker to send. - |fileinput| Video stickers can only be sent by a ``file_id``. Video and animated - stickers can't be sent via an HTTP URL. - - Lastly you can pass an existing :class:`telegram.Sticker` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - .. versionchanged:: 20.0 - File paths as input is also accepted for bots *not* running in - :paramref:`~telegram.Bot.local_mode`. - emoji (:obj:`str`, optional): Emoji associated with the sticker; only for just - uploaded stickers - - .. versionadded:: 20.2 - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "sticker": self._parse_file_input(sticker, Sticker), - "emoji": emoji, - } - return await self._send_message( - "sendSticker", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - business_connection_id=business_connection_id, - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """Use this method to send video files, Telegram clients support mp4 videos - (other formats may be sent as Document). - - Bots can currently send video files of up to - :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, this limit may be - changed in the future. - - Note: - :paramref:`thumbnail` will be ignored for small video files, for which Telegram can - easily generate thumbnails. However, this behaviour is undocumented and might be - changed by Telegram. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_arg| - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - video (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \ - | :class:`pathlib.Path` | :class:`telegram.Video`): Video file to send. - |fileinput| - Lastly you can pass an existing :class:`telegram.Video` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - .. versionchanged:: 20.0 - File paths as input is also accepted for bots *not* running in - :paramref:`~telegram.Bot.local_mode`. - duration (:obj:`int`, optional): Duration of sent video in seconds. - width (:obj:`int`, optional): Video width. - height (:obj:`int`, optional): Video height. - caption (:obj:`str`, optional): Video caption (may also be used when resending videos - by file_id), 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` - characters after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - - .. versionchanged:: 20.0 - |sequenceargs| - supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is - suitable for streaming. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - has_spoiler (:obj:`bool`, optional): Pass :obj:`True` if the video needs to be covered - with a spoiler animation. - - .. versionadded:: 20.0 - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstring| - - .. versionadded:: 20.2 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - filename (:obj:`str`, optional): Custom file name for the video, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "video": self._parse_file_input(video, Video, filename=filename), - "duration": duration, - "width": width, - "height": height, - "supports_streaming": supports_streaming, - "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None, - "has_spoiler": has_spoiler, - "show_caption_above_media": show_caption_above_media, - } - - return await self._send_message( - "sendVideo", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=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, - 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, - ) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """ - As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. - Use this method to send video messages. - - Note: - :paramref:`thumbnail` will be ignored for small video files, for which Telegram can - easily generate thumbnails. However, this behaviour is undocumented and might be - changed by Telegram. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_arg| - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - video_note (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \ - :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.VideoNote`): Video note - to send. - Pass a file_id as String to send a video note that exists on the Telegram - servers (recommended) or upload a new video using multipart/form-data. - |uploadinput| - Lastly you can pass an existing :class:`telegram.VideoNote` object to send. - Sending video notes by a URL is currently unsupported. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - .. versionchanged:: 20.0 - File paths as input is also accepted for bots *not* running in - :paramref:`~telegram.Bot.local_mode`. - duration (:obj:`int`, optional): Duration of sent video in seconds. - length (:obj:`int`, optional): Video width and height, i.e. diameter of the video - message. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstring| - - .. versionadded:: 20.2 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - filename (:obj:`str`, optional): Custom file name for the video note, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "video_note": self._parse_file_input(video_note, VideoNote, filename=filename), - "duration": duration, - "length": length, - "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None, - } - - return await self._send_message( - "sendVideoNote", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """ - Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). - Bots can currently send animation files of up to - :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, this limit may be - changed in the future. - - Note: - :paramref:`thumbnail` will be ignored for small files, for which Telegram can easily - generate thumbnails. However, this behaviour is undocumented and might be changed - by Telegram. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_arg| - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - animation (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \ - :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.Animation`): Animation to - send. |fileinput| - Lastly you can pass an existing :class:`telegram.Animation` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - duration (:obj:`int`, optional): Duration of sent animation in seconds. - width (:obj:`int`, optional): Animation width. - height (:obj:`int`, optional): Animation height. - caption (:obj:`str`, optional): Animation caption (may also be used when resending - animations by file_id), - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - - .. versionchanged:: 20.0 - |sequenceargs| - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - has_spoiler (:obj:`bool`, optional): Pass :obj:`True` if the animation needs to be - covered with a spoiler animation. - - .. versionadded:: 20.0 - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstring| - - .. versionadded:: 20.2 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - filename (:obj:`str`, optional): Custom file name for the animation, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "animation": self._parse_file_input(animation, Animation, filename=filename), - "duration": duration, - "width": width, - "height": height, - "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None, - "has_spoiler": has_spoiler, - "show_caption_above_media": show_caption_above_media, - } - - return await self._send_message( - "sendAnimation", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=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, - 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, - ) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """ - Use this method to send audio files, if you want Telegram clients to display the file - as a playable voice message. For this to work, your audio must be in an ``.ogg`` file - encoded with OPUS , or in .MP3 format, or in .M4A format (other formats may be sent as - :class:`~telegram.Audio` or :class:`~telegram.Document`). Bots can currently send voice - messages of up to :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, - this limit may be changed in the future. - - Note: - To use this method, the file must have the type :mimetype:`audio/ogg` and be no more - than :tg-const:`telegram.constants.FileSizeLimit.VOICE_NOTE_FILE_SIZE` in size. - :tg-const:`telegram.constants.FileSizeLimit.VOICE_NOTE_FILE_SIZE`- - :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD` voice notes will be - sent as files. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - voice (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \ - | :class:`pathlib.Path` | :class:`telegram.Voice`): Voice file to send. - |fileinput| - Lastly you can pass an existing :class:`telegram.Voice` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - .. versionchanged:: 20.0 - File paths as input is also accepted for bots *not* running in - :paramref:`~telegram.Bot.local_mode`. - caption (:obj:`str`, optional): Voice message caption, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - - .. versionchanged:: 20.0 - |sequenceargs| - duration (:obj:`int`, optional): Duration of the voice message in seconds. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - filename (:obj:`str`, optional): Custom file name for the voice, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "voice": self._parse_file_input(voice, Voice, filename=filename), - "duration": duration, - } - - return await self._send_message( - "sendVoice", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=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, - 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, - ) - - 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, - *, - 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, - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence["MessageEntity"]] = None, - ) -> tuple[Message, ...]: - """Use this method to send a group of photos, videos, documents or audios as an album. - Documents and audio files can be only grouped in an album with messages of the same type. - - Note: - If you supply a :paramref:`caption` (along with either :paramref:`parse_mode` or - :paramref:`caption_entities`), then items in :paramref:`media` must have no captions, - and vice versa. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.0 - Returns a tuple instead of a list. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - media (Sequence[:class:`telegram.InputMediaAudio`,\ - :class:`telegram.InputMediaDocument`, :class:`telegram.InputMediaPhoto`,\ - :class:`telegram.InputMediaVideo`]): An array - describing messages to be sent, must include - :tg-const:`telegram.constants.MediaGroupLimit.MIN_MEDIA_LENGTH`- - :tg-const:`telegram.constants.MediaGroupLimit.MAX_MEDIA_LENGTH` items. - - .. versionchanged:: 20.0 - |sequenceargs| - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - caption (:obj:`str`, optional): Caption that will be added to the - first element of :paramref:`media`, so that it will be used as caption for the - whole media group. - Defaults to :obj:`None`. - - .. versionadded:: 20.0 - parse_mode (:obj:`str` | :obj:`None`, optional): - Parse mode for :paramref:`caption`. - See the constants in :class:`telegram.constants.ParseMode` for the - available modes. - - .. versionadded:: 20.0 - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - List of special entities for :paramref:`caption`, - which can be specified instead of :paramref:`parse_mode`. - Defaults to :obj:`None`. - - .. versionadded:: 20.0 - - Returns: - tuple[:class:`telegram.Message`]: An array of the sent Messages. - - Raises: - :class:`telegram.error.TelegramError` - """ - if caption and any( - [ - any(item.caption for item in media), - any(item.caption_entities for item in media), - # if parse_mode was set explicitly, even to None, error must be raised - any(item.parse_mode is not DEFAULT_NONE for item in media), - ] - ): - raise ValueError("You can only supply either group caption or media with captions.") - - if caption: - # Copy first item (to avoid mutation of original object), apply group caption to it. - # This will lead to the group being shown with this caption. - item_to_get_caption = copy.copy(media[0]) - with item_to_get_caption._unfrozen(): - item_to_get_caption.caption = caption - if parse_mode is not DEFAULT_NONE: - item_to_get_caption.parse_mode = parse_mode - item_to_get_caption.caption_entities = parse_sequence_arg(caption_entities) - - # copy the list (just the references) to avoid mutating the original list - media = list(media) - media[0] = item_to_get_caption - - if allow_sending_without_reply is not DEFAULT_NONE and reply_parameters is not None: - raise ValueError( - "`allow_sending_without_reply` and `reply_parameters` are mutually exclusive." - ) - - if reply_to_message_id is not None and reply_parameters is not None: - raise ValueError( - "`reply_to_message_id` and `reply_parameters` are mutually exclusive." - ) - - if reply_to_message_id is not None: - reply_parameters = ReplyParameters( - message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - ) - - data: JSONDict = { - "chat_id": chat_id, - "media": media, - "disable_notification": disable_notification, - "protect_content": protect_content, - "message_thread_id": message_thread_id, - "reply_parameters": reply_parameters, - "business_connection_id": business_connection_id, - "message_effect_id": message_effect_id, - "allow_paid_broadcast": allow_paid_broadcast, - } - - result = await self._post( - "sendMediaGroup", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return Message.de_list(result, self) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """Use this method to send point on the map. - - Note: - You can either supply a :paramref:`latitude` and :paramref:`longitude` or a - :paramref:`location`. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - latitude (:obj:`float`, optional): Latitude of location. - longitude (:obj:`float`, optional): Longitude of location. - horizontal_accuracy (:obj:`int`, optional): The radius of uncertainty for the location, - measured in meters; - 0-:tg-const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`. - live_period (:obj:`int`, optional): Period in seconds for which the location will be - updated, should be between - :tg-const:`telegram.constants.LocationLimit.MIN_LIVE_PERIOD` and - :tg-const:`telegram.constants.LocationLimit.MAX_LIVE_PERIOD`, or - :tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` for live - locations that can be edited indefinitely. - heading (:obj:`int`, optional): For live locations, a direction in which the user is - moving, in degrees. Must be between - :tg-const:`telegram.constants.LocationLimit.MIN_HEADING` and - :tg-const:`telegram.constants.LocationLimit.MAX_HEADING` if specified. - proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance - for proximity alerts about approaching another chat member, in meters. Must be - between :tg-const:`telegram.constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS` - and :tg-const:`telegram.constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS` - if specified. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - location (:class:`telegram.Location`, optional): The location to send. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - if not ((latitude is not None and longitude is not None) or location): - raise ValueError( - "Either location or latitude and longitude must be passed as argument." - ) - - if not (latitude is not None or longitude is not None) ^ bool(location): - raise ValueError( - "Either location or latitude and longitude must be passed as argument. Not both." - ) - - if isinstance(location, Location): - latitude = location.latitude - longitude = location.longitude - - data: JSONDict = { - "chat_id": chat_id, - "latitude": latitude, - "longitude": longitude, - "horizontal_accuracy": horizontal_accuracy, - "live_period": live_period, - "heading": heading, - "proximity_alert_radius": proximity_alert_radius, - } - - return await self._send_message( - "sendLocation", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - 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, - ) -> Union[Message, bool]: - """Use this method to edit live location messages sent by the bot or via the bot - (for inline bots). A location can be edited until its :attr:`telegram.Location.live_period` - expires or editing is explicitly disabled by a call to :meth:`stop_message_live_location`. - - Note: - You can either supply a :paramref:`latitude` and :paramref:`longitude` or a - :paramref:`location`. - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if :paramref:`inline_message_id` - is not specified. |chat_id_channel| - message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not - specified. Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and - :paramref:`message_id` are not specified. Identifier of the inline message. - latitude (:obj:`float`, optional): Latitude of location. - longitude (:obj:`float`, optional): Longitude of location. - horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the - location, measured in meters; - 0-:tg-const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`. - heading (:obj:`int`, optional): Direction in which the user is moving, in degrees. Must - be between :tg-const:`telegram.constants.LocationLimit.MIN_HEADING` - and :tg-const:`telegram.constants.LocationLimit.MAX_HEADING` if specified. - proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts - about approaching another chat member, in meters. Must be between - :tg-const:`telegram.constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS` - and :tg-const:`telegram.constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS` - if specified. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new - inline keyboard. - live_period (:obj:`int`, optional): New period in seconds during which the location - can be updated, starting from the message send date. If - :tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` is specified, - then the location can be updated forever. Otherwise, the new value must not exceed - the current ``live_period`` by more than a day, and the live location expiration - date must remain within the next 90 days. If not specified, then ``live_period`` - remains unchanged - - .. versionadded:: 21.2. - business_connection_id (:obj:`str`, optional): |business_id_str_edit| - - .. versionadded:: 21.4 - - Keyword Args: - location (:class:`telegram.Location`, optional): The location to send. - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - """ - # The location parameter is a convenience functionality added by us, so enforcing the - # mutual exclusivity here is nothing that Telegram would handle anyway - if not (all([latitude, longitude]) or location): - raise ValueError( - "Either location or latitude and longitude must be passed as argument." - ) - if not (latitude is not None or longitude is not None) ^ bool(location): - raise ValueError( - "Either location or latitude and longitude must be passed as argument. Not both." - ) - - if isinstance(location, Location): - latitude = location.latitude - longitude = location.longitude - - data: JSONDict = { - "latitude": latitude, - "longitude": longitude, - "chat_id": chat_id, - "message_id": message_id, - "inline_message_id": inline_message_id, - "horizontal_accuracy": horizontal_accuracy, - "heading": heading, - "proximity_alert_radius": proximity_alert_radius, - "live_period": live_period, - } - - return await self._send_message( - "editMessageLiveLocation", - data, - 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=api_kwargs, - ) - - 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, - ) -> Union[Message, bool]: - """Use this method to stop updating a live location message sent by the bot or via the bot - (for inline bots) before :paramref:`~telegram.Location.live_period` expires. - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if :paramref:`inline_message_id` - is not specified. |chat_id_channel| - message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not - specified. Identifier of the sent message with live location to stop. - inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and - :paramref:`message_id` are not specified. Identifier of the inline message. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new - inline keyboard. - business_connection_id (:obj:`str`, optional): |business_id_str_edit| - - .. versionadded:: 21.4 - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - """ - data: JSONDict = { - "chat_id": chat_id, - "message_id": message_id, - "inline_message_id": inline_message_id, - } - - return await self._send_message( - "stopMessageLiveLocation", - data, - 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=api_kwargs, - ) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """Use this method to send information about a venue. - - Note: - * You can either supply :paramref:`venue`, or :paramref:`latitude`, - :paramref:`longitude`, :paramref:`title` and :paramref:`address` and optionally - :paramref:`foursquare_id` and :paramref:`foursquare_type` or optionally - :paramref:`google_place_id` and :paramref:`google_place_type`. - * Foursquare details and Google Place details are mutually exclusive. However, this - behaviour is undocumented and might be changed by Telegram. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - latitude (:obj:`float`, optional): Latitude of venue. - longitude (:obj:`float`, optional): Longitude of venue. - title (:obj:`str`, optional): Name of the venue. - address (:obj:`str`, optional): Address of the venue. - foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue. - foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. - (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or - "food/icecream".) - google_place_id (:obj:`str`, optional): Google Places identifier of the venue. - google_place_type (:obj:`str`, optional): Google Places type of the venue. (See - `supported types \ - `_.) - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - venue (:class:`telegram.Venue`, optional): The venue to send. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - # The venue parameter is a convenience functionality added by us, so enforcing the - # mutual exclusivity here is nothing that Telegram would handle anyway - if not (venue or all([latitude, longitude, address, title])): - raise ValueError( - "Either venue or latitude, longitude, address and title must be " - "passed as arguments." - ) - if not bool(venue) ^ any([latitude, longitude, address, title]): - raise ValueError( - "Either venue or latitude, longitude, address and title must be " - "passed as arguments. Not both." - ) - - if isinstance(venue, Venue): - latitude = venue.location.latitude - longitude = venue.location.longitude - address = venue.address - title = venue.title - foursquare_id = venue.foursquare_id - foursquare_type = venue.foursquare_type - google_place_id = venue.google_place_id - google_place_type = venue.google_place_type - - data: JSONDict = { - "chat_id": chat_id, - "latitude": latitude, - "longitude": longitude, - "address": address, - "title": title, - "foursquare_id": foursquare_id, - "foursquare_type": foursquare_type, - "google_place_id": google_place_id, - "google_place_type": google_place_type, - } - - return await self._send_message( - "sendVenue", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - 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, - *, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = 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: - """Use this method to send phone contacts. - - Note: - You can either supply :paramref:`contact` or :paramref:`phone_number` and - :paramref:`first_name` with optionally :paramref:`last_name` and optionally - :paramref:`vcard`. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - phone_number (:obj:`str`, optional): Contact's phone number. - first_name (:obj:`str`, optional): Contact's first name. - last_name (:obj:`str`, optional): Contact's last name. - vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, - 0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - contact (:class:`telegram.Contact`, optional): The contact to send. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - # The contact parameter is a convenience functionality added by us, so enforcing the - # mutual exclusivity here is nothing that Telegram would handle anyway - if (not contact) and (not all([phone_number, first_name])): - raise ValueError( - "Either contact or phone_number and first_name must be passed as arguments." - ) - if not bool(contact) ^ any([phone_number, first_name]): - raise ValueError( - "Either contact or phone_number and first_name must be passed as arguments. " - "Not both." - ) - - if isinstance(contact, Contact): - phone_number = contact.phone_number - first_name = contact.first_name - last_name = contact.last_name - vcard = contact.vcard - - data: JSONDict = { - "chat_id": chat_id, - "phone_number": phone_number, - "first_name": first_name, - "last_name": last_name, - "vcard": vcard, - } - - return await self._send_message( - "sendContact", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - business_connection_id=business_connection_id, - 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, - *, - 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, - ) -> Message: - """Use this method to send a game. - - Args: - chat_id (:obj:`int`): Unique identifier for the target chat. - game_short_name (:obj:`str`): Short name of the game, serves as the unique identifier - for the game. Set up your games via `@BotFather `_. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new - inline keyboard. If empty, one "Play game_title" button will be - shown. If not empty, the first button must launch the game. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "game_short_name": game_short_name} - - return await self._send_message( - "sendGame", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - business_connection_id=business_connection_id, - 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, - ) -> bool: - """ - Use this method when you need to tell the user that something is happening on the bot's - side. The status is set for 5 seconds or less (when a message arrives from your bot, - Telegram clients clear its typing status). Telegram only recommends using this method when - a response from the bot will take a noticeable amount of time to arrive. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - action(:obj:`str`): Type of action to broadcast. Choose one, depending on what the user - is about to receive. For convenience look at the constants in - :class:`telegram.constants.ChatAction`. - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "action": action, - "message_thread_id": message_thread_id, - "business_connection_id": business_connection_id, - } - return await self._post( - "sendChatAction", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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]]: - """ - Builds the effective results from the results input. - We make this a stand-alone method so tg.ext.ExtBot can wrap it. - - Returns: - Tuple of 1. the effective results and 2. correct the next_offset - - """ - if current_offset is not None and next_offset is not None: - raise ValueError("`current_offset` and `next_offset` are mutually exclusive!") - - if current_offset is not None: - # Convert the string input to integer - current_offset_int = 0 if not current_offset else int(current_offset) - - # for now set to empty string, stating that there are no more results - # might change later - next_offset = "" - - if callable(results): - callable_output = results(current_offset_int) - if not callable_output: - effective_results: Sequence[InlineQueryResult] = [] - else: - effective_results = callable_output - # the callback *might* return more results on the next call, so we increment - # the page count - next_offset = str(current_offset_int + 1) - - elif len(results) > (current_offset_int + 1) * InlineQueryLimit.RESULTS: - # we expect more results for the next page - next_offset_int = current_offset_int + 1 - next_offset = str(next_offset_int) - effective_results = results[ - current_offset_int - * InlineQueryLimit.RESULTS : next_offset_int - * InlineQueryLimit.RESULTS - ] - else: - effective_results = results[current_offset_int * InlineQueryLimit.RESULTS :] - else: - effective_results = results # type: ignore[assignment] - - return effective_results, next_offset - - @no_type_check # mypy doesn't play too well with hasattr - def _insert_defaults_for_ilq_results(self, res: "InlineQueryResult") -> "InlineQueryResult": - """The reason why this method exists is similar to the description of _insert_defaults - The reason why we do this in rather than in _insert_defaults is because converting - DEFAULT_NONE to NONE *before* calling to_dict() makes it way easier to drop None entries - from the json data. - - Must return the correct object instead of editing in-place! - """ - # Copy the objects that need modification to avoid modifying the original object - copied = False - if hasattr(res, "parse_mode"): - res = copy.copy(res) - copied = True - with res._unfrozen(): - res.parse_mode = DefaultValue.get_value(res.parse_mode) - if hasattr(res, "input_message_content") and res.input_message_content: - if hasattr(res.input_message_content, "parse_mode"): - if not copied: - res = copy.copy(res) - copied = True - - with res._unfrozen(): - res.input_message_content = copy.copy(res.input_message_content) - with res.input_message_content._unfrozen(): - res.input_message_content.parse_mode = DefaultValue.get_value( - res.input_message_content.parse_mode - ) - if hasattr(res.input_message_content, "link_preview_options"): - if not copied: - res = copy.copy(res) - - with res._unfrozen(): - res.input_message_content = copy.copy(res.input_message_content) - with res.input_message_content._unfrozen(): - res.input_message_content.link_preview_options = DefaultValue.get_value( - res.input_message_content.link_preview_options - ) - - return res - - 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, - ) -> bool: - """ - Use this method to send answers to an inline query. No more than - :tg-const:`telegram.InlineQuery.MAX_RESULTS` results per query are allowed. - - Warning: - In most use cases :paramref:`current_offset` should not be passed manually. Instead of - calling this method directly, use the shortcut :meth:`telegram.InlineQuery.answer` with - :paramref:`telegram.InlineQuery.answer.auto_pagination` set to :obj:`True`, which will - take care of passing the correct value. - - .. seealso:: :wiki:`Working with Files and Media ` - - - .. versionchanged:: 20.5 - Removed deprecated arguments ``switch_pm_text`` and ``switch_pm_parameter``. - - Args: - inline_query_id (:obj:`str`): Unique identifier for the answered query. - results (list[:class:`telegram.InlineQueryResult`] | Callable): A list of results for - the inline query. In case :paramref:`current_offset` is passed, - :paramref:`results` may also be - a callable that accepts the current page index starting from 0. It must return - either a list of :class:`telegram.InlineQueryResult` instances or :obj:`None` if - there are no more results. - cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the - result of the inline query may be cached on the server. Defaults to ``300``. - is_personal (:obj:`bool`, optional): Pass :obj:`True`, if results may be cached on - the server side only for the user that sent the query. By default, - results may be returned to any user who sends the same query. - next_offset (:obj:`str`, optional): Pass the offset that a client should send in the - next query with the same text to receive more results. Pass an empty string if - there are no more results or if you don't support pagination. Offset length can't - exceed :tg-const:`telegram.InlineQuery.MAX_OFFSET_LENGTH` bytes. - button (:class:`telegram.InlineQueryResultsButton`, optional): A button to be shown - above the inline query results. - - .. versionadded:: 20.3 - - Keyword Args: - current_offset (:obj:`str`, optional): The :attr:`telegram.InlineQuery.offset` of - the inline query to answer. If passed, PTB will automatically take care of - the pagination for you, i.e. pass the correct :paramref:`next_offset` and truncate - the results list/get the results from the callable you passed. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - effective_results, next_offset = self._effective_inline_results( - results=results, next_offset=next_offset, current_offset=current_offset - ) - - # Apply defaults - effective_results = [ - self._insert_defaults_for_ilq_results(result) for result in effective_results - ] - - data: JSONDict = { - "inline_query_id": inline_query_id, - "results": effective_results, - "next_offset": next_offset, - "cache_time": cache_time, - "is_personal": is_personal, - "button": button, - } - - return await self._post( - "answerInlineQuery", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> PreparedInlineMessage: - """Stores a message that can be sent by a user of a Mini App. - - .. versionadded:: 21.8 - - Args: - user_id (:obj:`int`): Unique identifier of the target user that can use the prepared - message. - result (:class:`telegram.InlineQueryResult`): The result to store. - allow_user_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent - to private chats with users - allow_bot_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent - to private chats with bots - allow_group_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent - to group and supergroup chats - allow_channel_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be - sent to channels - - Returns: - :class:`telegram.PreparedInlineMessage`: On success, the prepared message is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "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, - } - return PreparedInlineMessage.de_json( # type: ignore[return-value] - await self._post( - "savePreparedInlineMessage", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ), - self, - ) - - 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, - ) -> UserProfilePhotos: - """Use this method to get a list of profile pictures for a user. - - Args: - user_id (:obj:`int`): Unique identifier of the target user. - offset (:obj:`int`, optional): Sequential number of the first photo to be returned. - By default, all photos are returned. - limit (:obj:`int`, optional): Limits the number of photos to be retrieved. Values - between :tg-const:`telegram.constants.UserProfilePhotosLimit.MIN_LIMIT`- - :tg-const:`telegram.constants.UserProfilePhotosLimit.MAX_LIMIT` are accepted. - Defaults to ``100``. - - Returns: - :class:`telegram.UserProfilePhotos` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"user_id": user_id, "offset": offset, "limit": limit} - - result = await self._post( - "getUserProfilePhotos", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return UserProfilePhotos.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> File: - """ - Use this method to get basic info about a file and prepare it for downloading. For the - moment, bots can download files of up to - :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD` in size. The file can then - be e.g. downloaded with :meth:`telegram.File.download_to_drive`. It is guaranteed that - the link will be valid for at least 1 hour. When the link expires, a new one can be - requested by calling get_file again. - - Note: - This function may not preserve the original file name and MIME type. - You should save the file's MIME type and name (if available) when the File object - is received. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - file_id (:obj:`str` | :class:`telegram.Animation` | :class:`telegram.Audio` | \ - :class:`telegram.ChatPhoto` | :class:`telegram.Document` | \ - :class:`telegram.PhotoSize` | :class:`telegram.Sticker` | \ - :class:`telegram.Video` | :class:`telegram.VideoNote` | \ - :class:`telegram.Voice`): - Either the file identifier or an object that has a file_id attribute - to get file information about. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - # Try to get the file_id from the object, if it fails, assume it's a string - with contextlib.suppress(AttributeError): - file_id = file_id.file_id # type: ignore[union-attr] - - data: JSONDict = {"file_id": file_id} - - result = await self._post( - "getFile", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - file_path = cast(dict, result).get("file_path") - if file_path and not is_local_file(file_path): - result["file_path"] = f"{self._base_file_url}/{file_path}" - - return File.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> bool: - """ - Use this method to ban a user from a group, supergroup or a channel. In the case of - supergroups and channels, the user will not be able to return to the group on their own - using invite links, etc., unless unbanned first. The bot must be an administrator in the - chat for this to work and must have the appropriate admin rights. - - .. versionadded:: 13.7 - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username - of the target supergroup or channel (in the format ``@channelusername``). - user_id (:obj:`int`): Unique identifier of the target user. - until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the user will - be unbanned, unix time. If user is banned for more than 366 days or less than 30 - seconds from the current time they are considered to be banned forever. Applied - for supergroups and channels only. - |tz-naive-dtms| - revoke_messages (:obj:`bool`, optional): Pass :obj:`True` to delete all messages from - the chat for the user that is being removed. If :obj:`False`, the user will be able - to see messages in the group that were sent before the user was removed. - Always :obj:`True` for supergroups and channels. - - .. versionadded:: 13.4 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "user_id": user_id, - "revoke_messages": revoke_messages, - "until_date": until_date, - } - - return await self._post( - "banChatMember", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to ban a channel chat in a supergroup or a channel. Until the chat is - unbanned, the owner of the banned chat won't be able to send messages on behalf of **any of - their channels**. The bot must be an administrator in the supergroup or channel for this - to work and must have the appropriate administrator rights. - - .. versionadded:: 13.9 - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username - of the target supergroup or channel (in the format ``@channelusername``). - sender_chat_id (:obj:`int`): Unique identifier of the target sender chat. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "sender_chat_id": sender_chat_id} - - return await self._post( - "banChatSenderChat", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method to unban a previously kicked user in a supergroup or channel. - - The user will *not* return to the group or channel automatically, but will be able to join - via link, etc. The bot must be an administrator for this to work. By default, this method - guarantees that after the call the user is not a member of the chat, but will be able to - join it. So if the user is a member of the chat they will also be *removed* from the chat. - If you don't want this, use the parameter :paramref:`only_if_banned`. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - user_id (:obj:`int`): Unique identifier of the target user. - only_if_banned (:obj:`bool`, optional): Do nothing if the user is not banned. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "user_id": user_id, "only_if_banned": only_if_banned} - - return await self._post( - "unbanChatMember", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method to unban a previously banned channel in a supergroup or channel. - The bot must be an administrator for this to work and must have the - appropriate administrator rights. - - .. versionadded:: 13.9 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - sender_chat_id (:obj:`int`): Unique identifier of the target sender chat. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "sender_chat_id": sender_chat_id} - - return await self._post( - "unbanChatSenderChat", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to send answers to callback queries sent from inline keyboards. The answer - will be displayed to the user as a notification at the top of the chat screen or as an - alert. - Alternatively, the user can be redirected to the specified Game URL. For this option to - work, you must first create a game for your bot via `@BotFather `_ - and accept the terms. Otherwise, you may use links like t.me/your_bot?start=XXXX that open - your bot with a parameter. - - Args: - callback_query_id (:obj:`str`): Unique identifier for the query to be answered. - text (:obj:`str`, optional): Text of the notification. If not specified, nothing will - be shown to the user, 0-:tg-const:`telegram.CallbackQuery.MAX_ANSWER_TEXT_LENGTH` - characters. - show_alert (:obj:`bool`, optional): If :obj:`True`, an alert will be shown by the - client instead of a notification at the top of the chat screen. Defaults to - :obj:`False`. - url (:obj:`str`, optional): URL that will be opened by the user's client. If you have - created a Game and accepted the conditions via - `@BotFather `_, specify the URL that - opens your game - note that this will only work if the query comes from a callback - game button. Otherwise, you may use links like t.me/your_bot?start=XXXX that open - your bot with a parameter. - cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the - result of the callback query may be cached client-side. Defaults to 0. - - Returns: - :obj:`bool` On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "callback_query_id": callback_query_id, - "cache_time": cache_time, - "text": text, - "show_alert": show_alert, - "url": url, - } - - return await self._post( - "answerCallbackQuery", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> Union[Message, bool]: - """ - Use this method to edit text and game messages. - - Note: - * |editreplymarkup| - * |bcid_edit_time| - - .. seealso:: :attr:`telegram.Game.text` - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if :paramref:`inline_message_id` - is not specified. |chat_id_channel| - message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not - specified. Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and - :paramref:`message_id` are not specified. Identifier of the inline message. - text (:obj:`str`): New text of the message, - :tg-const:`telegram.constants.MessageLimit.MIN_TEXT_LENGTH`- - :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of special - entities that appear in message text, which can be specified instead of - :paramref:`parse_mode`. - - .. versionchanged:: 20.0 - |sequenceargs| - - link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation - options for the message. Mutually exclusive with - :paramref:`disable_web_page_preview`. - - .. versionadded:: 20.8 - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. - business_connection_id (:obj:`str`, optional): |business_id_str_edit| - - .. versionadded:: 21.4 - - Keyword Args: - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in - this message. Convenience parameter for setting :paramref:`link_preview_options`. - Mutually exclusive with :paramref:`link_preview_options`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`link_preview_options` replacing this - argument. PTB will automatically convert this argument to that one, but - for advanced options, please use :paramref:`link_preview_options` directly. - - .. versionchanged:: 21.0 - |keyword_only_arg| - - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - - Raises: - :exc:`ValueError`: If both :paramref:`disable_web_page_preview` and - :paramref:`link_preview_options` are passed. - :class:`telegram.error.TelegramError`: For other errors. - - """ - data: JSONDict = { - "text": text, - "chat_id": chat_id, - "message_id": message_id, - "inline_message_id": inline_message_id, - "entities": entities, - } - - link_preview_options = parse_lpo_and_dwpp(disable_web_page_preview, link_preview_options) - - return await self._send_message( - "editMessageText", - data, - reply_markup=reply_markup, - parse_mode=parse_mode, - link_preview_options=link_preview_options, - business_connection_id=business_connection_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> Union[Message, bool]: - """ - Use this method to edit captions of messages. - - Note: - * |editreplymarkup| - * |bcid_edit_time| - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. |chat_id_channel| - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - caption (:obj:`str`, optional): New caption of the message, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - - .. versionchanged:: 20.0 - |sequenceargs| - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - business_connection_id (:obj:`str`, optional): |business_id_str_edit| - - .. versionadded:: 21.4 - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_id": message_id, - "inline_message_id": inline_message_id, - "show_caption_above_media": show_caption_above_media, - } - - return await self._send_message( - "editMessageCaption", - data, - reply_markup=reply_markup, - caption=caption, - 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=api_kwargs, - ) - - 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, - ) -> Union[Message, bool]: - """ - Use this method to edit animation, audio, document, photo, or video messages, or to add - media to text messages. If a message - is part of a message album, then it can be edited only to an audio for audio albums, only - to a document for document albums and to a photo or a video otherwise. When an inline - message is edited, a new file can't be uploaded; use a previously uploaded file via its - :attr:`~telegram.File.file_id` or specify a URL. - - Note: - * |editreplymarkup| - * |bcid_edit_time| - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - media (:class:`telegram.InputMedia`): An object for a new media content - of the message. - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. |chat_id_channel| - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. - business_connection_id (:obj:`str`, optional): |business_id_str_edit| - - .. versionadded:: 21.4 - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "media": media, - "chat_id": chat_id, - "message_id": message_id, - "inline_message_id": inline_message_id, - } - - return await self._send_message( - "editMessageMedia", - data, - 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=api_kwargs, - ) - - 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, - ) -> Union[Message, bool]: - """ - Use this method to edit only the reply markup of messages sent by the bot or via the bot - (for inline bots). - - Note: - * |editreplymarkup| - * |bcid_edit_time| - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. |chat_id_channel| - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. - business_connection_id (:obj:`str`, optional): |business_id_str_edit| - - .. versionadded:: 21.4 - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_id": message_id, - "inline_message_id": inline_message_id, - } - - return await self._send_message( - "editMessageReplyMarkup", - data, - 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=api_kwargs, - ) - - 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, ...]: - """Use this method to receive incoming updates using long polling. - - Note: - 1. This method will not work if an outgoing webhook is set up. - 2. In order to avoid getting duplicate updates, recalculate offset after each - server response. - 3. To take full advantage of this library take a look at :class:`telegram.ext.Updater` - - .. seealso:: :meth:`telegram.ext.Application.run_polling`, - :meth:`telegram.ext.Updater.start_polling` - - .. versionchanged:: 20.0 - Returns a tuple instead of a list. - - Args: - offset (:obj:`int`, optional): Identifier of the first update to be returned. Must be - greater by one than the highest among the identifiers of previously received - updates. By default, updates starting with the earliest unconfirmed update are - returned. An update is considered confirmed as soon as this method is called with - an offset higher than its :attr:`telegram.Update.update_id`. The negative offset - can be specified to retrieve updates starting from -offset update from the end of - the updates queue. All previous updates will be forgotten. - limit (:obj:`int`, optional): Limits the number of updates to be retrieved. Values - between :tg-const:`telegram.constants.PollingLimit.MIN_LIMIT`- - :tg-const:`telegram.constants.PollingLimit.MAX_LIMIT` are accepted. - Defaults to ``100``. - timeout (:obj:`int`, optional): Timeout in seconds for long polling. Defaults to ``0``, - i.e. usual short polling. Should be positive, short polling should be used for - testing purposes only. - allowed_updates (Sequence[:obj:`str`]), optional): A sequence the types of - updates you want your bot to receive. For example, specify ["message", - "edited_channel_post", "callback_query"] to only receive updates of these types. - See :class:`telegram.Update` for a complete list of available update types. - Specify an empty sequence to receive all updates except - :attr:`telegram.Update.chat_member`, :attr:`telegram.Update.message_reaction` and - :attr:`telegram.Update.message_reaction_count` (default). If not specified, the - previous setting will be used. Please note that this parameter doesn't affect - updates created before the call to the get_updates, so unwanted updates may be - received for a short period of time. - - .. versionchanged:: 20.0 - |sequenceargs| - - Returns: - tuple[:class:`telegram.Update`] - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "timeout": timeout, - "offset": offset, - "limit": limit, - "allowed_updates": allowed_updates, - } - - # The "or 0" is needed for the case where read_timeout is None. - if not isinstance(read_timeout, DefaultValue): - arg_read_timeout: float = read_timeout or 0 - else: - try: - arg_read_timeout = self._request[0].read_timeout or 0 - except NotImplementedError: - arg_read_timeout = 2 - self._warn( - PTBDeprecationWarning( - "20.7", - f"The class {self._request[0].__class__.__name__} does not override " - "the property `read_timeout`. Overriding this property will be mandatory " - "in future versions. Using 2 seconds as fallback.", - ), - stacklevel=2, - ) - - # Ideally we'd use an aggressive read timeout for the polling. However, - # * Short polling should return within 2 seconds. - # * Long polling poses a different problem: the connection might have been dropped while - # waiting for the server to return and there's no way of knowing the connection had been - # dropped in real time. - result = cast( - list[JSONDict], - await self._post( - "getUpdates", - data, - read_timeout=arg_read_timeout + timeout if timeout else arg_read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ), - ) - - if result: - self._LOGGER.debug("Getting updates: %s", [u["update_id"] for u in result]) - else: - self._LOGGER.debug("No new updates found.") - - try: - return Update.de_list(result, self) - except Exception as exc: - # This logging is in place mostly b/c we can't access the raw json data in Updater, - # where the exception is caught and logged again. Still, it might also be beneficial - # for custom usages of `get_updates`. - self._LOGGER.critical( - "Error while parsing updates! Received data was %r", result, exc_info=exc - ) - raise - - 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, - ) -> bool: - """ - Use this method to specify a url and receive incoming updates via an outgoing webhook. - Whenever there is an update for the bot, Telegram will send an HTTPS POST request to the - specified url, containing An Update. In case of an unsuccessful request, - Telegram will give up after a reasonable amount of attempts. - - If you'd like to make sure that the Webhook was set by you, you can specify secret data in - the parameter :paramref:`secret_token`. If specified, the request will contain a header - ``X-Telegram-Bot-Api-Secret-Token`` with the secret token as content. - - Note: - 1. You will not be able to receive updates using :meth:`get_updates` for long as an - outgoing webhook is set up. - 2. To use a self-signed certificate, you need to upload your public key certificate - using :paramref:`certificate` parameter. Please upload as - :class:`~telegram.InputFile`, sending a String will not work. - 3. Ports currently supported for Webhooks: - :attr:`telegram.constants.SUPPORTED_WEBHOOK_PORTS`. - - If you're having any trouble setting up webhooks, please check out this `guide to - Webhooks`_. - - .. seealso:: :meth:`telegram.ext.Application.run_webhook`, - :meth:`telegram.ext.Updater.start_webhook` - - Examples: - :any:`Custom Webhook Bot ` - - Args: - url (:obj:`str`): HTTPS url to send updates to. Use an empty string to remove webhook - integration. - certificate (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`): - Upload your public key certificate so that the root - certificate in use can be checked. See our :wiki:`self-signed guide\ - ` for details. - |uploadinputnopath| - ip_address (:obj:`str`, optional): The fixed IP address which will be used to send - webhook requests instead of the IP address resolved through DNS. - max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS - connections to the webhook for update delivery, - :tg-const:`telegram.constants.WebhookLimit.MIN_CONNECTIONS_LIMIT`- - :tg-const:`telegram.constants.WebhookLimit.MAX_CONNECTIONS_LIMIT`. - Defaults to ``40``. Use lower values to limit the load on your bot's server, - and higher values to increase your bot's throughput. - allowed_updates (Sequence[:obj:`str`], optional): A sequence of the types of - updates you want your bot to receive. For example, specify ["message", - "edited_channel_post", "callback_query"] to only receive updates of these types. - See :class:`telegram.Update` for a complete list of available update types. - Specify an empty sequence to receive all updates except - :attr:`telegram.Update.chat_member`, - :attr:`telegram.Update.message_reaction` - and :attr:`telegram.Update.message_reaction_count` (default). If not - specified, the previous setting will be used. Please note that this - parameter doesn't affect - updates created before the call to the set_webhook, so unwanted update - may be received for a short period of time. - - .. versionchanged:: 20.0 - |sequenceargs| - drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending - updates. - secret_token (:obj:`str`, optional): A secret token to be sent in a header - ``X-Telegram-Bot-Api-Secret-Token`` in every webhook request, - :tg-const:`telegram.constants.WebhookLimit.MIN_SECRET_TOKEN_LENGTH`- - :tg-const:`telegram.constants.WebhookLimit.MAX_SECRET_TOKEN_LENGTH` characters. - Only characters ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed. - The header is useful to ensure that the request comes from a webhook set by you. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool` On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - .. _`guide to Webhooks`: https://core.telegram.org/bots/webhooks - - """ - data: JSONDict = { - "url": url, - "max_connections": max_connections, - "allowed_updates": allowed_updates, - "ip_address": ip_address, - "drop_pending_updates": drop_pending_updates, - "secret_token": secret_token, - "certificate": self._parse_file_input(certificate), # type: ignore[arg-type] - } - - return await self._post( - "setWebhook", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to remove webhook integration if you decide to switch back to - :meth:`get_updates()`. - - Args: - drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending - updates. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data = {"drop_pending_updates": drop_pending_updates} - - return await self._post( - "deleteWebhook", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method for your bot to leave a group, supergroup or channel. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - - return await self._post( - "leaveChat", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> ChatFullInfo: - """ - Use this method to get up to date information about the chat (current name of the user for - one-on-one conversations, current username of a user, group or channel, etc.). - - .. versionchanged:: 21.2 - In accordance to Bot API 7.3, this method now returns a :class:`telegram.ChatFullInfo`. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - - Returns: - :class:`telegram.ChatFullInfo` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - - result = await self._post( - "getChat", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return ChatFullInfo.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> tuple[ChatMember, ...]: - """ - Use this method to get a list of administrators in a chat. - - .. versionchanged:: 20.0 - Returns a tuple instead of a list. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - - Returns: - tuple[:class:`telegram.ChatMember`]: On success, returns a tuple of ``ChatMember`` - objects that contains information about all chat administrators except - other bots. If the chat is a group or a supergroup and no administrators were - appointed, only the creator will be returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - result = await self._post( - "getChatAdministrators", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return ChatMember.de_list(result, self) - - 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, - ) -> int: - """Use this method to get the number of members in a chat. - - .. versionadded:: 13.7 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - - Returns: - :obj:`int`: Number of members in the chat. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - return await self._post( - "getChatMemberCount", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> ChatMember: - """Use this method to get information about a member of a chat. The method is only - guaranteed to work for other users if the bot is an administrator in the chat. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - user_id (:obj:`int`): Unique identifier of the target user. - - Returns: - :class:`telegram.ChatMember` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "user_id": user_id} - result = await self._post( - "getChatMember", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return ChatMember.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> bool: - """Use this method to set a new group sticker set for a supergroup. - The bot must be an administrator in the chat for this to work and must have the appropriate - admin rights. Use the field :attr:`telegram.ChatFullInfo.can_set_sticker_set` optionally - returned in :meth:`get_chat` requests to check if the bot can use this method. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - sticker_set_name (:obj:`str`): Name of the sticker set to be set as the group - sticker set. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - data: JSONDict = {"chat_id": chat_id, "sticker_set_name": sticker_set_name} - return await self._post( - "setChatStickerSet", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method to delete a group sticker set from a supergroup. The bot must be an - administrator in the chat for this to work and must have the appropriate admin rights. - Use the field :attr:`telegram.ChatFullInfo.can_set_sticker_set` optionally returned in - :meth:`get_chat` requests to check if the bot can use this method. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - data: JSONDict = {"chat_id": chat_id} - return await self._post( - "deleteChatStickerSet", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> WebhookInfo: - """Use this method to get current webhook status. Requires no parameters. - - If the bot is using :meth:`get_updates`, will return an object with the - :attr:`telegram.WebhookInfo.url` field empty. - - Returns: - :class:`telegram.WebhookInfo` - - """ - result = await self._post( - "getWebhookInfo", - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return WebhookInfo.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> Union[Message, bool]: - """ - Use this method to set the score of the specified user in a game message. - - .. seealso:: :attr:`telegram.Game.text` - - Args: - user_id (:obj:`int`): User identifier. - score (:obj:`int`): New score, must be non-negative. - force (:obj:`bool`, optional): Pass :obj:`True`, if the high score is allowed to - decrease. This can be useful when fixing mistakes or banning cheaters. - disable_edit_message (:obj:`bool`, optional): Pass :obj:`True`, if the game message - should not be automatically edited to include the current scoreboard. - chat_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` - is not specified. Unique identifier for the target chat. - message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not - specified. Identifier of the sent message. - inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and - :paramref:`message_id` are not specified. Identifier of the inline message. - - Returns: - :class:`telegram.Message`: The edited message. If the message is not an inline message - , :obj:`True`. - - Raises: - :class:`telegram.error.TelegramError`: If the new score is not greater than the user's - current score in the chat and :paramref:`force` is :obj:`False`. - - """ - data: JSONDict = { - "user_id": user_id, - "score": score, - "force": force, - "disable_edit_message": disable_edit_message, - "chat_id": chat_id, - "message_id": message_id, - "inline_message_id": inline_message_id, - } - - return await self._send_message( - "setGameScore", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> tuple[GameHighScore, ...]: - """ - Use this method to get data for high score tables. Will return the score of the specified - user and several of their neighbors in a game. - - Note: - This method will currently return scores for the target user, plus two of their - closest neighbors on each side. Will also return the top three users if the user and - his neighbors are not among them. Please note that this behavior is subject to change. - - .. versionchanged:: 20.0 - Returns a tuple instead of a list. - - Args: - user_id (:obj:`int`): Target user id. - chat_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` - is not specified. Unique identifier for the target chat. - message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not - specified. Identifier of the sent message. - inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and - :paramref:`message_id` are not specified. Identifier of the inline message. - - Returns: - tuple[:class:`telegram.GameHighScore`] - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "user_id": user_id, - "chat_id": chat_id, - "message_id": message_id, - "inline_message_id": inline_message_id, - } - - result = await self._post( - "getGameHighScores", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return GameHighScore.de_list(result, self) - - async def send_invoice( - self, - chat_id: Union[int, str], - title: str, - description: str, - payload: str, - provider_token: Optional[str], # This arg is now optional as of Bot API 7.4 - 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, - *, - 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, - ) -> Message: - """Use this method to send invoices. - - 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. - - .. versionchanged:: 13.5 - As of Bot API 5.2, the parameter :paramref:`start_parameter` is optional. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`- - :tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters. - description (:obj:`str`): Product description. - :tg-const:`telegram.Invoice.MIN_DESCRIPTION_LENGTH`- - :tg-const:`telegram.Invoice.MAX_DESCRIPTION_LENGTH` characters. - payload (:obj:`str`): Bot-defined invoice payload. - :tg-const:`telegram.Invoice.MIN_PAYLOAD_LENGTH`- - :tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be - displayed to the user, use it for your internal processes. - provider_token (:obj:`str`): Payments provider token, obtained via - `@BotFather `_. Pass an empty string for payments in - |tg_stars|. - - .. deprecated:: 21.3 - As of Bot API 7.4, this parameter is now optional and future versions of the - library will make it optional as well. - - currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies - `_. Pass ``XTR`` for - payment in |tg_stars|. - prices (Sequence[:class:`telegram.LabeledPrice`]): Price breakdown, a sequence - of components (e.g. product price, tax, discount, delivery cost, delivery tax, - bonus, etc.). Must contain exactly one item for payment in |tg_stars|. - - .. versionchanged:: 20.0 - |sequenceargs| - max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the - *smallest units* of the currency (integer, **not** float/double). For example, for - a maximum tip of ``US$ 1.45`` pass ``max_tip_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). - Defaults to ``0``. Not supported for payment in |tg_stars|. - - .. versionadded:: 13.5 - suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of - suggested amounts of tips in the *smallest units* of the currency (integer, **not** - float/double). At most :tg-const:`telegram.Invoice.MAX_TIP_AMOUNTS` suggested tip - amounts can be specified. The suggested tip amounts must be positive, passed in a - strictly increased order and must not exceed :paramref:`max_tip_amount`. - - .. versionadded:: 13.5 - - .. versionchanged:: 20.0 - |sequenceargs| - start_parameter (:obj:`str`, optional): Unique deep-linking parameter. If left empty, - *forwarded copies* of the sent message will have a *Pay* button, allowing - multiple users to pay directly from the forwarded message, using the same invoice. - If non-empty, forwarded copies of the sent message will have a *URL* button with a - deep link to the bot (instead of a *Pay* button), with the value used as the - start parameter. - - .. versionchanged:: 13.5 - As of Bot API 5.2, this parameter is optional. - provider_data (:obj:`str` | :obj:`object`, optional): data about the - invoice, which will be shared with the payment provider. A detailed description of - required fields should be provided by the payment provider. When an object is - passed, it will be encoded as JSON. - photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a - photo of the goods or a marketing image for a service. People like it better when - they see what they are paying for. - photo_size (:obj:`str`, optional): Photo size. - photo_width (:obj:`int`, optional): Photo width. - photo_height (:obj:`int`, optional): Photo height. - need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full - name to complete the order. Ignored for payments in |tg_stars|. - need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's - phone number to complete the order. Ignored for payments in |tg_stars|. - need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email - to complete the order. Ignored for payments in |tg_stars|. - need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the - user's shipping address to complete the order. Ignored for payments in - |tg_stars|. - send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's - phone number should be sent to provider. Ignored for payments in |tg_stars|. - send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email - address should be sent to provider. Ignored for payments in |tg_stars|. - is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on - the shipping method. Ignored for payments in |tg_stars|. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. If empty, one 'Pay total price' button will be - shown. If not empty, the first button must be a Pay button. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "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, - "start_parameter": start_parameter, - "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, - "is_flexible": is_flexible, - "send_phone_number_to_provider": send_phone_number_to_provider, - "send_email_to_provider": send_email_to_provider, - } - - return await self._send_message( - "sendInvoice", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - 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, - ) -> bool: - """ - If you sent an invoice requesting a shipping address and the parameter - :paramref:`send_invoice.is_flexible` was specified, the Bot API will send an - :class:`telegram.Update` with a :attr:`telegram.Update.shipping_query` field to the bot. - Use this method to reply to shipping queries. - - Args: - shipping_query_id (:obj:`str`): Unique identifier for the query to be answered. - ok (:obj:`bool`): Specify :obj:`True` if delivery to the specified address is possible - and :obj:`False` if there are any problems (for example, if delivery to the - specified address is not possible). - shipping_options (Sequence[:class:`telegram.ShippingOption`]), optional): Required if - :paramref:`ok` is :obj:`True`. A sequence of available shipping options. - - .. versionchanged:: 20.0 - |sequenceargs| - error_message (:obj:`str`, optional): Required if :paramref:`ok` is :obj:`False`. - Error message in human readable form that explains why it is impossible to complete - the order (e.g. "Sorry, delivery to your desired address is unavailable"). Telegram - will display this message to the user. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "shipping_query_id": shipping_query_id, - "ok": ok, - "shipping_options": shipping_options, - "error_message": error_message, - } - - return await self._post( - "answerShippingQuery", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Once the user has confirmed their payment and shipping details, the Bot API sends the final - confirmation in the form of an :class:`telegram.Update` with the field - :attr:`telegram.Update.pre_checkout_query`. Use this method to respond to such pre-checkout - queries. - - Note: - The Bot API must receive an answer within 10 seconds after the pre-checkout - query was sent. - - Args: - pre_checkout_query_id (:obj:`str`): Unique identifier for the query to be answered. - ok (:obj:`bool`): Specify :obj:`True` if everything is alright - (goods are available, etc.) and the bot is ready to proceed with the order. Use - :obj:`False` if there are any problems. - error_message (:obj:`str`, optional): Required if :paramref:`ok` is :obj:`False`. Error - message in human readable form that explains the reason for failure to proceed with - the checkout (e.g. "Sorry, somebody just bought the last of our amazing black - T-shirts while you were busy filling out your payment details. Please choose a - different color or garment!"). Telegram will display this message to the user. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "pre_checkout_query_id": pre_checkout_query_id, - "ok": ok, - "error_message": error_message, - } - - return await self._post( - "answerPreCheckoutQuery", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> SentWebAppMessage: - """Use this method to set the result of an interaction with a Web App and send a - corresponding message on behalf of the user to the chat from which the query originated. - - .. versionadded:: 20.0 - - Args: - web_app_query_id (:obj:`str`): Unique identifier for the query to be answered. - result (:class:`telegram.InlineQueryResult`): An object describing the message to be - sent. - - Returns: - :class:`telegram.SentWebAppMessage`: On success, a sent - :class:`telegram.SentWebAppMessage` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "web_app_query_id": web_app_query_id, - "result": self._insert_defaults_for_ilq_results(result), - } - - api_result = await self._post( - "answerWebAppQuery", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return SentWebAppMessage.de_json(api_result, self) # type: ignore[return-value] - - 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, - ) -> bool: - """ - Use this method to restrict a user in a supergroup. The bot must be an administrator in - the supergroup for this to work and must have the appropriate admin rights. Pass - :obj:`True` for all boolean parameters to lift restrictions from a user. - - .. seealso:: :meth:`telegram.ChatPermissions.all_permissions` - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - user_id (:obj:`int`): Unique identifier of the target user. - until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when restrictions - will be lifted for the user, unix time. If user is restricted for more than 366 - days or less than 30 seconds from the current time, they are considered to be - restricted forever. - |tz-naive-dtms| - permissions (:class:`telegram.ChatPermissions`): An object for new user - permissions. - use_independent_chat_permissions (:obj:`bool`, optional): Pass :obj:`True` if chat - permissions are set independently. Otherwise, the - :attr:`~telegram.ChatPermissions.can_send_other_messages` and - :attr:`~telegram.ChatPermissions.can_add_web_page_previews` permissions will imply - the :attr:`~telegram.ChatPermissions.can_send_messages`, - :attr:`~telegram.ChatPermissions.can_send_audios`, - :attr:`~telegram.ChatPermissions.can_send_documents`, - :attr:`~telegram.ChatPermissions.can_send_photos`, - :attr:`~telegram.ChatPermissions.can_send_videos`, - :attr:`~telegram.ChatPermissions.can_send_video_notes`, and - :attr:`~telegram.ChatPermissions.can_send_voice_notes` permissions; the - :attr:`~telegram.ChatPermissions.can_send_polls` permission will imply the - :attr:`~telegram.ChatPermissions.can_send_messages` permission. - - .. versionadded: 20.1 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "chat_id": chat_id, - "user_id": user_id, - "permissions": permissions, - "until_date": until_date, - "use_independent_chat_permissions": use_independent_chat_permissions, - } - - return await self._post( - "restrictChatMember", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to promote or demote a user in a supergroup or a channel. The bot must be - an administrator in the chat for this to work and must have the appropriate admin rights. - Pass :obj:`False` for all boolean parameters to demote a user. - - .. versionchanged:: 20.0 - The argument ``can_manage_voice_chats`` was renamed to - :paramref:`can_manage_video_chats` in accordance to Bot API 6.0. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - user_id (:obj:`int`): Unique identifier of the target user. - is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence - in the chat is hidden. - can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - access the chat event log, get boost list, see hidden supergroup and channel - members, report spam messages and ignore slow mode. Implied by any other - administrator privilege. - - .. versionadded:: 13.4 - - can_manage_video_chats (:obj:`bool`, optional): Pass :obj:`True`, if the administrator - can manage video chats. - - .. versionadded:: 20.0 - - can_change_info (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - change chat title, photo and other settings. - can_post_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - post messages in the channel, or access channel statistics; for channels only. - can_edit_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - edit messages of other users and can pin messages, for channels only. - can_delete_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - delete messages of other users. - can_invite_users (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - invite new users to the chat. - can_restrict_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator - can restrict, ban or unban chat members, or access supergroup statistics. - can_pin_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - pin messages, for supergroups only. - can_promote_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - add new administrators with a subset of their own privileges or demote - administrators that they have promoted, directly or indirectly - (promoted by administrators that were appointed by the user). - can_manage_topics (:obj:`bool`, optional): Pass :obj:`True`, if the user is - allowed to create, rename, close, and reopen forum topics; for supergroups only. - - .. versionadded:: 20.0 - can_post_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - post stories to the chat. - - .. versionadded:: 20.6 - can_edit_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - edit stories posted by other users, post stories to the chat page, pin chat - stories, and access the chat's story archive - - .. versionadded:: 20.6 - can_delete_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - delete stories posted by other users. - - .. versionadded:: 20.6 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "user_id": user_id, - "is_anonymous": is_anonymous, - "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, - "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, - } - - return await self._post( - "promoteChatMember", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to set default chat permissions for all members. The bot must be an - administrator in the group or a supergroup for this to work and must have the - :attr:`telegram.ChatMemberAdministrator.can_restrict_members` admin rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - permissions (:class:`telegram.ChatPermissions`): New default chat permissions. - use_independent_chat_permissions (:obj:`bool`, optional): Pass :obj:`True` if chat - permissions are set independently. Otherwise, the - :attr:`~telegram.ChatPermissions.can_send_other_messages` and - :attr:`~telegram.ChatPermissions.can_add_web_page_previews` permissions will imply - the :attr:`~telegram.ChatPermissions.can_send_messages`, - :attr:`~telegram.ChatPermissions.can_send_audios`, - :attr:`~telegram.ChatPermissions.can_send_documents`, - :attr:`~telegram.ChatPermissions.can_send_photos`, - :attr:`~telegram.ChatPermissions.can_send_videos`, - :attr:`~telegram.ChatPermissions.can_send_video_notes`, and - :attr:`~telegram.ChatPermissions.can_send_voice_notes` permissions; the - :attr:`~telegram.ChatPermissions.can_send_polls` permission will imply the - :attr:`~telegram.ChatPermissions.can_send_messages` permission. - - .. versionadded: 20.1 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "permissions": permissions, - "use_independent_chat_permissions": use_independent_chat_permissions, - } - return await self._post( - "setChatPermissions", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to set a custom title for administrators promoted by the bot in a - supergroup. The bot must be an administrator for this to work. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - user_id (:obj:`int`): Unique identifier of the target administrator. - custom_title (:obj:`str`): New custom title for the administrator; - 0-:tg-const:`telegram.constants.ChatLimit.CHAT_ADMINISTRATOR_CUSTOM_TITLE_LENGTH` - characters, emoji are not allowed. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "user_id": user_id, "custom_title": custom_title} - - return await self._post( - "setChatAdministratorCustomTitle", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> str: - """ - Use this method to generate a new primary invite link for a chat; any previously generated - link is revoked. The bot must be an administrator in the chat for this to work and must - have the appropriate admin rights. - - Note: - Each administrator in a chat generates their own invite links. Bots can't use invite - links generated by other administrators. If you want your bot to work with invite - links, it will need to generate its own link using :meth:`export_chat_invite_link` or - by calling the :meth:`get_chat` method. If your bot needs to generate a new primary - invite link replacing its previous one, use :meth:`export_chat_invite_link` again. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - - Returns: - :obj:`str`: New invite link on success. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - return await self._post( - "exportChatInviteLink", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> ChatInviteLink: - """ - Use this method to create an additional invite link for a chat. The bot must be an - administrator in the chat for this to work and must have the appropriate admin rights. - The link can be revoked using the method :meth:`revoke_chat_invite_link`. - - Note: - When joining *public* groups via an invite link, Telegram clients may display the - usual "Join" button, effectively ignoring the invite link. In particular, the parameter - :paramref:`creates_join_request` has no effect in this case. - However, this behavior is undocument and may be subject to change. - See `this GitHub thread `_ - for some discussion. - - .. versionadded:: 13.4 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will - expire. Integer input will be interpreted as Unix timestamp. - |tz-naive-dtms| - member_limit (:obj:`int`, optional): Maximum number of users that can be members of - the chat simultaneously after joining the chat via this invite link; - :tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`- - :tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`. - name (:obj:`str`, optional): Invite link name; - 0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters. - - .. versionadded:: 13.8 - creates_join_request (:obj:`bool`, optional): :obj:`True`, if users joining the chat - via the link need to be approved by chat administrators. - If :obj:`True`, :paramref:`member_limit` can't be specified. - - .. versionadded:: 13.8 - - Returns: - :class:`telegram.ChatInviteLink` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "expire_date": expire_date, - "member_limit": member_limit, - "name": name, - "creates_join_request": creates_join_request, - } - - result = await self._post( - "createChatInviteLink", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return ChatInviteLink.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> ChatInviteLink: - """ - Use this method to edit a non-primary invite link created by the bot. The bot must be an - administrator in the chat for this to work and must have the appropriate admin rights. - - Note: - Though not stated explicitly in the official docs, Telegram changes not only the - optional parameters that are explicitly passed, but also replaces all other optional - parameters to the default values. However, since not documented, this behaviour may - change unbeknown to PTB. - - .. versionadded:: 13.4 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - invite_link (:obj:`str` | :class:`telegram.ChatInviteLink`): The invite link to edit. - - .. versionchanged:: 20.0 - Now also accepts :class:`telegram.ChatInviteLink` instances. - expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will - expire. - |tz-naive-dtms| - member_limit (:obj:`int`, optional): Maximum number of users that can be members of - the chat simultaneously after joining the chat via this invite link; - :tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`- - :tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`. - name (:obj:`str`, optional): Invite link name; - 0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters. - - .. versionadded:: 13.8 - creates_join_request (:obj:`bool`, optional): :obj:`True`, if users joining the chat - via the link need to be approved by chat administrators. - If :obj:`True`, :paramref:`member_limit` can't be specified. - - .. versionadded:: 13.8 - - Returns: - :class:`telegram.ChatInviteLink` - - Raises: - :class:`telegram.error.TelegramError` - - """ - link = invite_link.invite_link if isinstance(invite_link, ChatInviteLink) else invite_link - data: JSONDict = { - "chat_id": chat_id, - "invite_link": link, - "expire_date": expire_date, - "member_limit": member_limit, - "name": name, - "creates_join_request": creates_join_request, - } - - result = await self._post( - "editChatInviteLink", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return ChatInviteLink.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> ChatInviteLink: - """ - Use this method to revoke an invite link created by the bot. If the primary link is - revoked, a new link is automatically generated. The bot must be an administrator in the - chat for this to work and must have the appropriate admin rights. - - .. versionadded:: 13.4 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - invite_link (:obj:`str` | :class:`telegram.ChatInviteLink`): The invite link to revoke. - - .. versionchanged:: 20.0 - Now also accepts :class:`telegram.ChatInviteLink` instances. - - Returns: - :class:`telegram.ChatInviteLink` - - Raises: - :class:`telegram.error.TelegramError` - - """ - link = invite_link.invite_link if isinstance(invite_link, ChatInviteLink) else invite_link - data: JSONDict = {"chat_id": chat_id, "invite_link": link} - - result = await self._post( - "revokeChatInviteLink", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return ChatInviteLink.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> bool: - """Use this method to approve a chat join request. - - The bot must be an administrator in the chat for this to work and must have the - :attr:`telegram.ChatPermissions.can_invite_users` administrator right. - - .. versionadded:: 13.8 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - user_id (:obj:`int`): Unique identifier of the target user. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = {"chat_id": chat_id, "user_id": user_id} - - return await self._post( - "approveChatJoinRequest", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method to decline a chat join request. - - The bot must be an administrator in the chat for this to work and must have the - :attr:`telegram.ChatPermissions.can_invite_users` administrator right. - - .. versionadded:: 13.8 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - user_id (:obj:`int`): Unique identifier of the target user. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = {"chat_id": chat_id, "user_id": user_id} - - return await self._post( - "declineChatJoinRequest", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method to set a new profile photo for the chat. - - Photos can't be changed for private chats. The bot must be an administrator in the chat - for this to work and must have the appropriate admin rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - photo (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path`): New chat photo. - |uploadinput| - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - .. versionchanged:: 20.0 - File paths as input is also accepted for bots *not* running in - :paramref:`~telegram.Bot.local_mode`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "photo": self._parse_file_input(photo)} - return await self._post( - "setChatPhoto", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to delete a chat photo. Photos can't be changed for private chats. The bot - must be an administrator in the chat for this to work and must have the appropriate admin - rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - return await self._post( - "deleteChatPhoto", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to change the title of a chat. Titles can't be changed for private chats. - The bot must be an administrator in the chat for this to work and must have the appropriate - admin rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - title (:obj:`str`): New chat title, - :tg-const:`telegram.constants.ChatLimit.MIN_CHAT_TITLE_LENGTH`- - :tg-const:`telegram.constants.ChatLimit.MAX_CHAT_TITLE_LENGTH` characters. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "title": title} - return await self._post( - "setChatTitle", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to change the description of a group, a supergroup or a channel. The bot - must be an administrator in the chat for this to work and must have the appropriate admin - rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - description (:obj:`str`, optional): New chat description, - 0-:tg-const:`telegram.constants.ChatLimit.CHAT_DESCRIPTION_LENGTH` - characters. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "description": description} - - return await self._post( - "setChatDescription", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Changes the emoji status for a given user that previously allowed the bot to manage - their emoji status via the Mini App method - `requestEmojiStatusAccess `_ - . - - .. versionadded:: 21.8 - - Args: - user_id (:obj:`int`): Unique identifier of the target user - emoji_status_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of the - emoji status to set. Pass an empty string to remove the status. - emoji_status_expiration_date (Union[:obj:`int`, :obj:`datetime.datetime`], optional): - Expiration date of the emoji status, if any, as unix timestamp or - :class:`datetime.datetime` object. - |tz-naive-dtms| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "user_id": user_id, - "emoji_status_custom_emoji_id": emoji_status_custom_emoji_id, - "emoji_status_expiration_date": emoji_status_expiration_date, - } - return await self._post( - "setUserEmojiStatus", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to add a message to the list of pinned messages in a chat. If the - chat is not a private chat, the bot must be an administrator in the chat for this to work - and must have the :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` admin - right in a supergroup or :attr:`~telegram.ChatMemberAdministrator.can_edit_messages` admin - right in a channel. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - message_id (:obj:`int`): Identifier of a message to pin. - disable_notification (:obj:`bool`, optional): Pass :obj:`True`, if it is not necessary - to send a notification to all chat members about the new pinned message. - Notifications are always disabled in channels and private chats. - business_connection_id (:obj:`str`, optional): Unique identifier of the business - connection on behalf of which the message will be pinned. - - .. versionadded:: 21.5 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_id": message_id, - "disable_notification": disable_notification, - "business_connection_id": business_connection_id, - } - - return await self._post( - "pinChatMessage", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to remove a message from the list of pinned messages in a chat. If the - chat is not a private chat, the bot must be an administrator in the chat for this to work - and must have the :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` admin - right in a supergroup or :attr:`~telegram.ChatMemberAdministrator.can_edit_messages` admin - right in a channel. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - message_id (:obj:`int`, optional): Identifier of the message to unpin. Required if - :paramref:`business_connection_id` is specified. If not specified, - the most recent pinned message (by sending date) will be unpinned. - business_connection_id (:obj:`str`, optional): Unique identifier of the business - connection on behalf of which the message will be unpinned. - - .. versionadded:: 21.5 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_id": message_id, - "business_connection_id": business_connection_id, - } - - return await self._post( - "unpinChatMessage", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to clear the list of pinned messages in a chat. If the - chat is not a private chat, the bot must be an administrator in the chat for this - to work and must have the :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` - admin right in a supergroup or :attr:`~telegram.ChatMemberAdministrator.can_edit_messages` - admin right in a channel. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - return await self._post( - "unpinAllChatMessages", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> StickerSet: - """Use this method to get a sticker set. - - Args: - name (:obj:`str`): Name of the sticker set. - - Returns: - :class:`telegram.StickerSet` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"name": name} - result = await self._post( - "getStickerSet", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return StickerSet.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> tuple[Sticker, ...]: - """ - Use this method to get information about emoji stickers by their identifiers. - - .. versionchanged:: 20.0 - Returns a tuple instead of a list. - - Args: - custom_emoji_ids (Sequence[:obj:`str`]): Sequence of custom emoji identifiers. - At most :tg-const:`telegram.constants.CustomEmojiStickerLimit.\ -CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified. - - .. versionchanged:: 20.0 - |sequenceargs| - - Returns: - tuple[:class:`telegram.Sticker`] - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"custom_emoji_ids": custom_emoji_ids} - result = await self._post( - "getCustomEmojiStickers", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return Sticker.de_list(result, self) - - 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, - ) -> File: - """ - Use this method to upload a file with a sticker for later use in the - :meth:`create_new_sticker_set` and :meth:`add_sticker_to_set` methods (can be used multiple - times). - - .. versionchanged:: 20.5 - Removed deprecated parameter ``png_sticker``. - - Args: - user_id (:obj:`int`): User identifier of sticker file owner. - sticker (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \ - :obj:`bytes` | :class:`pathlib.Path`): A file with the sticker in the - ``".WEBP"``, ``".PNG"``, ``".TGS"`` or ``".WEBM"`` - format. See `here `_ for technical requirements - . |uploadinput| - - .. versionadded:: 20.2 - - sticker_format (:obj:`str`): Format of the sticker. Must be one of - :attr:`telegram.constants.StickerFormat.STATIC`, - :attr:`telegram.constants.StickerFormat.ANIMATED`, - :attr:`telegram.constants.StickerFormat.VIDEO`. - - .. versionadded:: 20.2 - - Returns: - :class:`telegram.File`: On success, the uploaded File is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "user_id": user_id, - "sticker": self._parse_file_input(sticker), - "sticker_format": sticker_format, - } - result = await self._post( - "uploadStickerFile", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return File.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> bool: - """ - Use this method to add a new sticker to a set created by the bot. The format of the added - sticker must match the format of the other stickers in the set. Emoji sticker sets can have - up to :tg-const:`telegram.constants.StickerSetLimit.MAX_EMOJI_STICKERS` stickers. Other - sticker sets can have up to - :tg-const:`telegram.constants.StickerSetLimit.MAX_STATIC_STICKERS` stickers. - - .. versionchanged:: 20.2 - Since Bot API 6.6, the parameter :paramref:`sticker` replace the parameters - ``png_sticker``, ``tgs_sticker``, ``webm_sticker``, ``emojis``, and ``mask_position``. - - .. versionchanged:: 20.5 - Removed deprecated parameters ``png_sticker``, ``tgs_sticker``, ``webm_sticker``, - ``emojis``, and ``mask_position``. - - Args: - user_id (:obj:`int`): User identifier of created sticker set owner. - name (:obj:`str`): Sticker set name. - sticker (:class:`telegram.InputSticker`): An object with information about the added - sticker. If exactly the same sticker had already been added to the set, then the - set isn't changed. - - .. versionadded:: 20.2 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "user_id": user_id, - "name": name, - "sticker": sticker, - } - - return await self._post( - "addStickerToSet", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method to move a sticker in a set created by the bot to a specific position. - - Args: - sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or - the sticker object. - - .. versionchanged:: 21.10 - Accepts also :class:`telegram.Sticker` instances. - position (:obj:`int`): New sticker position in the set, zero-based. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "sticker": sticker if isinstance(sticker, str) else sticker.file_id, - "position": position, - } - return await self._post( - "setStickerPositionInSet", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to create new sticker set owned by a user. - The bot will be able to edit the created sticker set thus created. - - .. versionchanged:: 20.0 - The parameter ``contains_masks`` has been removed. Use :paramref:`sticker_type` - instead. - - .. versionchanged:: 20.2 - Since Bot API 6.6, the parameters :paramref:`stickers` and :paramref:`sticker_format` - replace the parameters ``png_sticker``, ``tgs_sticker``,``webm_sticker``, ``emojis``, - and ``mask_position``. - - .. versionchanged:: 20.5 - Removed the deprecated parameters mentioned above and adjusted the order of the - parameters. - - .. versionremoved:: 21.2 - Removed the deprecated parameter ``sticker_format``. - - Args: - user_id (:obj:`int`): User identifier of created sticker set owner. - name (:obj:`str`): Short name of sticker set, to be used in t.me/addstickers/ URLs - (e.g., animals). Can contain only english letters, digits and underscores. - Must begin with a letter, can't contain consecutive underscores and - must end in "_by_". is case insensitive. - :tg-const:`telegram.constants.StickerLimit.MIN_NAME_AND_TITLE`- - :tg-const:`telegram.constants.StickerLimit.MAX_NAME_AND_TITLE` characters. - title (:obj:`str`): Sticker set title, - :tg-const:`telegram.constants.StickerLimit.MIN_NAME_AND_TITLE`- - :tg-const:`telegram.constants.StickerLimit.MAX_NAME_AND_TITLE` characters. - - stickers (Sequence[:class:`telegram.InputSticker`]): A sequence of - :tg-const:`telegram.constants.StickerSetLimit.MIN_INITIAL_STICKERS`- - :tg-const:`telegram.constants.StickerSetLimit.MAX_INITIAL_STICKERS` initial - stickers to be added to the sticker set. - - .. versionadded:: 20.2 - - sticker_type (:obj:`str`, optional): Type of stickers in the set, pass - :attr:`telegram.Sticker.REGULAR` or :attr:`telegram.Sticker.MASK`, or - :attr:`telegram.Sticker.CUSTOM_EMOJI`. By default, a regular sticker set is created - - .. versionadded:: 20.0 - - needs_repainting (:obj:`bool`, optional): Pass :obj:`True` if stickers in the sticker - set must be repainted to the color of text when used in messages, the accent color - if used as emoji status, white on chat photos, or another appropriate color based - on context; for custom emoji sticker sets only. - - .. versionadded:: 20.2 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "user_id": user_id, - "name": name, - "title": title, - "stickers": stickers, - "sticker_type": sticker_type, - "needs_repainting": needs_repainting, - } - - return await self._post( - "createNewStickerSet", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method to delete a sticker from a set created by the bot. - - Args: - sticker (:obj:`str` | :class:`telegram.Sticker`): File identifier of the sticker or - the sticker object. - - .. versionchanged:: 21.10 - Accepts also :class:`telegram.Sticker` instances. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"sticker": sticker if isinstance(sticker, str) else sticker.file_id} - return await self._post( - "deleteStickerFromSet", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to delete a sticker set that was created by the bot. - - .. versionadded:: 20.2 - - Args: - name (:obj:`str`): Sticker set name. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"name": name} - return await self._post( - "deleteStickerSet", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Use this method to set the thumbnail of a regular or mask sticker set. The format of the - thumbnail file must match the format of the stickers in the set. - - .. versionadded:: 20.2 - - .. versionchanged:: 21.1 - As per Bot API 7.2, the new argument :paramref:`format` will be required, and thus the - order of the arguments had to be changed. - - Args: - name (:obj:`str`): Sticker set name - user_id (:obj:`int`): User identifier of created sticker set owner. - format (:obj:`str`): Format of the added sticker, must be one of - :tg-const:`telegram.constants.StickerFormat.STATIC` for a - ``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED` - for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a - WEBM video. - - .. versionadded:: 21.1 - - thumbnail (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \ - :obj:`bytes` | :class:`pathlib.Path`, optional): A **.WEBP** or **.PNG** image - with the thumbnail, must - be up to :tg-const:`telegram.constants.StickerSetLimit.MAX_STATIC_THUMBNAIL_SIZE` - kilobytes in size and have width and height of exactly - :tg-const:`telegram.constants.StickerSetLimit.STATIC_THUMB_DIMENSIONS` px, or a - **.TGS** animation with the thumbnail up to - :tg-const:`telegram.constants.StickerSetLimit.MAX_ANIMATED_THUMBNAIL_SIZE` - kilobytes in size; see - `the docs `_ for - animated sticker technical requirements, or a **.WEBM** video with the thumbnail up - to :tg-const:`telegram.constants.StickerSetLimit.MAX_ANIMATED_THUMBNAIL_SIZE` - kilobytes in size; see - `this `_ for video sticker - technical requirements. - - |fileinput| - - Animated and video sticker set thumbnails can't be uploaded via HTTP URL. If - omitted, then the thumbnail is dropped and the first sticker is used as the - thumbnail. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "name": name, - "user_id": user_id, - "thumbnail": self._parse_file_input(thumbnail) if thumbnail else None, - "format": format, - } - - return await self._post( - "setStickerSetThumbnail", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to set the title of a created sticker set. - - .. versionadded:: 20.2 - - Args: - name (:obj:`str`): Sticker set name. - title (:obj:`str`): Sticker set title, - :tg-const:`telegram.constants.StickerLimit.MIN_NAME_AND_TITLE`- - :tg-const:`telegram.constants.StickerLimit.MAX_NAME_AND_TITLE` characters. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"name": name, "title": title} - return await self._post( - "setStickerSetTitle", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to change the list of emoji assigned to a regular or custom emoji sticker. - The sticker must belong to a sticker set created by the bot. - - .. versionadded:: 20.2 - - Args: - sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or - the sticker object. - - .. versionchanged:: 21.10 - Accepts also :class:`telegram.Sticker` instances. - emoji_list (Sequence[:obj:`str`]): A sequence of - :tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI`- - :tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with - the sticker. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "sticker": sticker if isinstance(sticker, str) else sticker.file_id, - "emoji_list": emoji_list, - } - return await self._post( - "setStickerEmojiList", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to change search keywords assigned to a regular or custom emoji sticker. - The sticker must belong to a sticker set created by the bot. - - .. versionadded:: 20.2 - - Args: - sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or - the sticker object. - - .. versionchanged:: 21.10 - Accepts also :class:`telegram.Sticker` instances. - keywords (Sequence[:obj:`str`]): A sequence of - 0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords - for the sticker with total length up to - :tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "sticker": sticker if isinstance(sticker, str) else sticker.file_id, - "keywords": keywords, - } - return await self._post( - "setStickerKeywords", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to change the mask position of a mask sticker. - The sticker must belong to a sticker set that was created by the bot. - - .. versionadded:: 20.2 - - Args: - sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or - the sticker object. - - .. versionchanged:: 21.10 - Accepts also :class:`telegram.Sticker` instances. - mask_position (:class:`telegram.MaskPosition`, optional): A object with the position - where the mask should be placed on faces. Omit the parameter to remove the mask - position. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "sticker": sticker if isinstance(sticker, str) else sticker.file_id, - "mask_position": mask_position, - } - return await self._post( - "setStickerMaskPosition", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to set the thumbnail of a custom emoji sticker set. - - .. versionadded:: 20.2 - - Args: - name (:obj:`str`): Sticker set name. - custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of a sticker from the - sticker set; pass an empty string to drop the thumbnail and use the first sticker - as the thumbnail. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"name": name, "custom_emoji_id": custom_emoji_id} - - return await self._post( - "setCustomEmojiStickerSetThumbnail", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Informs a user that some of the Telegram Passport elements they provided contains errors. - The user will not be able to re-submit their Passport to you until the errors are fixed - (the contents of the field for which you returned the error must change). - - Use this if the data submitted by the user doesn't satisfy the standards your service - requires for any reason. For example, if a birthday date seems invalid, a submitted - document is blurry, a scan shows evidence of tampering, etc. Supply some details in the - error message to make sure the user knows how to correct the issues. - - Args: - user_id (:obj:`int`): User identifier - errors (Sequence[:class:`PassportElementError`]): A Sequence describing the errors. - - .. versionchanged:: 20.0 - |sequenceargs| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"user_id": user_id, "errors": errors} - return await self._post( - "setPassportDataErrors", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - *, - 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, - ) -> Message: - """ - Use this method to send a native poll. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`- - :tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters. - options (Sequence[:obj:`str` | :class:`telegram.InputPollOption`]): Sequence of - :tg-const:`telegram.Poll.MIN_OPTION_NUMBER`- - :tg-const:`telegram.Poll.MAX_OPTION_NUMBER` answer options. Each option may either - be a string with - :tg-const:`telegram.Poll.MIN_OPTION_LENGTH`- - :tg-const:`telegram.Poll.MAX_OPTION_LENGTH` characters or an - :class:`~telegram.InputPollOption` object. Strings are converted to - :class:`~telegram.InputPollOption` objects automatically. - - .. versionchanged:: 20.0 - |sequenceargs| - - .. versionchanged:: 21.2 - Bot API 7.3 adds support for :class:`~telegram.InputPollOption` objects. - is_anonymous (:obj:`bool`, optional): :obj:`True`, if the poll needs to be anonymous, - defaults to :obj:`True`. - type (:obj:`str`, optional): Poll type, :tg-const:`telegram.Poll.QUIZ` or - :tg-const:`telegram.Poll.REGULAR`, defaults to :tg-const:`telegram.Poll.REGULAR`. - allows_multiple_answers (:obj:`bool`, optional): :obj:`True`, if the poll allows - multiple answers, ignored for polls in quiz mode, defaults to :obj:`False`. - correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer - option, required for polls in quiz mode. - 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 with at most - :tg-const:`telegram.Poll.MAX_EXPLANATION_LINE_FEEDS` line feeds after entities - parsing. - explanation_parse_mode (:obj:`str`, optional): Mode for parsing entities in the - explanation. See the constants in :class:`telegram.constants.ParseMode` for the - available modes. - explanation_entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of - special entities that appear in message text, which can be specified instead of - :paramref:`explanation_parse_mode`. - - .. versionchanged:: 20.0 - |sequenceargs| - open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active - after creation, :tg-const:`telegram.Poll.MIN_OPEN_PERIOD`- - :tg-const:`telegram.Poll.MAX_OPEN_PERIOD`. Can't be used together with - :paramref:`close_date`. - close_date (:obj:`int` | :obj:`datetime.datetime`, optional): Point in time (Unix - timestamp) when the poll will be automatically closed. Must be at least - :tg-const:`telegram.Poll.MIN_OPEN_PERIOD` and no more than - :tg-const:`telegram.Poll.MAX_OPEN_PERIOD` seconds in the future. - Can't be used together with :paramref:`open_period`. - |tz-naive-dtms| - is_closed (:obj:`bool`, optional): Pass :obj:`True`, if the poll needs to be - immediately closed. This can be useful for poll preview. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - question_parse_mode (:obj:`str`, optional): Mode for parsing entities in the question. - See the constants in :class:`telegram.constants.ParseMode` for the available modes. - Currently, only custom emoji entities are allowed. - - .. versionadded:: 21.2 - question_entities (Sequence[:class:`telegram.Message`], optional): Special entities - that appear in the poll :paramref:`question`. It can be specified instead of - :paramref:`question_parse_mode`. - - .. versionadded:: 21.2 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "question": question, - "options": [ - InputPollOption(option) if isinstance(option, str) else option - for option in options - ], - "explanation_parse_mode": explanation_parse_mode, - "is_anonymous": is_anonymous, - "type": type, - "allows_multiple_answers": allows_multiple_answers, - "correct_option_id": correct_option_id, - "is_closed": is_closed, - "explanation": explanation, - "explanation_entities": explanation_entities, - "open_period": open_period, - "close_date": close_date, - "question_parse_mode": question_parse_mode, - "question_entities": question_entities, - } - - return await self._send_message( - "sendPoll", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - 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, - ) -> Poll: - """ - Use this method to stop a poll which was sent by the bot. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - message_id (:obj:`int`): Identifier of the original message with the poll. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new - message inline keyboard. - business_connection_id (:obj:`str`, optional): |business_id_str_edit| - - .. versionadded:: 21.4 - - Returns: - :class:`telegram.Poll`: On success, the stopped Poll is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_id": message_id, - "reply_markup": reply_markup, - "business_connection_id": business_connection_id, - } - - result = await self._post( - "stopPoll", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return Poll.de_json(result, self) # type: ignore[return-value] - - 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, - *, - 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, - ) -> Message: - """ - Use this method to send an animated emoji that will display a random value. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - disable_notification (:obj:`bool`, optional): |disable_notification| - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user - emoji (:obj:`str`, optional): Emoji on which the dice throw animation is based. - Currently, must be one of :class:`telegram.constants.DiceEmoji`. Dice can have - values - :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BOWLING` - for :tg-const:`telegram.Dice.DICE`, :tg-const:`telegram.Dice.DARTS` and - :tg-const:`telegram.Dice.BOWLING`, values - :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BASKETBALL` - for :tg-const:`telegram.Dice.BASKETBALL` and :tg-const:`telegram.Dice.FOOTBALL`, - and values :tg-const:`telegram.Dice.MIN_VALUE`- - :tg-const:`telegram.Dice.MAX_VALUE_SLOT_MACHINE` - for :tg-const:`telegram.Dice.SLOT_MACHINE`. Defaults to - :tg-const:`telegram.Dice.DICE`. - - .. versionchanged:: 13.4 - Added the :tg-const:`telegram.Dice.BOWLING` emoji. - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.1 - message_effect_id (:obj:`str`, optional): |message_effect_id| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "emoji": emoji} - - return await self._send_message( - "sendDice", - data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=reply_markup, - 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=api_kwargs, - business_connection_id=business_connection_id, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - ) - - 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, - ) -> ChatAdministratorRights: - """Use this method to get the current default administrator rights of the bot. - - .. seealso:: :meth:`set_my_default_administrator_rights` - - .. versionadded:: 20.0 - - Args: - for_channels (:obj:`bool`, optional): Pass :obj:`True` to get default administrator - rights of the bot in channels. Otherwise, default administrator rights of the bot - for groups and supergroups will be returned. - - Returns: - :class:`telegram.ChatAdministratorRights`: On success. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = {"for_channels": for_channels} - - result = await self._post( - "getMyDefaultAdministratorRights", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return ChatAdministratorRights.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> bool: - """Use this method to change the default administrator rights requested by the bot when - it's added as an administrator to groups or channels. These rights will be suggested to - users, but they are free to modify the list before adding the bot. - - .. seealso:: :meth:`get_my_default_administrator_rights` - - .. versionadded:: 20.0 - - Args: - rights (:class:`telegram.ChatAdministratorRights`, optional): A - :class:`telegram.ChatAdministratorRights` object describing new default - administrator - rights. If not specified, the default administrator rights will be cleared. - for_channels (:obj:`bool`, optional): Pass :obj:`True` to change the default - administrator rights of the bot in channels. Otherwise, the default administrator - rights of the bot for groups and supergroups will be changed. - - Returns: - :obj:`bool`: Returns :obj:`True` on success. - - Raises: - :exc:`telegram.error.TelegramError` - """ - data: JSONDict = {"rights": rights, "for_channels": for_channels} - - return await self._post( - "setMyDefaultAdministratorRights", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> tuple[BotCommand, ...]: - """ - Use this method to get the current list of the bot's commands for the given scope and user - language. - - .. seealso:: :meth:`set_my_commands`, :meth:`delete_my_commands` - - .. versionchanged:: 20.0 - Returns a tuple instead of a list. - - Args: - scope (:class:`telegram.BotCommandScope`, optional): An object, - describing scope of users. Defaults to :class:`telegram.BotCommandScopeDefault`. - - .. versionadded:: 13.7 - - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty - string. - - .. versionadded:: 13.7 - - Returns: - tuple[:class:`telegram.BotCommand`]: On success, the commands set for the bot. An empty - tuple is returned if commands are not set. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"scope": scope, "language_code": language_code} - - result = await self._post( - "getMyCommands", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return BotCommand.de_list(result, self) - - 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, - ) -> bool: - """ - Use this method to change the list of the bot's commands. See the - `Telegram docs `_ for more details about - bot commands. - - .. seealso:: :meth:`get_my_commands`, :meth:`delete_my_commands` - - Args: - commands (Sequence[:class:`BotCommand` | (:obj:`str`, :obj:`str`)]): A sequence - of bot commands to be set as the list of the bot's commands. At most - :tg-const:`telegram.constants.BotCommandLimit.MAX_COMMAND_NUMBER` commands can be - specified. - - Note: - If you pass in a sequence of :obj:`tuple`, the order of elements in each - :obj:`tuple` must correspond to the order of positional arguments to create a - :class:`BotCommand` instance. - - .. versionchanged:: 20.0 - |sequenceargs| - scope (:class:`telegram.BotCommandScope`, optional): An object, - describing scope of users for which the commands are relevant. Defaults to - :class:`telegram.BotCommandScopeDefault`. - - .. versionadded:: 13.7 - - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty, - commands will be applied to all users from the given scope, for whose language - there are no dedicated commands. - - .. versionadded:: 13.7 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - cmds = [c if isinstance(c, BotCommand) else BotCommand(c[0], c[1]) for c in commands] - data: JSONDict = {"commands": cmds, "scope": scope, "language_code": language_code} - - return await self._post( - "setMyCommands", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to delete the list of the bot's commands for the given scope and user - language. After deletion, - `higher level commands `_ - will be shown to affected users. - - .. versionadded:: 13.7 - - .. seealso:: :meth:`get_my_commands`, :meth:`set_my_commands` - - Args: - scope (:class:`telegram.BotCommandScope`, optional): An object, - describing scope of users for which the commands are relevant. Defaults to - :class:`telegram.BotCommandScopeDefault`. - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty, - commands will be applied to all users from the given scope, for whose language - there are no dedicated commands. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = {"scope": scope, "language_code": language_code} - - return await self._post( - "deleteMyCommands", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to log out from the cloud Bot API server before launching the bot locally. - You *must* log out the bot before running it locally, otherwise there is no guarantee that - the bot will receive updates. After a successful call, you can immediately log in on a - local server, but will not be able to log in back to the cloud Bot API server for 10 - minutes. - - Returns: - :obj:`True`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - return await self._post( - "logOut", - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to close the bot instance before moving it from one local server to - another. You need to delete the webhook before calling this method to ensure that the bot - isn't launched again after server restart. The method will return error 429 in the first - 10 minutes after the bot is launched. - - Returns: - :obj:`True`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - return await self._post( - "close", - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - *, - 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, - ) -> MessageId: - """Use this method to copy messages of any kind. Service messages, paid media messages, - giveaway messages, giveaway winners messages, and invoice messages - can't be copied. The method is analogous to the method :meth:`forward_message`, but the - copied message doesn't have a link to the original message. - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the - original message was sent (or channel username in the format ``@channelusername``). - message_id (:obj:`int`): Message identifier in the chat specified in from_chat_id. - caption (:obj:`str`, optional): New caption for media, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. If not specified, the original caption is kept. - parse_mode (:obj:`str`, optional): Mode for parsing entities in the new caption. See - the constants in :class:`telegram.constants.ParseMode` for the available modes. - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - - .. versionchanged:: 20.0 - |sequenceargs| - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. versionchanged:: 21.0 - |keyword_only_arg| - - Returns: - :class:`telegram.MessageId`: On success, the :class:`telegram.MessageId` of the sent - message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - if allow_sending_without_reply is not DEFAULT_NONE and reply_parameters is not None: - raise ValueError( - "`allow_sending_without_reply` and `reply_parameters` are mutually exclusive." - ) - - if reply_to_message_id is not None and reply_parameters is not None: - raise ValueError( - "`reply_to_message_id` and `reply_parameters` are mutually exclusive." - ) - - if reply_to_message_id is not None: - reply_parameters = ReplyParameters( - message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - ) - - data: JSONDict = { - "chat_id": chat_id, - "from_chat_id": from_chat_id, - "message_id": message_id, - "parse_mode": parse_mode, - "disable_notification": disable_notification, - "protect_content": protect_content, - "caption": caption, - "caption_entities": caption_entities, - "reply_markup": reply_markup, - "message_thread_id": message_thread_id, - "reply_parameters": reply_parameters, - "show_caption_above_media": show_caption_above_media, - "allow_paid_broadcast": allow_paid_broadcast, - } - - result = await self._post( - "copyMessage", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return MessageId.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> tuple["MessageId", ...]: - """ - Use this method to copy messages of any kind. If some of the specified messages can't be - found or copied, they are skipped. Service messages, paid media messages, giveaway - messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can - be copied only if the value - of the field :attr:`telegram.Poll.correct_option_id` is known to the bot. The method is - analogous to the method :meth:`forward_messages`, but the copied messages don't have a - link to the original message. Album grouping is kept for copied messages. - - .. versionadded:: 20.8 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the - original message was sent (or channel username in the format ``@channelusername``). - message_ids (Sequence[:obj:`int`]): A list of - :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT` - - :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages - in the chat :paramref:`from_chat_id` to copy. The identifiers must be - specified in a strictly increasing order. - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - remove_caption (:obj:`bool`, optional): Pass :obj:`True` to copy the messages without - their captions. - - Returns: - tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId` - of the sent messages is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "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, - } - - result = await self._post( - "copyMessages", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return MessageId.de_list(result, self) - - 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, - ) -> bool: - """Use this method to change the bot's menu button in a private chat, or the default menu - button. - - .. seealso:: :meth:`get_chat_menu_button`, :meth:`telegram.Chat.get_menu_button` - :meth:`telegram.User.get_menu_button` - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`, optional): Unique identifier for the target private chat. If not - specified, default bot's menu button will be changed - menu_button (:class:`telegram.MenuButton`, optional): An object for the new bot's menu - button. Defaults to :class:`telegram.MenuButtonDefault`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - data: JSONDict = {"chat_id": chat_id, "menu_button": menu_button} - - return await self._post( - "setChatMenuButton", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> MenuButton: - """Use this method to get the current value of the bot's menu button in a private chat, or - the default menu button. - - .. seealso:: :meth:`set_chat_menu_button`, :meth:`telegram.Chat.set_menu_button`, - :meth:`telegram.User.set_menu_button` - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int`, optional): Unique identifier for the target private chat. If not - specified, default bot's menu button will be returned. - - Returns: - :class:`telegram.MenuButton`: On success, the current menu button is returned. - - """ - data = {"chat_id": chat_id} - - result = await self._post( - "getChatMenuButton", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return MenuButton.de_json(result, bot=self) # type: ignore[return-value] - - async def create_invoice_link( - self, - title: str, - description: str, - payload: str, - provider_token: Optional[str], # This arg is now optional as of Bot API 7.4 - 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, - ) -> str: - """Use this method to create a link for an invoice. - - .. versionadded:: 20.0 - - Args: - business_connection_id (:obj:`str`, optional): |business_id_str| - For payments in |tg_stars| only. - - .. versionadded:: 21.8 - title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`- - :tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters. - description (:obj:`str`): Product description. - :tg-const:`telegram.Invoice.MIN_DESCRIPTION_LENGTH`- - :tg-const:`telegram.Invoice.MAX_DESCRIPTION_LENGTH` characters. - payload (:obj:`str`): Bot-defined invoice payload. - :tg-const:`telegram.Invoice.MIN_PAYLOAD_LENGTH`- - :tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be - displayed to the user, use it for your internal processes. - provider_token (:obj:`str`): Payments provider token, obtained via - `@BotFather `_. Pass an empty string for payments in - |tg_stars|. - - .. deprecated:: 21.3 - As of Bot API 7.4, this parameter is now optional and future versions of the - library will make it optional as well. - - currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies - `_. Pass ``XTR`` for - payments in |tg_stars|. - prices (Sequence[:class:`telegram.LabeledPrice`)]: Price breakdown, a sequence - of components (e.g. product price, tax, discount, delivery cost, delivery tax, - bonus, etc.). Must contain exactly one item for payments in |tg_stars|. - - .. versionchanged:: 20.0 - |sequenceargs| - subscription_period (:obj:`int` | :class:`datetime.timedelta`, optional): The time the - subscription will be active for before the next payment, either as number of - seconds or as :class:`datetime.timedelta` object. The currency must be set to - ``“XTR”`` (Telegram Stars) if the parameter is used. Currently, it must always be - :tg-const:`telegram.constants.InvoiceLimit.SUBSCRIPTION_PERIOD` if specified. Any - number of subscriptions can be active for a given bot at the same time, including - multiple concurrent subscriptions from the same user. Subscription price must - not exceed - :tg-const:`telegram.constants.InvoiceLimit.SUBSCRIPTION_MAX_PRICE` - Telegram Stars. - - .. versionadded:: 21.8 - max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the - *smallest units* of the currency (integer, **not** float/double). For example, for - a maximum tip of ``US$ 1.45`` pass ``max_tip_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). - Defaults to ``0``. Not supported for payments in |tg_stars|. - suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of - suggested amounts of tips in the *smallest units* of the currency (integer, **not** - float/double). At most :tg-const:`telegram.Invoice.MAX_TIP_AMOUNTS` suggested tip - amounts can be specified. The suggested tip amounts must be positive, passed in a - strictly increased order and must not exceed :paramref:`max_tip_amount`. - - .. versionchanged:: 20.0 - |sequenceargs| - provider_data (:obj:`str` | :obj:`object`, optional): Data about the - invoice, which will be shared with the payment provider. A detailed description of - required fields should be provided by the payment provider. When an object is - passed, it will be encoded as JSON. - photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a - photo of the goods or a marketing image for a service. - photo_size (:obj:`int`, optional): Photo size in bytes. - photo_width (:obj:`int`, optional): Photo width. - photo_height (:obj:`int`, optional): Photo height. - need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full - name to complete the order. Ignored for payments in |tg_stars|. - need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's - phone number to complete the order. Ignored for payments in |tg_stars|. - need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email - address to complete the order. Ignored for payments in |tg_stars|. - need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the - user's shipping address to complete the order. Ignored for payments in - |tg_stars|. - send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's - phone number should be sent to provider. Ignored for payments in |tg_stars|. - send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email - address should be sent to provider. Ignored for payments in |tg_stars|. - is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on - the shipping method. Ignored for payments in |tg_stars|. - - Returns: - :class:`str`: On success, the created invoice link is returned. - - """ - data: JSONDict = { - "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, - "is_flexible": is_flexible, - "send_phone_number_to_provider": send_phone_number_to_provider, - "send_email_to_provider": send_email_to_provider, - "subscription_period": ( - subscription_period.total_seconds() - if isinstance(subscription_period, dtm.timedelta) - else subscription_period - ), - "business_connection_id": business_connection_id, - } - - return await self._post( - "createInvoiceLink", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> tuple[Sticker, ...]: - """Use this method to get custom emoji stickers, which can be used as a forum topic - icon by any user. Requires no parameters. - - .. versionadded:: 20.0 - - Returns: - tuple[:class:`telegram.Sticker`] - - Raises: - :class:`telegram.error.TelegramError` - - """ - result = await self._post( - "getForumTopicIconStickers", - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return Sticker.de_list(result, self) - - 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, - ) -> ForumTopic: - """ - Use this method to create a topic in a forum supergroup chat. The bot must be - an administrator in the chat for this to work and must have - :paramref:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - name (:obj:`str`): New topic name, - :tg-const:`telegram.constants.ForumTopicLimit.MIN_NAME_LENGTH`- - :tg-const:`telegram.constants.ForumTopicLimit.MAX_NAME_LENGTH` characters. - icon_color (:obj:`int`, optional): Color of the topic icon in RGB format. Currently, - must be one of :attr:`telegram.constants.ForumIconColor.BLUE`, - :attr:`telegram.constants.ForumIconColor.YELLOW`, - :attr:`telegram.constants.ForumIconColor.PURPLE`, - :attr:`telegram.constants.ForumIconColor.GREEN`, - :attr:`telegram.constants.ForumIconColor.PINK`, or - :attr:`telegram.constants.ForumIconColor.RED`. - icon_custom_emoji_id (:obj:`str`, optional): New unique identifier of the custom emoji - shown as the topic icon. Use :meth:`~telegram.Bot.get_forum_topic_icon_stickers` - to get all allowed custom emoji identifiers. - - Returns: - :class:`telegram.ForumTopic` - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "chat_id": chat_id, - "name": name, - "icon_color": icon_color, - "icon_custom_emoji_id": icon_custom_emoji_id, - } - result = await self._post( - "createForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - return ForumTopic.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> bool: - """ - Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must - be an administrator in the chat for this to work and must have the - :paramref:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights, - unless it is the creator of the topic. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - message_thread_id (:obj:`int`): |message_thread_id| - name (:obj:`str`, optional): New topic name, - :tg-const:`telegram.constants.ForumTopicLimit.MIN_NAME_LENGTH`- - :tg-const:`telegram.constants.ForumTopicLimit.MAX_NAME_LENGTH` characters. If - not specified or empty, the current name of the topic will be kept. - icon_custom_emoji_id (:obj:`str`, optional): New unique identifier of the custom emoji - shown as the topic icon. Use :meth:`~telegram.Bot.get_forum_topic_icon_stickers` - to get all allowed custom emoji identifiers.Pass an empty string to remove the - icon. If not specified, the current icon will be kept. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_thread_id": message_thread_id, - "name": name, - "icon_custom_emoji_id": icon_custom_emoji_id, - } - return await self._post( - "editForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to close an open topic in a forum supergroup chat. The bot must - be an administrator in the chat for this to work and must have - :paramref:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights, - unless it is the creator of the topic. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - message_thread_id (:obj:`int`): |message_thread_id| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_thread_id": message_thread_id, - } - return await self._post( - "closeForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to reopen a closed topic in a forum supergroup chat. The bot must - be an administrator in the chat for this to work and must have - :paramref:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights, - unless it is the creator of the topic. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - message_thread_id (:obj:`int`): |message_thread_id| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_thread_id": message_thread_id, - } - return await self._post( - "reopenForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to delete a forum topic along with all its messages in a forum supergroup - chat. The bot must be an administrator in the chat for this to work and must have - :paramref:`~telegram.ChatAdministratorRights.can_delete_messages` administrator rights. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - message_thread_id (:obj:`int`): |message_thread_id| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_thread_id": message_thread_id, - } - return await self._post( - "deleteForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to clear the list of pinned messages in a forum topic. The bot must - be an administrator in the chat for this to work and must have - :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` administrator rights - in the supergroup. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - message_thread_id (:obj:`int`): |message_thread_id| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "message_thread_id": message_thread_id, - } - return await self._post( - "unpinAllForumTopicMessages", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to clear the list of pinned messages in a General forum topic. The bot must - be an administrator in the chat for this to work and must have - :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` administrator rights in the - supergroup. - - .. versionadded:: 20.5 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = {"chat_id": chat_id} - - return await self._post( - "unpinAllGeneralForumTopicMessages", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot - must be an administrator in the chat for this to work and must have the - :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - name (:obj:`str`): New topic name, - :tg-const:`telegram.constants.ForumTopicLimit.MIN_NAME_LENGTH`- - :tg-const:`telegram.constants.ForumTopicLimit.MAX_NAME_LENGTH` characters. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id, "name": name} - - return await self._post( - "editGeneralForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to close an open 'General' topic in a forum supergroup chat. The bot must - be an administrator in the chat for this to work and must have - :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - - return await self._post( - "closeGeneralForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must - be an administrator in the chat for this to work and must have - :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights. - The topic will be automatically unhidden if it was hidden. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - - return await self._post( - "reopenGeneralForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to hide the 'General' topic in a forum supergroup chat. The bot must - be an administrator in the chat for this to work and must have - :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights. - The topic will be automatically closed if it was open. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - - return await self._post( - "hideGeneralForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must - be an administrator in the chat for this to work and must have - :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights. - - .. versionadded:: 20.0 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_group| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"chat_id": chat_id} - - return await self._post( - "unhideGeneralForumTopic", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to change the bot's description, which is shown in the chat with the bot - if the chat is empty. - - .. versionadded:: 20.2 - - Args: - description (:obj:`str`, optional): New bot description; - 0-:tg-const:`telegram.constants.BotDescriptionLimit.MAX_DESCRIPTION_LENGTH` - characters. Pass an empty string to remove the dedicated description for the given - language. - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty, - the description will be applied to all users for whose language there is no - dedicated description. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"description": description, "language_code": language_code} - - return await self._post( - "setMyDescription", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """ - Use this method to change the bot's short description, which is shown on the bot's profile - page and is sent together with the link when users share the bot. - - .. versionadded:: 20.2 - - Args: - short_description (:obj:`str`, optional): New short description for the bot; - 0-:tg-const:`telegram.constants.BotDescriptionLimit.MAX_SHORT_DESCRIPTION_LENGTH` - characters. Pass an empty string to remove the dedicated description for the given - language. - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty, - the description will be applied to all users for whose language there is no - dedicated description. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"short_description": short_description, "language_code": language_code} - - return await self._post( - "setMyShortDescription", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> BotDescription: - """ - Use this method to get the current bot description for the given user language. - - Args: - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty - string. - - Returns: - :class:`telegram.BotDescription`: On success, the bot description is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data = {"language_code": language_code} - return BotDescription.de_json( # type: ignore[return-value] - await self._post( - "getMyDescription", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ), - bot=self, - ) - - 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, - ) -> BotShortDescription: - """ - Use this method to get the current bot short description for the given user language. - - Args: - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty - string. - - Returns: - :class:`telegram.BotShortDescription`: On success, the bot short description is - returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data = {"language_code": language_code} - return BotShortDescription.de_json( # type: ignore[return-value] - await self._post( - "getMyShortDescription", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ), - bot=self, - ) - - 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, - ) -> bool: - """ - Use this method to change the bot's name. - - .. versionadded:: 20.3 - - Args: - name (:obj:`str`, optional): New bot name; - 0-:tg-const:`telegram.constants.BotNameLimit.MAX_NAME_LENGTH` - characters. Pass an empty string to remove the dedicated name for the given - language. - - Caution: - If :paramref:`language_code` is not specified, a :paramref:`name` *must* - be specified. - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty, - the name will be applied to all users for whose language there is no - dedicated name. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {"name": name, "language_code": language_code} - - return await self._post( - "setMyName", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> BotName: - """ - Use this method to get the current bot name for the given user language. - - Args: - language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty - string. - - Returns: - :class:`telegram.BotName`: On success, the bot name is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data = {"language_code": language_code} - return BotName.de_json( # type: ignore[return-value] - await self._post( - "getMyName", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ), - bot=self, - ) - - 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, - ) -> UserChatBoosts: - """ - Use this method to get the list of boosts added to a chat by a user. Requires - administrator rights in the chat. - - .. versionadded:: 20.8 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - user_id (:obj:`int`): Unique identifier of the target user. - - Returns: - :class:`telegram.UserChatBoosts`: On success, the object containing the list of boosts - is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = {"chat_id": chat_id, "user_id": user_id} - return UserChatBoosts.de_json( # type: ignore[return-value] - await self._post( - "getUserChatBoosts", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ), - bot=self, - ) - - 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, - ) -> bool: - """ - Use this method to change the chosen reactions on a message. Service messages can't be - reacted to. Automatically forwarded messages from a channel to its discussion group have - the same available reactions as messages in the channel. Bots can't use paid reactions. - - .. versionadded:: 20.8 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - message_id (:obj:`int`): Identifier of the target message. If the message belongs to a - media group, the reaction is set to the first non-deleted message in the group - instead. - reaction (Sequence[:class:`telegram.ReactionType` | :obj:`str`] | \ - :class:`telegram.ReactionType` | :obj:`str`, optional): A list of reaction - types to set on the message. Currently, as non-premium users, bots can set up to - one reaction per message. A custom emoji reaction can be used if it is either - already present on the message or explicitly allowed by chat administrators. Paid - reactions can't be used by bots. - - Tip: - Passed :obj:`str` values will be converted to either - :class:`telegram.ReactionTypeEmoji` or - :class:`telegram.ReactionTypeCustomEmoji` - depending on whether they are listed in - :class:`~telegram.constants.ReactionEmoji`. - - is_big (:obj:`bool`, optional): Pass :obj:`True` to set the reaction with a big - animation. - - Returns: - :obj:`bool` On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - allowed_reactions: set[str] = set(ReactionEmoji) - parsed_reaction = ( - [ - ( - entry - if isinstance(entry, ReactionType) - else ( - ReactionTypeEmoji(emoji=entry) - if entry in allowed_reactions - else ReactionTypeCustomEmoji(custom_emoji_id=entry) - ) - ) - for entry in ( - [reaction] if isinstance(reaction, (ReactionType, str)) else reaction - ) - ] - if reaction is not None - else None - ) - - data: JSONDict = { - "chat_id": chat_id, - "message_id": message_id, - "reaction": parsed_reaction, - "is_big": is_big, - } - - return await self._post( - "setMessageReaction", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> BusinessConnection: - """ - Use this method to get information about the connection of the bot with a business account. - - .. versionadded:: 21.1 - - Args: - business_connection_id (:obj:`str`): Unique identifier of the business connection. - - Returns: - :class:`telegram.BusinessConnection`: On success, the object containing the business - connection information is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = {"business_connection_id": business_connection_id} - return BusinessConnection.de_json( # type: ignore[return-value] - await self._post( - "getBusinessConnection", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ), - bot=self, - ) - - 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, - ) -> bool: - """Use this method to replace an existing sticker in a sticker set with a new one. - The method is equivalent to calling :meth:`delete_sticker_from_set`, - then :meth:`add_sticker_to_set`, then :meth:`set_sticker_position_in_set`. - - .. versionadded:: 21.1 - - Args: - user_id (:obj:`int`): User identifier of the sticker set owner. - name (:obj:`str`): Sticker set name. - old_sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the replaced - sticker or the sticker object itself. - - .. versionchanged:: 21.10 - Accepts also :class:`telegram.Sticker` instances. - sticker (:class:`telegram.InputSticker`): An object with information about the added - sticker. If exactly the same sticker had already been added to the set, then the - set remains unchanged. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "user_id": user_id, - "name": name, - "old_sticker": old_sticker if isinstance(old_sticker, str) else old_sticker.file_id, - "sticker": sticker, - } - - return await self._post( - "replaceStickerInSet", - data, - 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, - 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, - ) -> bool: - """Refunds a successful payment in |tg_stars|. - - .. versionadded:: 21.3 - - Args: - user_id (:obj:`int`): User identifier of the user whose payment will be refunded. - telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "user_id": user_id, - "telegram_payment_charge_id": telegram_payment_charge_id, - } - - return await self._post( - "refundStarPayment", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> StarTransactions: - """Returns the bot's Telegram Star transactions in chronological order. - - .. versionadded:: 21.4 - - Args: - offset (:obj:`int`, optional): Number of transactions to skip in the response. - limit (:obj:`int`, optional): The maximum number of transactions to be retrieved. - Values between :tg-const:`telegram.constants.StarTransactionsLimit.MIN_LIMIT`- - :tg-const:`telegram.constants.StarTransactionsLimit.MAX_LIMIT` are accepted. - Defaults to :tg-const:`telegram.constants.StarTransactionsLimit.MAX_LIMIT`. - - Returns: - :class:`telegram.StarTransactions`: On success. - - Raises: - :class:`telegram.error.TelegramError` - """ - - data: JSONDict = {"offset": offset, "limit": limit} - - return StarTransactions.de_json( # type: ignore[return-value] - await self._post( - "getStarTransactions", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ), - bot=self, - ) - - 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, - ) -> bool: - """Allows the bot to cancel or re-enable extension of a subscription paid in Telegram - Stars. - - .. versionadded:: 21.8 - - Args: - user_id (:obj:`int`): Identifier of the user whose subscription will be edited. - telegram_payment_charge_id (:obj:`str`): Telegram payment identifier for the - subscription. - is_canceled (:obj:`bool`): Pass :obj:`True` to cancel extension of the user - subscription; the subscription must be active up to the end of the current - subscription period. Pass :obj:`False` to allow the user to re-enable a - subscription that was previously canceled by the bot. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "user_id": user_id, - "telegram_payment_charge_id": telegram_payment_charge_id, - "is_canceled": is_canceled, - } - return await self._post( - "editUserStartSubscription", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> Message: - """Use this method to send paid media. - - .. versionadded:: 21.4 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| If the chat is a channel, all - Telegram Star proceeds from this media will be credited to the chat's balance. - Otherwise, they will be credited to the bot's balance. - star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access - to the media; :tg-const:`telegram.constants.InvoiceLimit.MIN_STAR_COUNT` - - :tg-const:`telegram.constants.InvoiceLimit.MAX_STAR_COUNT`. - media (Sequence[:class:`telegram.InputPaidMedia`]): A list describing the media to be - sent; up to :tg-const:`telegram.constants.MediaGroupLimit.MAX_MEDIA_LENGTH` items. - payload (:obj:`str`, optional): Bot-defined paid media payload, - 0-:tg-const:`telegram.constants.InvoiceLimit.MAX_PAYLOAD_LENGTH` bytes. This will - not be displayed to the user, use it for your internal processes. - - .. versionadded:: 21.6 - caption (:obj:`str`, optional): Caption of the media to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): - |caption_entities| - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - business_connection_id (:obj:`str`, optional): |business_id_str| - - .. versionadded:: 21.5 - allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| - - .. versionadded:: 21.7 - - Keyword Args: - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience - parameter for - - Returns: - :class:`telegram.Message`: On success, the sent message is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - - data: JSONDict = { - "chat_id": chat_id, - "star_count": star_count, - "media": media, - "show_caption_above_media": show_caption_above_media, - "payload": payload, - } - - return await self._send_message( - "sendPaidMedia", - data, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - 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=api_kwargs, - business_connection_id=business_connection_id, - 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, - ) -> ChatInviteLink: - """ - Use this method to create a `subscription invite link `_ for a channel chat. - The bot must have the :attr:`~telegram.ChatPermissions.can_invite_users` administrator - right. The link can be edited using the :meth:`edit_chat_subscription_invite_link` or - revoked using the :meth:`revoke_chat_invite_link`. - - .. versionadded:: 21.5 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - subscription_period (:obj:`int`): The number of seconds the subscription will be - active for before the next payment. Currently, it must always be - :tg-const:`telegram.constants.ChatSubscriptionLimit.SUBSCRIPTION_PERIOD` (30 days). - subscription_price (:obj:`int`): The number of Telegram Stars a user must pay initially - and after each subsequent subscription period to be a member of the chat; - :tg-const:`telegram.constants.ChatSubscriptionLimit.MIN_PRICE`- - :tg-const:`telegram.constants.ChatSubscriptionLimit.MAX_PRICE`. - name (:obj:`str`, optional): Invite link name; - 0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters. - - Returns: - :class:`telegram.ChatInviteLink` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - "chat_id": chat_id, - "subscription_period": subscription_period, - "subscription_price": subscription_price, - "name": name, - } - - result = await self._post( - "createChatSubscriptionInviteLink", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return ChatInviteLink.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> ChatInviteLink: - """ - Use this method to edit a subscription invite link created by the bot. The bot must have - :attr:`telegram.ChatPermissions.can_invite_users` administrator right. - - .. versionadded:: 21.5 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - invite_link (:obj:`str` | :obj:`telegram.ChatInviteLink`): The invite link to edit. - name (:obj:`str`, optional): Invite link name; - 0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters. - - Tip: - Omitting this argument removes the name of the invite link. - - Returns: - :class:`telegram.ChatInviteLink` - - Raises: - :class:`telegram.error.TelegramError` - - """ - link = invite_link.invite_link if isinstance(invite_link, ChatInviteLink) else invite_link - data: JSONDict = { - "chat_id": chat_id, - "invite_link": link, - "name": name, - } - - result = await self._post( - "editChatSubscriptionInviteLink", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - return ChatInviteLink.de_json(result, self) # type: ignore[return-value] - - 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, - ) -> Gifts: - """Returns the list of gifts that can be sent by the bot to users. - Requires no parameters. - - .. versionadded:: 21.8 - - Returns: - :class:`telegram.Gifts` - - Raises: - :class:`telegram.error.TelegramError` - """ - return Gifts.de_json( # type: ignore[return-value] - await self._post( - "getAvailableGifts", - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - ) - - 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, - ) -> bool: - """Sends a gift to the given user. - The gift can't be converted to Telegram Stars by the user - - .. versionadded:: 21.8 - - Args: - user_id (:obj:`int`): Unique identifier of the target user that will receive the gift - gift_id (:obj:`str` | :class:`~telegram.Gift`): Identifier of the gift or a - :class:`~telegram.Gift` object - text (:obj:`str`, optional): Text that will be shown along with the gift; - 0- :tg-const:`telegram.constants.GiftLimit.MAX_TEXT_LENGTH` characters - text_parse_mode (:obj:`str`, optional): Mode for parsing entities. - See :class:`telegram.constants.ParseMode` and - `formatting options `__ for - more details. Entities other than :attr:`~MessageEntity.BOLD`, - :attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`, - :attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and - :attr:`~MessageEntity.CUSTOM_EMOJI` are ignored. - text_entities (Sequence[:class:`telegram.MessageEntity`], optional): A list of special - entities that appear in the gift text. It can be specified instead of - :paramref:`text_parse_mode`. Entities other than :attr:`~MessageEntity.BOLD`, - :attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`, - :attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and - :attr:`~MessageEntity.CUSTOM_EMOJI` are ignored. - pay_for_upgrade (:obj:`bool`, optional): Pass :obj:`True` to pay for the gift upgrade - from the bot's balance, thereby making the upgrade free for the receiver. - - .. versionadded:: 21.10 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "user_id": user_id, - "gift_id": gift_id.id if isinstance(gift_id, Gift) else gift_id, - "text": text, - "text_parse_mode": text_parse_mode, - "text_entities": text_entities, - "pay_for_upgrade": pay_for_upgrade, - } - return await self._post( - "sendGift", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Verifies a chat on behalf of the organization which is represented by the bot. - - .. versionadded:: 21.10 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - custom_description (:obj:`str`, optional): Custom description for the verification; - 0- :tg-const:`telegram.constants.VerifyLimit.MAX_TEXT_LENGTH` characters. Must be - empty if the organization isn't allowed to provide a custom verification - description. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "chat_id": chat_id, - "custom_description": custom_description, - } - return await self._post( - "verifyChat", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Verifies a user on behalf of the organization which is represented by the bot. - - .. versionadded:: 21.10 - - Args: - user_id (:obj:`int`): Unique identifier of the target user. - custom_description (:obj:`str`, optional): Custom description for the verification; - 0- :tg-const:`telegram.constants.VerifyLimit.MAX_TEXT_LENGTH` characters. Must be - empty if the organization isn't allowed to provide a custom verification - description. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "user_id": user_id, - "custom_description": custom_description, - } - return await self._post( - "verifyUser", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Removes verification from a chat that is currently verified on behalf of the - organization represented by the bot. - - - - .. versionadded:: 21.10 - - Args: - chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "chat_id": chat_id, - } - return await self._post( - "removeChatVerification", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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, - ) -> bool: - """Removes verification from a user who is currently verified on behalf of the - organization represented by the bot. - - - - .. versionadded:: 21.10 - - Args: - user_id (:obj:`int`): Unique identifier of the target user. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - "user_id": user_id, - } - return await self._post( - "removeUserVerification", - data, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002 - """See :meth:`telegram.TelegramObject.to_dict`.""" - data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name} - - if self.last_name: - data["last_name"] = self.last_name - - return data - - # camelCase aliases - getMe = get_me - """Alias for :meth:`get_me`""" - sendMessage = send_message - """Alias for :meth:`send_message`""" - deleteMessage = delete_message - """Alias for :meth:`delete_message`""" - deleteMessages = delete_messages - """Alias for :meth:`delete_messages`""" - forwardMessage = forward_message - """Alias for :meth:`forward_message`""" - forwardMessages = forward_messages - """Alias for :meth:`forward_messages`""" - sendPhoto = send_photo - """Alias for :meth:`send_photo`""" - sendAudio = send_audio - """Alias for :meth:`send_audio`""" - sendDocument = send_document - """Alias for :meth:`send_document`""" - sendSticker = send_sticker - """Alias for :meth:`send_sticker`""" - sendVideo = send_video - """Alias for :meth:`send_video`""" - sendAnimation = send_animation - """Alias for :meth:`send_animation`""" - sendVoice = send_voice - """Alias for :meth:`send_voice`""" - sendVideoNote = send_video_note - """Alias for :meth:`send_video_note`""" - sendMediaGroup = send_media_group - """Alias for :meth:`send_media_group`""" - sendLocation = send_location - """Alias for :meth:`send_location`""" - editMessageLiveLocation = edit_message_live_location - """Alias for :meth:`edit_message_live_location`""" - stopMessageLiveLocation = stop_message_live_location - """Alias for :meth:`stop_message_live_location`""" - sendVenue = send_venue - """Alias for :meth:`send_venue`""" - sendContact = send_contact - """Alias for :meth:`send_contact`""" - sendGame = send_game - """Alias for :meth:`send_game`""" - sendChatAction = send_chat_action - """Alias for :meth:`send_chat_action`""" - answerInlineQuery = answer_inline_query - """Alias for :meth:`answer_inline_query`""" - savePreparedInlineMessage = save_prepared_inline_message - """Alias for :meth:`save_prepared_inline_message`""" - getUserProfilePhotos = get_user_profile_photos - """Alias for :meth:`get_user_profile_photos`""" - getFile = get_file - """Alias for :meth:`get_file`""" - banChatMember = ban_chat_member - """Alias for :meth:`ban_chat_member`""" - banChatSenderChat = ban_chat_sender_chat - """Alias for :meth:`ban_chat_sender_chat`""" - unbanChatMember = unban_chat_member - """Alias for :meth:`unban_chat_member`""" - unbanChatSenderChat = unban_chat_sender_chat - """Alias for :meth:`unban_chat_sender_chat`""" - answerCallbackQuery = answer_callback_query - """Alias for :meth:`answer_callback_query`""" - editMessageText = edit_message_text - """Alias for :meth:`edit_message_text`""" - editMessageCaption = edit_message_caption - """Alias for :meth:`edit_message_caption`""" - editMessageMedia = edit_message_media - """Alias for :meth:`edit_message_media`""" - editMessageReplyMarkup = edit_message_reply_markup - """Alias for :meth:`edit_message_reply_markup`""" - getUpdates = get_updates - """Alias for :meth:`get_updates`""" - setWebhook = set_webhook - """Alias for :meth:`set_webhook`""" - deleteWebhook = delete_webhook - """Alias for :meth:`delete_webhook`""" - leaveChat = leave_chat - """Alias for :meth:`leave_chat`""" - getChat = get_chat - """Alias for :meth:`get_chat`""" - getChatAdministrators = get_chat_administrators - """Alias for :meth:`get_chat_administrators`""" - getChatMember = get_chat_member - """Alias for :meth:`get_chat_member`""" - setChatStickerSet = set_chat_sticker_set - """Alias for :meth:`set_chat_sticker_set`""" - deleteChatStickerSet = delete_chat_sticker_set - """Alias for :meth:`delete_chat_sticker_set`""" - getChatMemberCount = get_chat_member_count - """Alias for :meth:`get_chat_member_count`""" - getWebhookInfo = get_webhook_info - """Alias for :meth:`get_webhook_info`""" - setGameScore = set_game_score - """Alias for :meth:`set_game_score`""" - getGameHighScores = get_game_high_scores - """Alias for :meth:`get_game_high_scores`""" - sendInvoice = send_invoice - """Alias for :meth:`send_invoice`""" - answerShippingQuery = answer_shipping_query - """Alias for :meth:`answer_shipping_query`""" - answerPreCheckoutQuery = answer_pre_checkout_query - """Alias for :meth:`answer_pre_checkout_query`""" - answerWebAppQuery = answer_web_app_query - """Alias for :meth:`answer_web_app_query`""" - restrictChatMember = restrict_chat_member - """Alias for :meth:`restrict_chat_member`""" - promoteChatMember = promote_chat_member - """Alias for :meth:`promote_chat_member`""" - setChatPermissions = set_chat_permissions - """Alias for :meth:`set_chat_permissions`""" - setChatAdministratorCustomTitle = set_chat_administrator_custom_title - """Alias for :meth:`set_chat_administrator_custom_title`""" - exportChatInviteLink = export_chat_invite_link - """Alias for :meth:`export_chat_invite_link`""" - createChatInviteLink = create_chat_invite_link - """Alias for :meth:`create_chat_invite_link`""" - editChatInviteLink = edit_chat_invite_link - """Alias for :meth:`edit_chat_invite_link`""" - revokeChatInviteLink = revoke_chat_invite_link - """Alias for :meth:`revoke_chat_invite_link`""" - approveChatJoinRequest = approve_chat_join_request - """Alias for :meth:`approve_chat_join_request`""" - declineChatJoinRequest = decline_chat_join_request - """Alias for :meth:`decline_chat_join_request`""" - setChatPhoto = set_chat_photo - """Alias for :meth:`set_chat_photo`""" - deleteChatPhoto = delete_chat_photo - """Alias for :meth:`delete_chat_photo`""" - setChatTitle = set_chat_title - """Alias for :meth:`set_chat_title`""" - setChatDescription = set_chat_description - """Alias for :meth:`set_chat_description`""" - setUserEmojiStatus = set_user_emoji_status - """Alias for :meth:`set_user_emoji_status`""" - pinChatMessage = pin_chat_message - """Alias for :meth:`pin_chat_message`""" - unpinChatMessage = unpin_chat_message - """Alias for :meth:`unpin_chat_message`""" - unpinAllChatMessages = unpin_all_chat_messages - """Alias for :meth:`unpin_all_chat_messages`""" - getCustomEmojiStickers = get_custom_emoji_stickers - """Alias for :meth:`get_custom_emoji_stickers`""" - getStickerSet = get_sticker_set - """Alias for :meth:`get_sticker_set`""" - uploadStickerFile = upload_sticker_file - """Alias for :meth:`upload_sticker_file`""" - createNewStickerSet = create_new_sticker_set - """Alias for :meth:`create_new_sticker_set`""" - addStickerToSet = add_sticker_to_set - """Alias for :meth:`add_sticker_to_set`""" - setStickerPositionInSet = set_sticker_position_in_set - """Alias for :meth:`set_sticker_position_in_set`""" - deleteStickerFromSet = delete_sticker_from_set - """Alias for :meth:`delete_sticker_from_set`""" - setStickerSetThumbnail = set_sticker_set_thumbnail - """Alias for :meth:`set_sticker_set_thumbnail`""" - setPassportDataErrors = set_passport_data_errors - """Alias for :meth:`set_passport_data_errors`""" - sendPoll = send_poll - """Alias for :meth:`send_poll`""" - stopPoll = stop_poll - """Alias for :meth:`stop_poll`""" - sendDice = send_dice - """Alias for :meth:`send_dice`""" - getMyCommands = get_my_commands - """Alias for :meth:`get_my_commands`""" - setMyCommands = set_my_commands - """Alias for :meth:`set_my_commands`""" - deleteMyCommands = delete_my_commands - """Alias for :meth:`delete_my_commands`""" - logOut = log_out - """Alias for :meth:`log_out`""" - copyMessage = copy_message - """Alias for :meth:`copy_message`""" - copyMessages = copy_messages - """Alias for :meth:`copy_messages`""" - getChatMenuButton = get_chat_menu_button - """Alias for :meth:`get_chat_menu_button`""" - setChatMenuButton = set_chat_menu_button - """Alias for :meth:`set_chat_menu_button`""" - getMyDefaultAdministratorRights = get_my_default_administrator_rights - """Alias for :meth:`get_my_default_administrator_rights`""" - setMyDefaultAdministratorRights = set_my_default_administrator_rights - """Alias for :meth:`set_my_default_administrator_rights`""" - createInvoiceLink = create_invoice_link - """Alias for :meth:`create_invoice_link`""" - getForumTopicIconStickers = get_forum_topic_icon_stickers - """Alias for :meth:`get_forum_topic_icon_stickers`""" - createForumTopic = create_forum_topic - """Alias for :meth:`create_forum_topic`""" - editForumTopic = edit_forum_topic - """Alias for :meth:`edit_forum_topic`""" - closeForumTopic = close_forum_topic - """Alias for :meth:`close_forum_topic`""" - reopenForumTopic = reopen_forum_topic - """Alias for :meth:`reopen_forum_topic`""" - deleteForumTopic = delete_forum_topic - """Alias for :meth:`delete_forum_topic`""" - unpinAllForumTopicMessages = unpin_all_forum_topic_messages - """Alias for :meth:`unpin_all_forum_topic_messages`""" - editGeneralForumTopic = edit_general_forum_topic - """Alias for :meth:`edit_general_forum_topic`""" - closeGeneralForumTopic = close_general_forum_topic - """Alias for :meth:`close_general_forum_topic`""" - reopenGeneralForumTopic = reopen_general_forum_topic - """Alias for :meth:`reopen_general_forum_topic`""" - hideGeneralForumTopic = hide_general_forum_topic - """Alias for :meth:`hide_general_forum_topic`""" - unhideGeneralForumTopic = unhide_general_forum_topic - """Alias for :meth:`unhide_general_forum_topic`""" - setMyDescription = set_my_description - """Alias for :meth:`set_my_description`""" - setMyShortDescription = set_my_short_description - """Alias for :meth:`set_my_short_description`""" - getMyDescription = get_my_description - """Alias for :meth:`get_my_description`""" - getMyShortDescription = get_my_short_description - """Alias for :meth:`get_my_short_description`""" - setCustomEmojiStickerSetThumbnail = set_custom_emoji_sticker_set_thumbnail - """Alias for :meth:`set_custom_emoji_sticker_set_thumbnail`""" - setStickerSetTitle = set_sticker_set_title - """Alias for :meth:`set_sticker_set_title`""" - deleteStickerSet = delete_sticker_set - """Alias for :meth:`delete_sticker_set`""" - setStickerEmojiList = set_sticker_emoji_list - """Alias for :meth:`set_sticker_emoji_list`""" - setStickerKeywords = set_sticker_keywords - """Alias for :meth:`set_sticker_keywords`""" - setStickerMaskPosition = set_sticker_mask_position - """Alias for :meth:`set_sticker_mask_position`""" - setMyName = set_my_name - """Alias for :meth:`set_my_name`""" - getMyName = get_my_name - """Alias for :meth:`get_my_name`""" - unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages - """Alias for :meth:`unpin_all_general_forum_topic_messages`""" - getUserChatBoosts = get_user_chat_boosts - """Alias for :meth:`get_user_chat_boosts`""" - setMessageReaction = set_message_reaction - """Alias for :meth:`set_message_reaction`""" - getBusinessConnection = get_business_connection - """Alias for :meth:`get_business_connection`""" - replaceStickerInSet = replace_sticker_in_set - """Alias for :meth:`replace_sticker_in_set`""" - refundStarPayment = refund_star_payment - """Alias for :meth:`refund_star_payment`""" - getStarTransactions = get_star_transactions - """Alias for :meth:`get_star_transactions`""" - editUserStarSubscription = edit_user_star_subscription - """Alias for :meth:`edit_user_star_subscription`""" - sendPaidMedia = send_paid_media - """Alias for :meth:`send_paid_media`""" - createChatSubscriptionInviteLink = create_chat_subscription_invite_link - """Alias for :meth:`create_chat_subscription_invite_link`""" - editChatSubscriptionInviteLink = edit_chat_subscription_invite_link - """Alias for :meth:`edit_chat_subscription_invite_link`""" - getAvailableGifts = get_available_gifts - """Alias for :meth:`get_available_gifts`""" - sendGift = send_gift - """Alias for :meth:`send_gift`""" - verifyChat = verify_chat - """Alias for :meth:`verify_chat`""" - verifyUser = verify_user - """Alias for :meth:`verify_user`""" - removeChatVerification = remove_chat_verification - """Alias for :meth:`remove_chat_verification`""" - removeUserVerification = remove_user_verification - """Alias for :meth:`remove_user_verification`""" diff --git a/venv/lib/python3.11/site-packages/telegram/_botcommand.py b/venv/lib/python3.11/site-packages/telegram/_botcommand.py deleted file mode 100755 index 0597408..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_botcommand.py +++ /dev/null @@ -1,83 +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 Bot Command.""" - -from typing import Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class BotCommand(TelegramObject): - """ - This object represents a bot command. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`command` and :attr:`description` are equal. - - Args: - command (:obj:`str`): Text of the command; :tg-const:`telegram.BotCommand.MIN_COMMAND`- - :tg-const:`telegram.BotCommand.MAX_COMMAND` characters. Can contain only lowercase - English letters, digits and underscores. - description (:obj:`str`): Description of the command; - :tg-const:`telegram.BotCommand.MIN_DESCRIPTION`- - :tg-const:`telegram.BotCommand.MAX_DESCRIPTION` characters. - - Attributes: - command (:obj:`str`): Text of the command; :tg-const:`telegram.BotCommand.MIN_COMMAND`- - :tg-const:`telegram.BotCommand.MAX_COMMAND` characters. Can contain only lowercase - English letters, digits and underscores. - description (:obj:`str`): Description of the command; - :tg-const:`telegram.BotCommand.MIN_DESCRIPTION`- - :tg-const:`telegram.BotCommand.MAX_DESCRIPTION` characters. - - """ - - __slots__ = ("command", "description") - - def __init__(self, command: str, description: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.command: str = command - self.description: str = description - - self._id_attrs = (self.command, self.description) - - self._freeze() - - MIN_COMMAND: Final[int] = constants.BotCommandLimit.MIN_COMMAND - """:const:`telegram.constants.BotCommandLimit.MIN_COMMAND` - - .. versionadded:: 20.0 - """ - MAX_COMMAND: Final[int] = constants.BotCommandLimit.MAX_COMMAND - """:const:`telegram.constants.BotCommandLimit.MAX_COMMAND` - - .. versionadded:: 20.0 - """ - MIN_DESCRIPTION: Final[int] = constants.BotCommandLimit.MIN_DESCRIPTION - """:const:`telegram.constants.BotCommandLimit.MIN_DESCRIPTION` - - .. versionadded:: 20.0 - """ - MAX_DESCRIPTION: Final[int] = constants.BotCommandLimit.MAX_DESCRIPTION - """:const:`telegram.constants.BotCommandLimit.MAX_DESCRIPTION` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_botcommandscope.py b/venv/lib/python3.11/site-packages/telegram/_botcommandscope.py deleted file mode 100755 index 0c339a3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_botcommandscope.py +++ /dev/null @@ -1,273 +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 objects representing Telegram bot command scopes.""" -from typing import TYPE_CHECKING, Final, 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 BotCommandScope(TelegramObject): - """Base class for objects that represent the scope to which bot commands are applied. - Currently, the following 7 scopes are supported: - - * :class:`telegram.BotCommandScopeDefault` - * :class:`telegram.BotCommandScopeAllPrivateChats` - * :class:`telegram.BotCommandScopeAllGroupChats` - * :class:`telegram.BotCommandScopeAllChatAdministrators` - * :class:`telegram.BotCommandScopeChat` - * :class:`telegram.BotCommandScopeChatAdministrators` - * :class:`telegram.BotCommandScopeChatMember` - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` is equal. For subclasses with additional attributes, - the notion of equality is overridden. - - Note: - Please see the `official docs`_ on how Telegram determines which commands to display. - - .. _`official docs`: https://core.telegram.org/bots/api#determining-list-of-commands - - .. versionadded:: 13.7 - - Args: - type (:obj:`str`): Scope type. - - Attributes: - type (:obj:`str`): Scope type. - """ - - __slots__ = ("type",) - - DEFAULT: Final[str] = constants.BotCommandScopeType.DEFAULT - """:const:`telegram.constants.BotCommandScopeType.DEFAULT`""" - ALL_PRIVATE_CHATS: Final[str] = constants.BotCommandScopeType.ALL_PRIVATE_CHATS - """:const:`telegram.constants.BotCommandScopeType.ALL_PRIVATE_CHATS`""" - ALL_GROUP_CHATS: Final[str] = constants.BotCommandScopeType.ALL_GROUP_CHATS - """:const:`telegram.constants.BotCommandScopeType.ALL_GROUP_CHATS`""" - ALL_CHAT_ADMINISTRATORS: Final[str] = constants.BotCommandScopeType.ALL_CHAT_ADMINISTRATORS - """:const:`telegram.constants.BotCommandScopeType.ALL_CHAT_ADMINISTRATORS`""" - CHAT: Final[str] = constants.BotCommandScopeType.CHAT - """:const:`telegram.constants.BotCommandScopeType.CHAT`""" - CHAT_ADMINISTRATORS: Final[str] = constants.BotCommandScopeType.CHAT_ADMINISTRATORS - """:const:`telegram.constants.BotCommandScopeType.CHAT_ADMINISTRATORS`""" - CHAT_MEMBER: Final[str] = constants.BotCommandScopeType.CHAT_MEMBER - """:const:`telegram.constants.BotCommandScopeType.CHAT_MEMBER`""" - - def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.type: str = enum.get_member(constants.BotCommandScopeType, type, type) - self._id_attrs = (self.type,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["BotCommandScope"]: - """Converts JSON data to the appropriate :class:`BotCommandScope` object, i.e. takes - care of selecting the correct subclass. - - 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. - - """ - data = cls._parse_data(data) - - if not data: - return None - - _class_mapping: dict[str, type[BotCommandScope]] = { - cls.DEFAULT: BotCommandScopeDefault, - cls.ALL_PRIVATE_CHATS: BotCommandScopeAllPrivateChats, - cls.ALL_GROUP_CHATS: BotCommandScopeAllGroupChats, - cls.ALL_CHAT_ADMINISTRATORS: BotCommandScopeAllChatAdministrators, - cls.CHAT: BotCommandScopeChat, - cls.CHAT_ADMINISTRATORS: BotCommandScopeChatAdministrators, - cls.CHAT_MEMBER: BotCommandScopeChatMember, - } - - if cls is BotCommandScope 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 BotCommandScopeDefault(BotCommandScope): - """Represents the default scope of bot commands. Default commands are used if no commands with - a `narrower scope`_ are specified for the user. - - .. _`narrower scope`: https://core.telegram.org/bots/api#determining-list-of-commands - - .. versionadded:: 13.7 - Attributes: - type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.DEFAULT`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=BotCommandScope.DEFAULT, api_kwargs=api_kwargs) - self._freeze() - - -class BotCommandScopeAllPrivateChats(BotCommandScope): - """Represents the scope of bot commands, covering all private chats. - - .. versionadded:: 13.7 - - Attributes: - type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.ALL_PRIVATE_CHATS`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=BotCommandScope.ALL_PRIVATE_CHATS, api_kwargs=api_kwargs) - self._freeze() - - -class BotCommandScopeAllGroupChats(BotCommandScope): - """Represents the scope of bot commands, covering all group and supergroup chats. - - .. versionadded:: 13.7 - Attributes: - type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.ALL_GROUP_CHATS`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=BotCommandScope.ALL_GROUP_CHATS, api_kwargs=api_kwargs) - self._freeze() - - -class BotCommandScopeAllChatAdministrators(BotCommandScope): - """Represents the scope of bot commands, covering all group and supergroup chat administrators. - - .. versionadded:: 13.7 - Attributes: - type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.ALL_CHAT_ADMINISTRATORS`. - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=BotCommandScope.ALL_CHAT_ADMINISTRATORS, api_kwargs=api_kwargs) - self._freeze() - - -class BotCommandScopeChat(BotCommandScope): - """Represents the scope of bot commands, covering a specific chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` and :attr:`chat_id` are equal. - - .. versionadded:: 13.7 - - Args: - chat_id (:obj:`str` | :obj:`int`): |chat_id_group| - - Attributes: - type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT`. - chat_id (:obj:`str` | :obj:`int`): |chat_id_group| - """ - - __slots__ = ("chat_id",) - - def __init__(self, chat_id: Union[str, int], *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=BotCommandScope.CHAT, api_kwargs=api_kwargs) - with self._unfrozen(): - self.chat_id: Union[str, int] = ( - chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id) - ) - self._id_attrs = (self.type, self.chat_id) - - -class BotCommandScopeChatAdministrators(BotCommandScope): - """Represents the scope of bot commands, covering all administrators of a specific group or - supergroup chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` and :attr:`chat_id` are equal. - - .. versionadded:: 13.7 - - Args: - chat_id (:obj:`str` | :obj:`int`): |chat_id_group| - Attributes: - type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT_ADMINISTRATORS`. - chat_id (:obj:`str` | :obj:`int`): |chat_id_group| - """ - - __slots__ = ("chat_id",) - - def __init__(self, chat_id: Union[str, int], *, api_kwargs: Optional[JSONDict] = None): - super().__init__(type=BotCommandScope.CHAT_ADMINISTRATORS, api_kwargs=api_kwargs) - with self._unfrozen(): - self.chat_id: Union[str, int] = ( - chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id) - ) - self._id_attrs = (self.type, self.chat_id) - - -class BotCommandScopeChatMember(BotCommandScope): - """Represents the scope of bot commands, covering a specific member of a group or supergroup - chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type`, :attr:`chat_id` and :attr:`user_id` are equal. - - .. versionadded:: 13.7 - - Args: - chat_id (:obj:`str` | :obj:`int`): |chat_id_group| - user_id (:obj:`int`): Unique identifier of the target user. - - Attributes: - type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT_MEMBER`. - chat_id (:obj:`str` | :obj:`int`): |chat_id_group| - user_id (:obj:`int`): Unique identifier of the target user. - """ - - __slots__ = ("chat_id", "user_id") - - def __init__( - self, chat_id: Union[str, int], user_id: int, *, api_kwargs: Optional[JSONDict] = None - ): - super().__init__(type=BotCommandScope.CHAT_MEMBER, api_kwargs=api_kwargs) - with self._unfrozen(): - self.chat_id: Union[str, int] = ( - chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id) - ) - self.user_id: int = user_id - self._id_attrs = (self.type, self.chat_id, self.user_id) diff --git a/venv/lib/python3.11/site-packages/telegram/_botdescription.py b/venv/lib/python3.11/site-packages/telegram/_botdescription.py deleted file mode 100755 index 9f53ef1..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_botdescription.py +++ /dev/null @@ -1,77 +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 that represent a Telegram bots (short) description.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class BotDescription(TelegramObject): - """This object represents the bot's description. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`description` is equal. - - .. versionadded:: 20.2 - - Args: - description (:obj:`str`): The bot's description. - - Attributes: - description (:obj:`str`): The bot's description. - - """ - - __slots__ = ("description",) - - def __init__(self, description: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.description: str = description - - self._id_attrs = (self.description,) - - self._freeze() - - -class BotShortDescription(TelegramObject): - """This object represents the bot's short description. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`short_description` is equal. - - .. versionadded:: 20.2 - - Args: - short_description (:obj:`str`): The bot's short description. - - Attributes: - short_description (:obj:`str`): The bot's short description. - - """ - - __slots__ = ("short_description",) - - def __init__(self, short_description: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.short_description: str = short_description - - self._id_attrs = (self.short_description,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_botname.py b/venv/lib/python3.11/site-packages/telegram/_botname.py deleted file mode 100755 index a297027..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_botname.py +++ /dev/null @@ -1,54 +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 represent a Telegram bots name.""" -from typing import Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class BotName(TelegramObject): - """This object represents the bot's name. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`name` is equal. - - .. versionadded:: 20.3 - - Args: - name (:obj:`str`): The bot's name. - - Attributes: - name (:obj:`str`): The bot's name. - - """ - - __slots__ = ("name",) - - def __init__(self, name: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.name: str = name - - self._id_attrs = (self.name,) - - self._freeze() - - MAX_LENGTH: Final[int] = constants.BotNameLimit.MAX_NAME_LENGTH - """:const:`telegram.constants.BotNameLimit.MAX_NAME_LENGTH`""" diff --git a/venv/lib/python3.11/site-packages/telegram/_business.py b/venv/lib/python3.11/site-packages/telegram/_business.py deleted file mode 100755 index 412eae7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_business.py +++ /dev/null @@ -1,455 +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 the Telegram Business related classes.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._chat import Chat -from telegram._files.location import Location -from telegram._files.sticker import Sticker -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 BusinessConnection(TelegramObject): - """ - Describes the connection of the bot with a business account. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal if their :attr:`id`, :attr:`user`, :attr:`user_chat_id`, :attr:`date`, - :attr:`can_reply`, and :attr:`is_enabled` are equal. - - .. versionadded:: 21.1 - - Args: - id (:obj:`str`): Unique identifier of the business connection. - user (:class:`telegram.User`): Business account user that created the business connection. - user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the - business connection. - date (:obj:`datetime.datetime`): Date the connection was established in Unix time. - can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in - chats that were active in the last 24 hours. - is_enabled (:obj:`bool`): True, if the connection is active. - - Attributes: - id (:obj:`str`): Unique identifier of the business connection. - user (:class:`telegram.User`): Business account user that created the business connection. - user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the - business connection. - date (:obj:`datetime.datetime`): Date the connection was established in Unix time. - can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in - chats that were active in the last 24 hours. - is_enabled (:obj:`bool`): True, if the connection is active. - """ - - __slots__ = ( - "can_reply", - "date", - "id", - "is_enabled", - "user", - "user_chat_id", - ) - - def __init__( - self, - id: str, - user: "User", - user_chat_id: int, - date: dtm.datetime, - can_reply: bool, - is_enabled: bool, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.id: str = id - self.user: User = user - self.user_chat_id: int = user_chat_id - self.date: dtm.datetime = date - self.can_reply: bool = can_reply - self.is_enabled: bool = is_enabled - - self._id_attrs = ( - self.id, - self.user, - self.user_chat_id, - self.date, - self.can_reply, - self.is_enabled, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["BusinessConnection"]: - """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"), tzinfo=loc_tzinfo) - data["user"] = User.de_json(data.get("user"), bot) - - return super().de_json(data=data, bot=bot) - - -class BusinessMessagesDeleted(TelegramObject): - """ - This object is received when messages are deleted from a connected business account. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal if their :attr:`business_connection_id`, :attr:`message_ids`, and - :attr:`chat` are equal. - - .. versionadded:: 21.1 - - Args: - business_connection_id (:obj:`str`): Unique identifier of the business connection. - chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot - may not have access to the chat or the corresponding user. - message_ids (Sequence[:obj:`int`]): A list of identifiers of the deleted messages in the - chat of the business account. - - Attributes: - business_connection_id (:obj:`str`): Unique identifier of the business connection. - chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot - may not have access to the chat or the corresponding user. - message_ids (tuple[:obj:`int`]): A list of identifiers of the deleted messages in the - chat of the business account. - """ - - __slots__ = ( - "business_connection_id", - "chat", - "message_ids", - ) - - def __init__( - self, - business_connection_id: str, - chat: Chat, - message_ids: Sequence[int], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.business_connection_id: str = business_connection_id - self.chat: Chat = chat - self.message_ids: tuple[int, ...] = parse_sequence_arg(message_ids) - - self._id_attrs = ( - self.business_connection_id, - self.chat, - self.message_ids, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["BusinessMessagesDeleted"]: - """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) - - -class BusinessIntro(TelegramObject): - """ - This object contains information about the start page settings 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 - :attr:`title`, :attr:`message` and :attr:`sticker` are equal. - - .. versionadded:: 21.1 - - Args: - title (:obj:`str`, optional): Title text of the business intro. - message (:obj:`str`, optional): Message text of the business intro. - sticker (:class:`telegram.Sticker`, optional): Sticker of the business intro. - - Attributes: - title (:obj:`str`): Optional. Title text of the business intro. - message (:obj:`str`): Optional. Message text of the business intro. - sticker (:class:`telegram.Sticker`): Optional. Sticker of the business intro. - """ - - __slots__ = ( - "message", - "sticker", - "title", - ) - - def __init__( - self, - title: Optional[str] = None, - message: Optional[str] = None, - sticker: Optional[Sticker] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.title: Optional[str] = title - self.message: Optional[str] = message - self.sticker: Optional[Sticker] = sticker - - self._id_attrs = (self.title, self.message, self.sticker) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["BusinessIntro"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["sticker"] = Sticker.de_json(data.get("sticker"), bot) - - return super().de_json(data=data, bot=bot) - - -class BusinessLocation(TelegramObject): - """ - This object contains information about the location 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 - :attr:`address` is equal. - - .. versionadded:: 21.1 - - Args: - address (:obj:`str`): Address of the business. - location (:class:`telegram.Location`, optional): Location of the business. - - Attributes: - address (:obj:`str`): Address of the business. - location (:class:`telegram.Location`): Optional. Location of the business. - """ - - __slots__ = ( - "address", - "location", - ) - - def __init__( - self, - address: str, - location: Optional[Location] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.address: str = address - self.location: Optional[Location] = location - - self._id_attrs = (self.address,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["BusinessLocation"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["location"] = Location.de_json(data.get("location"), bot) - - return super().de_json(data=data, bot=bot) - - -class BusinessOpeningHoursInterval(TelegramObject): - """ - This object describes an interval of time during which a business is open. - - Objects of this class are comparable in terms of equality. - Two objects of this class are considered equal, if their - :attr:`opening_minute` and :attr:`closing_minute` are equal. - - .. versionadded:: 21.1 - - Examples: - A day has (24 * 60 =) 1440 minutes, a week has (7 * 1440 =) 10080 minutes. - Starting the the minute's sequence from Monday, example values of - :attr:`opening_minute`, :attr:`closing_minute` will map to the following day times: - - * Monday - 8am to 8:30pm: - - ``opening_minute = 480`` :guilabel:`8 * 60` - - ``closing_minute = 1230`` :guilabel:`20 * 60 + 30` - * Tuesday - 24 hours: - - ``opening_minute = 1440`` :guilabel:`24 * 60` - - ``closing_minute = 2879`` :guilabel:`2 * 24 * 60 - 1` - * Sunday - 12am - 11:58pm: - - ``opening_minute = 8640`` :guilabel:`6 * 24 * 60` - - ``closing_minute = 10078`` :guilabel:`7 * 24 * 60 - 2` - - Args: - opening_minute (:obj:`int`): The minute's sequence number in a week, starting on Monday, - marking the start of the time interval during which the business is open; - 0 - 7 * 24 * 60. - closing_minute (:obj:`int`): The minute's - sequence number in a week, starting on Monday, marking the end of the time interval - during which the business is open; 0 - 8 * 24 * 60 - - Attributes: - opening_minute (:obj:`int`): The minute's sequence number in a week, starting on Monday, - marking the start of the time interval during which the business is open; - 0 - 7 * 24 * 60. - closing_minute (:obj:`int`): The minute's - sequence number in a week, starting on Monday, marking the end of the time interval - during which the business is open; 0 - 8 * 24 * 60 - """ - - __slots__ = ("_closing_time", "_opening_time", "closing_minute", "opening_minute") - - def __init__( - self, - opening_minute: int, - closing_minute: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.opening_minute: int = opening_minute - self.closing_minute: int = closing_minute - - self._opening_time: Optional[tuple[int, int, int]] = None - self._closing_time: Optional[tuple[int, int, int]] = None - - self._id_attrs = (self.opening_minute, self.closing_minute) - - self._freeze() - - def _parse_minute(self, minute: int) -> tuple[int, int, int]: - return (minute // 1440, minute % 1440 // 60, minute % 1440 % 60) - - @property - def opening_time(self) -> tuple[int, int, int]: - """Convenience attribute. A :obj:`tuple` parsed from :attr:`opening_minute`. It contains - the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`, - :attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute` - - Returns: - tuple[:obj:`int`, :obj:`int`, :obj:`int`]: - """ - if self._opening_time is None: - self._opening_time = self._parse_minute(self.opening_minute) - return self._opening_time - - @property - def closing_time(self) -> tuple[int, int, int]: - """Convenience attribute. A :obj:`tuple` parsed from :attr:`closing_minute`. It contains - the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`, - :attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute` - - Returns: - tuple[:obj:`int`, :obj:`int`, :obj:`int`]: - """ - if self._closing_time is None: - self._closing_time = self._parse_minute(self.closing_minute) - return self._closing_time - - -class BusinessOpeningHours(TelegramObject): - """ - This object describes the opening hours of a business. - - Objects of this class are comparable in terms of equality. - Two objects of this class are considered equal, if their - :attr:`time_zone_name` and :attr:`opening_hours` are equal. - - .. versionadded:: 21.1 - - Args: - time_zone_name (:obj:`str`): Unique name of the time zone for which the opening - hours are defined. - opening_hours (Sequence[:class:`telegram.BusinessOpeningHoursInterval`]): List of - time intervals describing business opening hours. - - Attributes: - time_zone_name (:obj:`str`): Unique name of the time zone for which the opening - hours are defined. - opening_hours (Sequence[:class:`telegram.BusinessOpeningHoursInterval`]): List of - time intervals describing business opening hours. - """ - - __slots__ = ("opening_hours", "time_zone_name") - - def __init__( - self, - time_zone_name: str, - opening_hours: Sequence[BusinessOpeningHoursInterval], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.time_zone_name: str = time_zone_name - self.opening_hours: Sequence[BusinessOpeningHoursInterval] = parse_sequence_arg( - opening_hours - ) - - self._id_attrs = (self.time_zone_name, self.opening_hours) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["BusinessOpeningHours"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["opening_hours"] = BusinessOpeningHoursInterval.de_list( - data.get("opening_hours"), bot - ) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_callbackquery.py b/venv/lib/python3.11/site-packages/telegram/_callbackquery.py deleted file mode 100755 index 8febcca..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_callbackquery.py +++ /dev/null @@ -1,895 +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 an object that represents a Telegram CallbackQuery""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional, Union - -from telegram import constants -from telegram._files.location import Location -from telegram._message import MaybeInaccessibleMessage, Message -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput, ReplyMarkup - -if TYPE_CHECKING: - from telegram import ( - Bot, - GameHighScore, - InlineKeyboardMarkup, - InputMedia, - LinkPreviewOptions, - MessageEntity, - MessageId, - ReplyParameters, - ) - - -class CallbackQuery(TelegramObject): - """ - This object represents an incoming callback query from a callback button in an inline keyboard. - - If the button that originated the query was attached to a message sent by the bot, the field - :attr:`message` will be present. If the button was attached to a message sent via the bot (in - inline mode), the field :attr:`inline_message_id` will be present. - - 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. - * Exactly one of the fields :attr:`data` or :attr:`game_short_name` will be present. - * After the user presses an inline button, Telegram clients will display a progress bar - until you call :attr:`answer`. It is, therefore, necessary to react - by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user - is needed (e.g., without specifying any of the optional parameters). - * If you're using :attr:`telegram.ext.ExtBot.callback_data_cache`, :attr:`data` may be - an instance - of :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data - associated with the button triggering the :class:`telegram.CallbackQuery` was already - deleted or if :attr:`data` was manipulated by a malicious client. - - .. versionadded:: 13.6 - - Args: - id (:obj:`str`): Unique identifier for this query. - from_user (:class:`telegram.User`): Sender. - chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which - the message with the callback button was sent. Useful for high scores in games. - message (:class:`telegram.MaybeInaccessibleMessage`, optional): Message sent by the bot - with the callback button that originated the query. - - .. versionchanged:: 20.8 - Accept objects of type :class:`telegram.MaybeInaccessibleMessage` since Bot API 7.0. - data (:obj:`str`, optional): Data associated with the callback button. Be aware that the - message, which originated the query, can contain no callback buttons with this data. - inline_message_id (:obj:`str`, optional): Identifier of the message sent via the bot in - inline mode, that originated the query. - game_short_name (:obj:`str`, optional): Short name of a Game to be returned, serves as - the unique identifier for the game. - - Attributes: - id (:obj:`str`): Unique identifier for this query. - from_user (:class:`telegram.User`): Sender. - chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which - the message with the callback button was sent. Useful for high scores in games. - message (:class:`telegram.MaybeInaccessibleMessage`): Optional. Message sent by the bot - with the callback button that originated the query. - - .. versionchanged:: 20.8 - Objects may be of type :class:`telegram.MaybeInaccessibleMessage` since Bot API - 7.0. - data (:obj:`str` | :obj:`object`): Optional. Data associated with the callback button. - Be aware that the message, which originated the query, can contain no callback buttons - with this data. - - Tip: - The value here is the same as the value passed in - :paramref:`telegram.InlineKeyboardButton.callback_data`. - inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in - inline mode, that originated the query. - game_short_name (:obj:`str`): Optional. Short name of a Game to be returned, serves as - the unique identifier for the game. - - - """ - - __slots__ = ( - "chat_instance", - "data", - "from_user", - "game_short_name", - "id", - "inline_message_id", - "message", - ) - - def __init__( - self, - id: str, - from_user: User, - chat_instance: str, - message: Optional[MaybeInaccessibleMessage] = None, - data: Optional[str] = None, - inline_message_id: Optional[str] = None, - game_short_name: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.id: str = id - self.from_user: User = from_user - self.chat_instance: str = chat_instance - # Optionals - self.message: Optional[MaybeInaccessibleMessage] = message - self.data: Optional[str] = data - self.inline_message_id: Optional[str] = inline_message_id - self.game_short_name: Optional[str] = game_short_name - - self._id_attrs = (self.id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["CallbackQuery"]: - """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["message"] = Message.de_json(data.get("message"), bot) - - return super().de_json(data=data, bot=bot) - - async def answer( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.answer_callback_query(update.callback_query.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.answer_callback_query`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().answer_callback_query( - callback_query_id=self.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=api_kwargs, - ) - - def _get_message(self, action: str = "edit") -> Message: - """Helper method to get the message for the shortcut methods. Must be called only - if :attr:`inline_message_id` is *not* set. - """ - if not isinstance(self.message, Message): - raise TypeError(f"Cannot {action} an inaccessible message") - return self.message - - async def edit_message_text( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - reply_markup: Optional["InlineKeyboardMarkup"] = None, - entities: Optional[Sequence["MessageEntity"]] = None, - link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_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, - ) -> Union[Message, bool]: - """Shortcut for either:: - - await update.callback_query.message.edit_text(*args, **kwargs) - - or:: - - await bot.edit_message_text( - inline_message_id=update.callback_query.inline_message_id, *args, **kwargs, - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_text` and :meth:`telegram.Message.edit_text`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - if self.inline_message_id: - return await self.get_bot().edit_message_text( - inline_message_id=self.inline_message_id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - link_preview_options=link_preview_options, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - entities=entities, - chat_id=None, - message_id=None, - # inline messages can not be sent on behalf of a bcid - business_connection_id=None, - ) - return await self._get_message().edit_text( - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - link_preview_options=link_preview_options, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - entities=entities, - ) - - async def edit_message_caption( - self, - 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, - *, - 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, - ) -> Union[Message, bool]: - """Shortcut for either:: - - await update.callback_query.message.edit_caption(*args, **kwargs) - - or:: - - await bot.edit_message_caption( - inline_message_id=update.callback_query.inline_message_id, *args, **kwargs, - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_caption` and :meth:`telegram.Message.edit_caption`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - if self.inline_message_id: - return await self.get_bot().edit_message_caption( - caption=caption, - inline_message_id=self.inline_message_id, - 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, - caption_entities=caption_entities, - chat_id=None, - message_id=None, - show_caption_above_media=show_caption_above_media, - # inline messages can not be sent on behalf of a bcid - business_connection_id=None, - ) - return await self._get_message().edit_caption( - caption=caption, - 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, - caption_entities=caption_entities, - show_caption_above_media=show_caption_above_media, - ) - - async def edit_message_reply_markup( - self, - reply_markup: Optional["InlineKeyboardMarkup"] = 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, - ) -> Union[Message, bool]: - """Shortcut for either:: - - await update.callback_query.message.edit_reply_markup(*args, **kwargs) - - or:: - - await bot.edit_message_reply_markup( - inline_message_id=update.callback_query.inline_message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_reply_markup` and - :meth:`telegram.Message.edit_reply_markup`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - if self.inline_message_id: - return await self.get_bot().edit_message_reply_markup( - reply_markup=reply_markup, - inline_message_id=self.inline_message_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - # inline messages can not be sent on behalf of a bcid - business_connection_id=None, - ) - return await self._get_message().edit_reply_markup( - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def edit_message_media( - self, - media: "InputMedia", - reply_markup: Optional["InlineKeyboardMarkup"] = 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, - ) -> Union[Message, bool]: - """Shortcut for either:: - - await update.callback_query.message.edit_media(*args, **kwargs) - - or:: - - await bot.edit_message_media( - inline_message_id=update.callback_query.inline_message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_media` and :meth:`telegram.Message.edit_media`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - if self.inline_message_id: - return await self.get_bot().edit_message_media( - inline_message_id=self.inline_message_id, - media=media, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - # inline messages can not be sent on behalf of a bcid - business_connection_id=None, - ) - return await self._get_message().edit_media( - media=media, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def edit_message_live_location( - self, - 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, - *, - 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, - ) -> Union[Message, bool]: - """Shortcut for either:: - - await update.callback_query.message.edit_live_location(*args, **kwargs) - - or:: - - await bot.edit_message_live_location( - inline_message_id=update.callback_query.inline_message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_live_location` and - :meth:`telegram.Message.edit_live_location`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - if self.inline_message_id: - return await self.get_bot().edit_message_live_location( - inline_message_id=self.inline_message_id, - latitude=latitude, - longitude=longitude, - location=location, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - live_period=live_period, - chat_id=None, - message_id=None, - # inline messages can not be sent on behalf of a bcid - business_connection_id=None, - ) - return await self._get_message().edit_live_location( - latitude=latitude, - longitude=longitude, - location=location, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - live_period=live_period, - ) - - async def stop_message_live_location( - self, - reply_markup: Optional["InlineKeyboardMarkup"] = 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, - ) -> Union[Message, bool]: - """Shortcut for either:: - - await update.callback_query.message.stop_live_location(*args, **kwargs) - - or:: - - await bot.stop_message_live_location( - inline_message_id=update.callback_query.inline_message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.stop_message_live_location` and - :meth:`telegram.Message.stop_live_location`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - if self.inline_message_id: - return await self.get_bot().stop_message_live_location( - inline_message_id=self.inline_message_id, - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - # inline messages can not be sent on behalf of a bcid - business_connection_id=None, - ) - return await self._get_message().stop_live_location( - reply_markup=reply_markup, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def set_game_score( - self, - user_id: int, - score: int, - 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, - ) -> Union[Message, bool]: - """Shortcut for either:: - - await update.callback_query.message.set_game_score(*args, **kwargs) - - or:: - - await bot.set_game_score( - inline_message_id=update.callback_query.inline_message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_game_score` and :meth:`telegram.Message.set_game_score`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - if self.inline_message_id: - return await self.get_bot().set_game_score( - inline_message_id=self.inline_message_id, - user_id=user_id, - score=score, - 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=api_kwargs, - chat_id=None, - message_id=None, - ) - return await self._get_message().set_game_score( - user_id=user_id, - score=score, - 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=api_kwargs, - ) - - async def get_game_high_scores( - 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, - ) -> tuple["GameHighScore", ...]: - """Shortcut for either:: - - await update.callback_query.message.get_game_high_score(*args, **kwargs) - - or:: - - await bot.get_game_high_scores( - inline_message_id=update.callback_query.inline_message_id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_game_high_scores` and - :meth:`telegram.Message.get_game_high_scores`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - tuple[:class:`telegram.GameHighScore`] - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - if self.inline_message_id: - return await self.get_bot().get_game_high_scores( - inline_message_id=self.inline_message_id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - ) - return await self._get_message().get_game_high_scores( - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def delete_message( - 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 update.callback_query.message.delete(*args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Message.delete`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - - """ - return await self._get_message(action="delete").delete( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def pin_message( - self, - disable_notification: 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, - ) -> bool: - """Shortcut for:: - - await update.callback_query.message.pin(*args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Message.pin`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - """ - return await self._get_message(action="pin").pin( - disable_notification=disable_notification, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def unpin_message( - 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 update.callback_query.message.unpin(*args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Message.unpin`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - """ - return await self._get_message(action="unpin").unpin( - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def copy_message( - self, - chat_id: Union[int, str], - 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, - *, - 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, - ) -> "MessageId": - """Shortcut for:: - - await update.callback_query.message.copy( - from_chat_id=update.message.chat_id, - message_id=update.message.message_id, - *args, - **kwargs - ) - - For the documentation of the arguments, please see :meth:`telegram.Message.copy`. - - .. versionchanged:: 20.8 - Raises :exc:`TypeError` if :attr:`message` is not accessible. - - Returns: - :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. - - Raises: - :exc:`TypeError` if :attr:`message` is not accessible. - """ - return await self._get_message(action="copy").copy( - chat_id=chat_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=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, - reply_parameters=reply_parameters, - show_caption_above_media=show_caption_above_media, - allow_paid_broadcast=allow_paid_broadcast, - ) - - MAX_ANSWER_TEXT_LENGTH: Final[int] = ( - constants.CallbackQueryLimit.ANSWER_CALLBACK_QUERY_TEXT_LENGTH - ) - """ - :const:`telegram.constants.CallbackQueryLimit.ANSWER_CALLBACK_QUERY_TEXT_LENGTH` - - .. versionadded:: 13.2 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_chat.py b/venv/lib/python3.11/site-packages/telegram/_chat.py deleted file mode 100755 index 16c1205..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chat.py +++ /dev/null @@ -1,3599 +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 Chat.""" -import datetime as dtm -from collections.abc import Sequence -from html import escape -from typing import TYPE_CHECKING, Final, Optional, Union - -from telegram import constants -from telegram._chatpermissions import ChatPermissions -from telegram._forumtopic import ForumTopic -from telegram._menubutton import MenuButton -from telegram._reaction import ReactionType -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup -from telegram.helpers import escape_markdown -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, - ChatInviteLink, - ChatMember, - Contact, - Document, - Gift, - InlineKeyboardMarkup, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - InputPaidMedia, - InputPollOption, - LabeledPrice, - LinkPreviewOptions, - Location, - Message, - MessageEntity, - MessageId, - PhotoSize, - ReplyParameters, - Sticker, - UserChatBoosts, - Venue, - Video, - VideoNote, - Voice, - ) - - -class _ChatBase(TelegramObject): - """Base class for :class:`telegram.Chat` and :class:`telegram.ChatFullInfo`. - - .. versionadded:: 21.3 - """ - - __slots__ = ("first_name", "id", "is_forum", "last_name", "title", "type", "username") - - def __init__( - self, - id: int, - type: str, - title: Optional[str] = None, - username: Optional[str] = None, - first_name: Optional[str] = None, - last_name: Optional[str] = None, - is_forum: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.id: int = id - self.type: str = enum.get_member(constants.ChatType, type, type) - # Optionals - self.title: Optional[str] = title - self.username: Optional[str] = username - self.first_name: Optional[str] = first_name - self.last_name: Optional[str] = last_name - self.is_forum: Optional[bool] = is_forum - - self._id_attrs = (self.id,) - - self._freeze() - - SENDER: Final[str] = constants.ChatType.SENDER - """:const:`telegram.constants.ChatType.SENDER` - - .. versionadded:: 13.5 - """ - PRIVATE: Final[str] = constants.ChatType.PRIVATE - """:const:`telegram.constants.ChatType.PRIVATE`""" - GROUP: Final[str] = constants.ChatType.GROUP - """:const:`telegram.constants.ChatType.GROUP`""" - SUPERGROUP: Final[str] = constants.ChatType.SUPERGROUP - """:const:`telegram.constants.ChatType.SUPERGROUP`""" - CHANNEL: Final[str] = constants.ChatType.CHANNEL - """:const:`telegram.constants.ChatType.CHANNEL`""" - - @property - def effective_name(self) -> Optional[str]: - """ - :obj:`str`: Convenience property. Gives :attr:`~Chat.title` if not :obj:`None`, - else :attr:`~Chat.full_name` if not :obj:`None`. - - .. versionadded:: 20.1 - """ - if self.title is not None: - return self.title - if self.full_name is not None: - return self.full_name - return None - - @property - def full_name(self) -> Optional[str]: - """ - :obj:`str`: Convenience property. If :attr:`~Chat.first_name` is not :obj:`None`, gives - :attr:`~Chat.first_name` followed by (if available) :attr:`~Chat.last_name`. - - Note: - :attr:`full_name` will always be :obj:`None`, if the chat is a (super)group or - channel. - - .. versionadded:: 13.2 - """ - if not self.first_name: - return None - 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 the chat has a :attr:`~Chat.username`, returns a - t.me link of the chat. - """ - if self.username: - return f"https://t.me/{self.username}" - return None - - 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. - - .. versionadded:: 20.0 - - Args: - name (:obj:`str`): The name used as a link for the chat. Defaults to - :attr:`~Chat.full_name`. - - Returns: - :obj:`str`: The inline mention for the chat as markdown (version 1). - - Raises: - :exc:`TypeError`: If the chat is a private chat and neither the :paramref:`name` - nor the :attr:`~Chat.first_name` is set, then throw an :exc:`TypeError`. - If the chat is a public chat and neither the :paramref:`name` nor the - :attr:`~Chat.title` is set, then throw an :exc:`TypeError`. If chat is a - private group chat, then throw an :exc:`TypeError`. - - """ - if self.type == self.PRIVATE: - if name: - return helpers_mention_markdown(self.id, name) - if self.full_name: - return helpers_mention_markdown(self.id, self.full_name) - raise TypeError("Can not create a mention to a private chat without first name") - if self.username: - if name: - return f"[{name}]({self.link})" - if self.title: - return f"[{self.title}]({self.link})" - raise TypeError("Can not create a mention to a public chat without title") - raise TypeError("Can not create a mention to a private group chat") - - def mention_markdown_v2(self, name: Optional[str] = None) -> str: - """ - .. versionadded:: 20.0 - - Args: - name (:obj:`str`): The name used as a link for the chat. Defaults to - :attr:`~Chat.full_name`. - - Returns: - :obj:`str`: The inline mention for the chat as markdown (version 2). - - Raises: - :exc:`TypeError`: If the chat is a private chat and neither the :paramref:`name` - nor the :attr:`~Chat.first_name` is set, then throw an :exc:`TypeError`. - If the chat is a public chat and neither the :paramref:`name` nor the - :attr:`~Chat.title` is set, then throw an :exc:`TypeError`. If chat is a - private group chat, then throw an :exc:`TypeError`. - - """ - if self.type == self.PRIVATE: - if name: - return helpers_mention_markdown(self.id, name, version=2) - if self.full_name: - return helpers_mention_markdown(self.id, self.full_name, version=2) - raise TypeError("Can not create a mention to a private chat without first name") - if self.username: - if name: - return f"[{escape_markdown(name, version=2)}]({self.link})" - if self.title: - return f"[{escape_markdown(self.title, version=2)}]({self.link})" - raise TypeError("Can not create a mention to a public chat without title") - raise TypeError("Can not create a mention to a private group chat") - - def mention_html(self, name: Optional[str] = None) -> str: - """ - .. versionadded:: 20.0 - - Args: - name (:obj:`str`): The name used as a link for the chat. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the chat as HTML. - - Raises: - :exc:`TypeError`: If the chat is a private chat and neither the :paramref:`name` - nor the :attr:`~Chat.first_name` is set, then throw an :exc:`TypeError`. - If the chat is a public chat and neither the :paramref:`name` nor the - :attr:`~Chat.title` is set, then throw an :exc:`TypeError`. - If chat is a private group chat, then throw an :exc:`TypeError`. - - """ - if self.type == self.PRIVATE: - if name: - return helpers_mention_html(self.id, name) - if self.full_name: - return helpers_mention_html(self.id, self.full_name) - raise TypeError("Can not create a mention to a private chat without first name") - if self.username: - if name: - return f'{escape(name)}' - if self.title: - return f'{escape(self.title)}' - raise TypeError("Can not create a mention to a public chat without title") - raise TypeError("Can not create a mention to a private group chat") - - async def leave( - 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.leave_chat(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.leave_chat`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().leave_chat( - 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_administrators( - 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, - ) -> tuple["ChatMember", ...]: - """Shortcut for:: - - await bot.get_chat_administrators(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_chat_administrators`. - - Returns: - tuple[:class:`telegram.ChatMember`]: A tuple of administrators in a chat. An Array of - :class:`telegram.ChatMember` objects that contains information about all - chat administrators except other bots. If the chat is a group or a supergroup - and no administrators were appointed, only the creator will be returned. - - """ - return await self.get_bot().get_chat_administrators( - 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_member_count( - 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, - ) -> int: - """Shortcut for:: - - await bot.get_chat_member_count(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_chat_member_count`. - - Returns: - :obj:`int` - """ - return await self.get_bot().get_chat_member_count( - 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_member( - 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, - ) -> "ChatMember": - """Shortcut for:: - - await bot.get_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_chat_member`. - - Returns: - :class:`telegram.ChatMember` - - """ - return await self.get_bot().get_chat_member( - chat_id=self.id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def ban_member( - self, - user_id: int, - revoke_messages: Optional[bool] = None, - until_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, - ) -> bool: - """Shortcut for:: - - await bot.ban_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.ban_chat_member`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().ban_chat_member( - chat_id=self.id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - until_date=until_date, - api_kwargs=api_kwargs, - revoke_messages=revoke_messages, - ) - - async def ban_sender_chat( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.ban_chat_sender_chat(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.ban_chat_sender_chat`. - - .. versionadded:: 13.9 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().ban_chat_sender_chat( - chat_id=self.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=api_kwargs, - ) - - async def ban_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, - ) -> bool: - """Shortcut for:: - - await bot.ban_chat_sender_chat( - sender_chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.ban_chat_sender_chat`. - - .. versionadded:: 13.9 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().ban_chat_sender_chat( - chat_id=chat_id, - sender_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 unban_sender_chat( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.unban_chat_sender_chat(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unban_chat_sender_chat`. - - .. versionadded:: 13.9 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().unban_chat_sender_chat( - chat_id=self.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=api_kwargs, - ) - - async def unban_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, - ) -> bool: - """Shortcut for:: - - await bot.unban_chat_sender_chat( - sender_chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unban_chat_sender_chat`. - - .. versionadded:: 13.9 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().unban_chat_sender_chat( - chat_id=chat_id, - sender_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 unban_member( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.unban_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.unban_chat_member`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().unban_chat_member( - chat_id=self.id, - user_id=user_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - only_if_banned=only_if_banned, - ) - - async def promote_member( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.promote_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.promote_chat_member`. - - .. versionadded:: 13.2 - .. versionchanged:: 20.0 - The argument ``can_manage_voice_chats`` was renamed to - :paramref:`~telegram.Bot.promote_chat_member.can_manage_video_chats` in accordance to - Bot API 6.0. - .. versionchanged:: 20.6 - The arguments `can_post_stories`, `can_edit_stories` and `can_delete_stories` were - added. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().promote_chat_member( - chat_id=self.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, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - 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, - ) - - async def restrict_member( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.restrict_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.restrict_chat_member`. - - .. versionadded:: 13.2 - - .. versionadded:: 20.1 - Added :paramref:`~telegram.Bot.restrict_chat_member.use_independent_chat_permissions`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().restrict_chat_member( - chat_id=self.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=api_kwargs, - ) - - async def set_permissions( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.set_chat_permissions(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_permissions`. - - .. versionadded:: 20.1 - Added :paramref:`~telegram.Bot.set_chat_permissions.use_independent_chat_permissions`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().set_chat_permissions( - chat_id=self.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=api_kwargs, - ) - - async def set_administrator_custom_title( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.set_chat_administrator_custom_title( - update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_administrator_custom_title`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().set_chat_administrator_custom_title( - chat_id=self.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=api_kwargs, - ) - - async def set_photo( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.set_chat_photo( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_photo`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().set_chat_photo( - chat_id=self.id, - photo=photo, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def delete_photo( - 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.delete_chat_photo( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.delete_chat_photo`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().delete_chat_photo( - 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 set_title( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.set_chat_title( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_title`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().set_chat_title( - chat_id=self.id, - title=title, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def set_description( - self, - 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.set_chat_description( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_description`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().set_chat_description( - chat_id=self.id, - description=description, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.pin_chat_message`. - - 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, - api_kwargs=api_kwargs, - business_connection_id=business_connection_id, - ) - - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_chat_message`. - - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_all_chat_messages`. - - 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, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_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, - ) -> "Message": - """Shortcut for:: - - await bot.send_message(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - 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, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - link_preview_options=link_preview_options, - 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_chat.id, *args, **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_chat.id, *args, **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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. - - 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, - 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, - reply_parameters=reply_parameters, - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. - - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. - - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. - - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. - - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. - - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. - - 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_chat.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. - - .. 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_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, - reply_parameters=reply_parameters, - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. - - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. - - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. - - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. - - 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( - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. - - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_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, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. - - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. - - 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, - message_effect_id=message_effect_id, - allow_paid_broadcast=allow_paid_broadcast, - 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, - ) - - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - .. seealso:: :meth:`copy_message`, :meth:`send_copies`, :meth:`copy_messages`. - - 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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - .. seealso:: :meth:`send_copy`, :meth:`send_copies`, :meth:`copy_messages`. - - 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_chat.id, *args, **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_chat.id, *args, **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_chat.id, *args, **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_chat.id, *args, **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_chat.id, *args, **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_chat.id, *args, **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 export_invite_link( - 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, - ) -> str: - """Shortcut for:: - - await bot.export_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.export_chat_invite_link`. - - .. versionadded:: 13.4 - - Returns: - :obj:`str`: New invite link on success. - - """ - return await self.get_bot().export_chat_invite_link( - 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 create_invite_link( - self, - 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, - ) -> "ChatInviteLink": - """Shortcut for:: - - await bot.create_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.create_chat_invite_link`. - - .. versionadded:: 13.4 - - .. versionchanged:: 13.8 - Edited signature according to the changes of - :meth:`telegram.Bot.create_chat_invite_link`. - - Returns: - :class:`telegram.ChatInviteLink` - - """ - return await self.get_bot().create_chat_invite_link( - chat_id=self.id, - expire_date=expire_date, - member_limit=member_limit, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - name=name, - creates_join_request=creates_join_request, - ) - - async def edit_invite_link( - self, - 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, - ) -> "ChatInviteLink": - """Shortcut for:: - - await bot.edit_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_chat_invite_link`. - - .. versionadded:: 13.4 - - .. versionchanged:: 13.8 - Edited signature according to the changes of :meth:`telegram.Bot.edit_chat_invite_link`. - - Returns: - :class:`telegram.ChatInviteLink` - - """ - return await self.get_bot().edit_chat_invite_link( - chat_id=self.id, - invite_link=invite_link, - expire_date=expire_date, - member_limit=member_limit, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - name=name, - creates_join_request=creates_join_request, - ) - - async def revoke_invite_link( - self, - 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, - ) -> "ChatInviteLink": - """Shortcut for:: - - await bot.revoke_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.revoke_chat_invite_link`. - - .. versionadded:: 13.4 - - Returns: - :class:`telegram.ChatInviteLink` - - """ - return await self.get_bot().revoke_chat_invite_link( - chat_id=self.id, - invite_link=invite_link, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def create_subscription_invite_link( - self, - 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, - ) -> "ChatInviteLink": - """Shortcut for:: - - await bot.create_chat_subscription_invite_link( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.create_chat_subscription_invite_link`. - - .. versionadded:: 21.5 - - Returns: - :class:`telegram.ChatInviteLink` - """ - return await self.get_bot().create_chat_subscription_invite_link( - chat_id=self.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=api_kwargs, - ) - - async def edit_subscription_invite_link( - self, - 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, - ) -> "ChatInviteLink": - """Shortcut for:: - - await bot.edit_chat_subscription_invite_link( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_chat_subscription_invite_link`. - - .. versionadded:: 21.5 - - Returns: - :class:`telegram.ChatInviteLink` - - """ - return await self.get_bot().edit_chat_subscription_invite_link( - chat_id=self.id, - invite_link=invite_link, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - name=name, - ) - - async def approve_join_request( - 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, - ) -> bool: - """Shortcut for:: - - await bot.approve_chat_join_request(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.approve_chat_join_request`. - - .. versionadded:: 13.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().approve_chat_join_request( - chat_id=self.id, - user_id=user_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, - 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, - ) -> bool: - """Shortcut for:: - - await bot.decline_chat_join_request(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.decline_chat_join_request`. - - .. versionadded:: 13.8 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().decline_chat_join_request( - chat_id=self.id, - user_id=user_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_menu_button`. - - Caution: - Can only work, if the chat is a private chat. - - .. seealso:: :meth:`get_menu_button` - - .. 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 create_forum_topic( - self, - 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, - ) -> ForumTopic: - """Shortcut for:: - - await bot.create_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.create_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :class:`telegram.ForumTopic` - """ - return await self.get_bot().create_forum_topic( - chat_id=self.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=api_kwargs, - ) - - async def edit_forum_topic( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.edit_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().edit_forum_topic( - chat_id=self.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=api_kwargs, - ) - - async def close_forum_topic( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.close_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.close_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().close_forum_topic( - chat_id=self.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=api_kwargs, - ) - - async def reopen_forum_topic( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.reopen_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.reopen_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().reopen_forum_topic( - chat_id=self.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=api_kwargs, - ) - - async def delete_forum_topic( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.delete_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.delete_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().delete_forum_topic( - chat_id=self.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=api_kwargs, - ) - - async def unpin_all_forum_topic_messages( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.unpin_all_forum_topic_messages(chat_id=update.effective_chat.id, - *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_all_forum_topic_messages`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().unpin_all_forum_topic_messages( - chat_id=self.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=api_kwargs, - ) - - async def unpin_all_general_forum_topic_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_general_forum_topic_messages(chat_id=update.effective_chat.id, - *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_all_general_forum_topic_messages`. - - .. versionadded:: 20.5 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().unpin_all_general_forum_topic_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 edit_general_forum_topic( - 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, - ) -> bool: - """Shortcut for:: - - await bot.edit_general_forum_topic( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_general_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().edit_general_forum_topic( - chat_id=self.id, - name=name, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def close_general_forum_topic( - 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.close_general_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.close_general_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().close_general_forum_topic( - 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 reopen_general_forum_topic( - 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.reopen_general_forum_topic( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.reopen_general_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().reopen_general_forum_topic( - 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 hide_general_forum_topic( - 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.hide_general_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.hide_general_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().hide_general_forum_topic( - 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 unhide_general_forum_topic( - 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.unhide_general_forum_topic ( - chat_id=update.effective_chat.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unhide_general_forum_topic`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().unhide_general_forum_topic( - 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_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_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_chat_menu_button`. - - Caution: - Can only work, if the chat is a private chat. - - .. seealso:: :meth:`set_menu_button` - - .. 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_user_chat_boosts( - 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, - ) -> "UserChatBoosts": - """Shortcut for:: - - await bot.get_user_chat_boosts(chat_id=update.effective_chat.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 in the chat. - """ - return await self.get_bot().get_user_chat_boosts( - chat_id=self.id, - user_id=user_id, - api_kwargs=api_kwargs, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - - async def set_message_reaction( - self, - 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, - ) -> bool: - """Shortcut for:: - - await bot.set_message_reaction(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_message_reaction`. - - .. versionadded:: 20.8 - - Returns: - :obj:`bool` On success, :obj:`True` is returned. - """ - return await self.get_bot().set_message_reaction( - chat_id=self.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=api_kwargs, - ) - - async def send_paid_media( - self, - 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, - ) -> "Message": - """Shortcut for:: - - await bot.send_paid_media(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.send_paid_media`. - - .. versionadded:: 21.4 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - """ - return await self.get_bot().send_paid_media( - chat_id=self.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=api_kwargs, - business_connection_id=business_connection_id, - payload=payload, - 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_chat.id, *args, **kwargs ) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_gift`. - - Caution: - Can only work, if the chat is a private chat, see :attr:`type`. - - .. 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 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_chat(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.verify_chat`. - - .. versionadded:: 21.10 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().verify_chat( - chat_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_chat_verification(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.remove_chat_verification`. - - .. versionadded:: 21.10 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - return await self.get_bot().remove_chat_verification( - chat_id=self.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - -class Chat(_ChatBase): - """This object represents a chat. - - 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 - - * Removed the deprecated methods ``kick_member`` and ``get_members_count``. - * The following are now keyword-only arguments in Bot methods: - ``location``, ``filename``, ``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. - - .. versionchanged:: 20.0 - Removed the attribute ``all_members_are_administrators``. As long as Telegram provides - this field for backwards compatibility, it is available through - :attr:`~telegram.TelegramObject.api_kwargs`. - - .. versionchanged:: 21.3 - As per Bot API 7.3, most of the arguments and attributes of this class have now moved to - :class:`telegram.ChatFullInfo`. - - Args: - id (:obj:`int`): Unique identifier for this chat. - type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`, - :attr:`SUPERGROUP` or :attr:`CHANNEL`. - title (:obj:`str`, optional): Title, for supergroups, channels and group chats. - username (:obj:`str`, optional): Username, for private chats, supergroups and channels if - available. - first_name (:obj:`str`, optional): First name of the other party in a private chat. - last_name (:obj:`str`, optional): Last name of the other party in a private chat. - is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum - (has topics_ enabled). - - .. versionadded:: 20.0 - - Attributes: - id (:obj:`int`): Unique identifier for this chat. - type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`, - :attr:`SUPERGROUP` or :attr:`CHANNEL`. - title (:obj:`str`): Optional. Title, for supergroups, channels and group chats. - username (:obj:`str`): Optional. Username, for private chats, supergroups and channels if - available. - first_name (:obj:`str`): Optional. First name of the other party in a private chat. - last_name (:obj:`str`): Optional. Last name of the other party in a private chat. - is_forum (:obj:`bool`): Optional. :obj:`True`, if the supergroup chat is a forum - (has topics_ enabled). - - .. versionadded:: 20.0 - - .. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups - """ - - __slots__ = () diff --git a/venv/lib/python3.11/site-packages/telegram/_chatadministratorrights.py b/venv/lib/python3.11/site-packages/telegram/_chatadministratorrights.py deleted file mode 100755 index 6b6c437..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatadministratorrights.py +++ /dev/null @@ -1,247 +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 which represents a Telegram ChatAdministratorRights.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class ChatAdministratorRights(TelegramObject): - """Represents the rights of an administrator in a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`is_anonymous`, :attr:`can_manage_chat`, - :attr:`can_delete_messages`, :attr:`can_manage_video_chats`, :attr:`can_restrict_members`, - :attr:`can_promote_members`, :attr:`can_change_info`, :attr:`can_invite_users`, - :attr:`can_post_messages`, :attr:`can_edit_messages`, :attr:`can_pin_messages`, - :attr:`can_manage_topics`, :attr:`can_post_stories`, :attr:`can_delete_stories`, and - :attr:`can_edit_stories` are equal. - - .. versionadded:: 20.0 - - .. versionchanged:: 20.0 - :attr:`can_manage_topics` is considered as well when comparing objects of - this type in terms of equality. - - .. versionchanged:: 20.6 - :attr:`can_post_stories`, :attr:`can_edit_stories`, and :attr:`can_delete_stories` are - considered as well when comparing objects of this type in terms of equality. - - .. versionchanged:: 21.1 - As of this version, :attr:`can_post_stories`, :attr:`can_edit_stories`, - and :attr:`can_delete_stories` is now required. Thus, the order of arguments had to be - changed. - - Args: - is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. - can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, get boost list, see hidden supergroup and channel members, report spam messages - and ignore slow mode. Implied by any other administrator privilege. - can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of - other users. - can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video - chats. - can_restrict_members (:obj:`bool`): :obj:`True`, if the administrator can restrict, ban or - unban chat members, or access supergroup statistics. - can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new - administrators with a subset of their own privileges or demote administrators - that they have promoted, directly or indirectly (promoted by administrators that - were appointed by the user). - can_change_info (:obj:`bool`): :obj:`True`, if the user is allowed to change the chat title - , photo and other settings. - can_invite_users (:obj:`bool`): :obj:`True`, if the user is allowed to invite new users to - the chat. - can_post_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can post - messages in the channel, or access channel statistics; for channels only. - can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can edit - messages of other users and can pin messages; for channels only. - can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin - messages; for groups and supergroups only. - can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post - stories to the chat. - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted - by other users, post stories to the chat page, pin chat stories, and access the chat's - story archive - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete - stories posted by other users. - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed - to create, rename, close, and reopen forum topics; for supergroups only. - - .. versionadded:: 20.0 - - Attributes: - is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. - can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, get boost list, see hidden supergroup and channel members, report spam messages - and ignore slow mode. Implied by any other administrator privilege. - can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of - other users. - can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video - chats. - can_restrict_members (:obj:`bool`): :obj:`True`, if the administrator can restrict, ban or - unban chat members, or access supergroup statistics. - can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new - administrators with a subset of their own privileges or demote administrators that he - has promoted, directly or indirectly (promoted by administrators that were appointed by - the user.) - can_change_info (:obj:`bool`): :obj:`True`, if the user is allowed to change the chat title - ,photo and other settings. - can_invite_users (:obj:`bool`): :obj:`True`, if the user is allowed to invite new users to - the chat. - can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can post - messages in the channel, or access channel statistics; for channels only. - can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit - messages of other users and can pin messages; for channels only. - can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin - messages; for groups and supergroups only. - can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post - stories to the chat. - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted - by other users, post stories to the chat page, pin chat stories, and access the chat's - story archive - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete - stories posted by other users. - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed - to create, rename, close, and reopen forum topics; for supergroups only. - - .. versionadded:: 20.0 - """ - - __slots__ = ( - "can_change_info", - "can_delete_messages", - "can_delete_stories", - "can_edit_messages", - "can_edit_stories", - "can_invite_users", - "can_manage_chat", - "can_manage_topics", - "can_manage_video_chats", - "can_pin_messages", - "can_post_messages", - "can_post_stories", - "can_promote_members", - "can_restrict_members", - "is_anonymous", - ) - - def __init__( - self, - is_anonymous: bool, - can_manage_chat: bool, - can_delete_messages: bool, - can_manage_video_chats: bool, - can_restrict_members: bool, - can_promote_members: bool, - can_change_info: bool, - can_invite_users: bool, - can_post_stories: bool, - can_edit_stories: bool, - can_delete_stories: bool, - can_post_messages: Optional[bool] = None, - can_edit_messages: Optional[bool] = None, - can_pin_messages: Optional[bool] = None, - can_manage_topics: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - # Required - self.is_anonymous: bool = is_anonymous - self.can_manage_chat: bool = can_manage_chat - self.can_delete_messages: bool = can_delete_messages - self.can_manage_video_chats: bool = can_manage_video_chats - self.can_restrict_members: bool = can_restrict_members - self.can_promote_members: bool = can_promote_members - self.can_change_info: bool = can_change_info - self.can_invite_users: bool = can_invite_users - self.can_post_stories: bool = can_post_stories - self.can_edit_stories: bool = can_edit_stories - self.can_delete_stories: bool = can_delete_stories - # Optionals - self.can_post_messages: Optional[bool] = can_post_messages - self.can_edit_messages: Optional[bool] = can_edit_messages - self.can_pin_messages: Optional[bool] = can_pin_messages - self.can_manage_topics: Optional[bool] = can_manage_topics - - self._id_attrs = ( - self.is_anonymous, - self.can_manage_chat, - self.can_delete_messages, - self.can_manage_video_chats, - self.can_restrict_members, - self.can_promote_members, - self.can_change_info, - self.can_invite_users, - self.can_post_messages, - self.can_edit_messages, - self.can_pin_messages, - self.can_manage_topics, - self.can_post_stories, - self.can_edit_stories, - self.can_delete_stories, - ) - - self._freeze() - - @classmethod - def all_rights(cls) -> "ChatAdministratorRights": - """ - This method returns the :class:`ChatAdministratorRights` object with all attributes set to - :obj:`True`. This is e.g. useful when changing the bot's default administrator rights with - :meth:`telegram.Bot.set_my_default_administrator_rights`. - - .. versionadded:: 20.0 - """ - return cls(*(True,) * len(cls.__slots__)) - - @classmethod - def no_rights(cls) -> "ChatAdministratorRights": - """ - This method returns the :class:`ChatAdministratorRights` object with all attributes set to - :obj:`False`. - - .. versionadded:: 20.0 - """ - return cls(*(False,) * len(cls.__slots__)) diff --git a/venv/lib/python3.11/site-packages/telegram/_chatbackground.py b/venv/lib/python3.11/site-packages/telegram/_chatbackground.py deleted file mode 100755 index 4d41e55..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatbackground.py +++ /dev/null @@ -1,547 +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 chat backgrounds.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._files.document import Document -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class BackgroundFill(TelegramObject): - """Base class for Telegram BackgroundFill Objects. It can be one of: - - * :class:`telegram.BackgroundFillSolid` - * :class:`telegram.BackgroundFillGradient` - * :class:`telegram.BackgroundFillFreeformGradient` - - 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.2 - - Args: - type (:obj:`str`): Type of the background fill. Can be one of: - :attr:`~telegram.BackgroundFill.SOLID`, :attr:`~telegram.BackgroundFill.GRADIENT` - or :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`. - - Attributes: - type (:obj:`str`): Type of the background fill. Can be one of: - :attr:`~telegram.BackgroundFill.SOLID`, :attr:`~telegram.BackgroundFill.GRADIENT` - or :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`. - """ - - __slots__ = ("type",) - - SOLID: Final[constants.BackgroundFillType] = constants.BackgroundFillType.SOLID - """:const:`telegram.constants.BackgroundFillType.SOLID`""" - GRADIENT: Final[constants.BackgroundFillType] = constants.BackgroundFillType.GRADIENT - """:const:`telegram.constants.BackgroundFillType.GRADIENT`""" - FREEFORM_GRADIENT: Final[constants.BackgroundFillType] = ( - constants.BackgroundFillType.FREEFORM_GRADIENT - ) - """:const:`telegram.constants.BackgroundFillType.FREEFORM_GRADIENT`""" - - def __init__( - self, - type: str, # pylint: disable=redefined-builtin - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required by all subclasses - self.type: str = enum.get_member(constants.BackgroundFillType, type, type) - - self._id_attrs = (self.type,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["BackgroundFill"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - _class_mapping: dict[str, type[BackgroundFill]] = { - cls.SOLID: BackgroundFillSolid, - cls.GRADIENT: BackgroundFillGradient, - cls.FREEFORM_GRADIENT: BackgroundFillFreeformGradient, - } - - if cls is BackgroundFill 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 BackgroundFillSolid(BackgroundFill): - """ - The background is filled using the selected color. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`color` is equal. - - .. versionadded:: 21.2 - - Args: - color (:obj:`int`): The color of the background fill in the `RGB24` format. - - Attributes: - type (:obj:`str`): Type of the background fill. Always - :attr:`~telegram.BackgroundFill.SOLID`. - color (:obj:`int`): The color of the background fill in the `RGB24` format. - """ - - __slots__ = ("color",) - - def __init__( - self, - color: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.SOLID, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.color: int = color - - self._id_attrs = (self.color,) - - -class BackgroundFillGradient(BackgroundFill): - """ - The background is a gradient fill. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`top_color`, :attr:`bottom_color` - and :attr:`rotation_angle` are equal. - - .. versionadded:: 21.2 - - Args: - top_color (:obj:`int`): Top color of the gradient in the `RGB24` format. - bottom_color (:obj:`int`): Bottom color of the gradient in the `RGB24` format. - rotation_angle (:obj:`int`): Clockwise rotation angle of the background - fill in degrees; - 0-:tg-const:`telegram.constants.BackgroundFillLimit.MAX_ROTATION_ANGLE`. - - - Attributes: - type (:obj:`str`): Type of the background fill. Always - :attr:`~telegram.BackgroundFill.GRADIENT`. - top_color (:obj:`int`): Top color of the gradient in the `RGB24` format. - bottom_color (:obj:`int`): Bottom color of the gradient in the `RGB24` format. - rotation_angle (:obj:`int`): Clockwise rotation angle of the background - fill in degrees; - 0-:tg-const:`telegram.constants.BackgroundFillLimit.MAX_ROTATION_ANGLE`. - """ - - __slots__ = ("bottom_color", "rotation_angle", "top_color") - - def __init__( - self, - top_color: int, - bottom_color: int, - rotation_angle: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.GRADIENT, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.top_color: int = top_color - self.bottom_color: int = bottom_color - self.rotation_angle: int = rotation_angle - - self._id_attrs = (self.top_color, self.bottom_color, self.rotation_angle) - - -class BackgroundFillFreeformGradient(BackgroundFill): - """ - The background is a freeform gradient that rotates after every message in the chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`colors` is equal. - - .. versionadded:: 21.2 - - Args: - colors (Sequence[:obj:`int`]): A list of the 3 or 4 base colors that are used to - generate the freeform gradient in the `RGB24` format - - Attributes: - type (:obj:`str`): Type of the background fill. Always - :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`. - colors (Sequence[:obj:`int`]): A list of the 3 or 4 base colors that are used to - generate the freeform gradient in the `RGB24` format - """ - - __slots__ = ("colors",) - - def __init__( - self, - colors: Sequence[int], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.FREEFORM_GRADIENT, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.colors: tuple[int, ...] = parse_sequence_arg(colors) - - self._id_attrs = (self.colors,) - - -class BackgroundType(TelegramObject): - """Base class for Telegram BackgroundType Objects. It can be one of: - - * :class:`telegram.BackgroundTypeFill` - * :class:`telegram.BackgroundTypeWallpaper` - * :class:`telegram.BackgroundTypePattern` - * :class:`telegram.BackgroundTypeChatTheme`. - - 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.2 - - Args: - type (:obj:`str`): Type of the background. Can be one of: - :attr:`~telegram.BackgroundType.FILL`, :attr:`~telegram.BackgroundType.WALLPAPER` - :attr:`~telegram.BackgroundType.PATTERN` or - :attr:`~telegram.BackgroundType.CHAT_THEME`. - - Attributes: - type (:obj:`str`): Type of the background. Can be one of: - :attr:`~telegram.BackgroundType.FILL`, :attr:`~telegram.BackgroundType.WALLPAPER` - :attr:`~telegram.BackgroundType.PATTERN` or - :attr:`~telegram.BackgroundType.CHAT_THEME`. - - """ - - __slots__ = ("type",) - - FILL: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.FILL - """:const:`telegram.constants.BackgroundTypeType.FILL`""" - WALLPAPER: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.WALLPAPER - """:const:`telegram.constants.BackgroundTypeType.WALLPAPER`""" - PATTERN: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.PATTERN - """:const:`telegram.constants.BackgroundTypeType.PATTERN`""" - CHAT_THEME: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.CHAT_THEME - """:const:`telegram.constants.BackgroundTypeType.CHAT_THEME`""" - - def __init__( - self, - type: str, # pylint: disable=redefined-builtin - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required by all subclasses - self.type: str = enum.get_member(constants.BackgroundTypeType, type, type) - - self._id_attrs = (self.type,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["BackgroundType"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - _class_mapping: dict[str, type[BackgroundType]] = { - cls.FILL: BackgroundTypeFill, - cls.WALLPAPER: BackgroundTypeWallpaper, - cls.PATTERN: BackgroundTypePattern, - cls.CHAT_THEME: BackgroundTypeChatTheme, - } - - if cls is BackgroundType and data.get("type") in _class_mapping: - return _class_mapping[data.pop("type")].de_json(data=data, bot=bot) - - if "fill" in data: - data["fill"] = BackgroundFill.de_json(data.get("fill"), bot) - - if "document" in data: - data["document"] = Document.de_json(data.get("document"), bot) - - return super().de_json(data=data, bot=bot) - - -class BackgroundTypeFill(BackgroundType): - """ - The background is automatically filled based on the selected colors. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`fill` and :attr:`dark_theme_dimming` are equal. - - .. versionadded:: 21.2 - - Args: - fill (:class:`telegram.BackgroundFill`): The background fill. - dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a - percentage; - 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`. - - Attributes: - type (:obj:`str`): Type of the background. Always - :attr:`~telegram.BackgroundType.FILL`. - fill (:class:`telegram.BackgroundFill`): The background fill. - dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a - percentage; - 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`. - """ - - __slots__ = ("dark_theme_dimming", "fill") - - def __init__( - self, - fill: BackgroundFill, - dark_theme_dimming: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.FILL, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.fill: BackgroundFill = fill - self.dark_theme_dimming: int = dark_theme_dimming - - self._id_attrs = (self.fill, self.dark_theme_dimming) - - -class BackgroundTypeWallpaper(BackgroundType): - """ - The background is a wallpaper in the `JPEG` format. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`document` and :attr:`dark_theme_dimming` are equal. - - .. versionadded:: 21.2 - - Args: - document (:class:`telegram.Document`): Document with the wallpaper - dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a - percentage; - 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`. - is_blurred (:obj:`bool`, optional): :obj:`True`, if the wallpaper is downscaled to fit - in a 450x450 square and then box-blurred with radius 12 - is_moving (:obj:`bool`, optional): :obj:`True`, if the background moves slightly - when the device is tilted - - Attributes: - type (:obj:`str`): Type of the background. Always - :attr:`~telegram.BackgroundType.WALLPAPER`. - document (:class:`telegram.Document`): Document with the wallpaper - dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a - percentage; - 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`. - is_blurred (:obj:`bool`): Optional. :obj:`True`, if the wallpaper is downscaled to fit - in a 450x450 square and then box-blurred with radius 12 - is_moving (:obj:`bool`): Optional. :obj:`True`, if the background moves slightly - when the device is tilted - """ - - __slots__ = ("dark_theme_dimming", "document", "is_blurred", "is_moving") - - def __init__( - self, - document: Document, - dark_theme_dimming: int, - is_blurred: Optional[bool] = None, - is_moving: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.WALLPAPER, api_kwargs=api_kwargs) - - with self._unfrozen(): - # Required - self.document: Document = document - self.dark_theme_dimming: int = dark_theme_dimming - # Optionals - self.is_blurred: Optional[bool] = is_blurred - self.is_moving: Optional[bool] = is_moving - - self._id_attrs = (self.document, self.dark_theme_dimming) - - -class BackgroundTypePattern(BackgroundType): - """ - The background is a `PNG` or `TGV` (gzipped subset of `SVG` with `MIME` type - `"application/x-tgwallpattern"`) pattern to be combined with the background fill - chosen by the user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`document` and :attr:`fill` and :attr:`intensity` are equal. - - .. versionadded:: 21.2 - - Args: - document (:class:`telegram.Document`): Document with the pattern. - fill (:class:`telegram.BackgroundFill`): The background fill that is combined with - the pattern. - intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled - background; - 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_INTENSITY`. - is_inverted (:obj:`int`, optional): :obj:`True`, if the background fill must be applied - only to the pattern itself. All other pixels are black in this case. For dark - themes only. - is_moving (:obj:`bool`, optional): :obj:`True`, if the background moves slightly - when the device is tilted. - - Attributes: - type (:obj:`str`): Type of the background. Always - :attr:`~telegram.BackgroundType.PATTERN`. - document (:class:`telegram.Document`): Document with the pattern. - fill (:class:`telegram.BackgroundFill`): The background fill that is combined with - the pattern. - intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled - background; - 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_INTENSITY`. - is_inverted (:obj:`int`): Optional. :obj:`True`, if the background fill must be applied - only to the pattern itself. All other pixels are black in this case. For dark - themes only. - is_moving (:obj:`bool`): Optional. :obj:`True`, if the background moves slightly - when the device is tilted. - """ - - __slots__ = ( - "document", - "fill", - "intensity", - "is_inverted", - "is_moving", - ) - - def __init__( - self, - document: Document, - fill: BackgroundFill, - intensity: int, - is_inverted: Optional[bool] = None, - is_moving: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.PATTERN, api_kwargs=api_kwargs) - - with self._unfrozen(): - # Required - self.document: Document = document - self.fill: BackgroundFill = fill - self.intensity: int = intensity - # Optionals - self.is_inverted: Optional[bool] = is_inverted - self.is_moving: Optional[bool] = is_moving - - self._id_attrs = (self.document, self.fill, self.intensity) - - -class BackgroundTypeChatTheme(BackgroundType): - """ - The background is taken directly from a built-in chat theme. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`theme_name` is equal. - - .. versionadded:: 21.2 - - Args: - theme_name (:obj:`str`): Name of the chat theme, which is usually an emoji. - - Attributes: - type (:obj:`str`): Type of the background. Always - :attr:`~telegram.BackgroundType.CHAT_THEME`. - theme_name (:obj:`str`): Name of the chat theme, which is usually an emoji. - """ - - __slots__ = ("theme_name",) - - def __init__( - self, - theme_name: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.CHAT_THEME, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.theme_name: str = theme_name - - self._id_attrs = (self.theme_name,) - - -class ChatBackground(TelegramObject): - """ - This object represents a chat background. - - 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.2 - - Args: - type (:class:`telegram.BackgroundType`): Type of the background. - - Attributes: - type (:class:`telegram.BackgroundType`): Type of the background. - """ - - __slots__ = ("type",) - - def __init__( - self, - type: BackgroundType, # pylint: disable=redefined-builtin - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.type: BackgroundType = type - - self._id_attrs = (self.type,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatBackground"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["type"] = BackgroundType.de_json(data.get("type"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_chatboost.py b/venv/lib/python3.11/site-packages/telegram/_chatboost.py deleted file mode 100755 index 6f45a27..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatboost.py +++ /dev/null @@ -1,464 +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 that represent Telegram ChatBoosts.""" -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._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.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ChatBoostAdded(TelegramObject): - """ - This object represents a service message about a user boosting a chat. - - Objects of this class are comparable in terms of equality. - Two objects of this class are considered equal, if their - :attr:`boost_count` are equal. - - .. versionadded:: 21.0 - - Args: - boost_count (:obj:`int`): Number of boosts added by the user. - - Attributes: - boost_count (:obj:`int`): Number of boosts added by the user. - - """ - - __slots__ = ("boost_count",) - - def __init__( - self, - boost_count: int, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.boost_count: int = boost_count - self._id_attrs = (self.boost_count,) - - self._freeze() - - -class ChatBoostSource(TelegramObject): - """ - Base class for Telegram ChatBoostSource objects. It can be one of: - - * :class:`telegram.ChatBoostSourcePremium` - * :class:`telegram.ChatBoostSourceGiftCode` - * :class:`telegram.ChatBoostSourceGiveaway` - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source` is equal. - - .. versionadded:: 20.8 - - Args: - source (:obj:`str`): The source of the chat boost. Can be one of: - :attr:`~telegram.ChatBoostSource.PREMIUM`, :attr:`~telegram.ChatBoostSource.GIFT_CODE`, - or :attr:`~telegram.ChatBoostSource.GIVEAWAY`. - - Attributes: - source (:obj:`str`): The source of the chat boost. Can be one of: - :attr:`~telegram.ChatBoostSource.PREMIUM`, :attr:`~telegram.ChatBoostSource.GIFT_CODE`, - or :attr:`~telegram.ChatBoostSource.GIVEAWAY`. - """ - - __slots__ = ("source",) - - PREMIUM: Final[str] = constants.ChatBoostSources.PREMIUM - """:const:`telegram.constants.ChatBoostSources.PREMIUM`""" - GIFT_CODE: Final[str] = constants.ChatBoostSources.GIFT_CODE - """:const:`telegram.constants.ChatBoostSources.GIFT_CODE`""" - GIVEAWAY: Final[str] = constants.ChatBoostSources.GIVEAWAY - """:const:`telegram.constants.ChatBoostSources.GIVEAWAY`""" - - def __init__(self, source: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - - # Required by all subclasses: - self.source: str = enum.get_member(constants.ChatBoostSources, source, source) - - self._id_attrs = (self.source,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatBoostSource"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - _class_mapping: dict[str, type[ChatBoostSource]] = { - cls.PREMIUM: ChatBoostSourcePremium, - cls.GIFT_CODE: ChatBoostSourceGiftCode, - cls.GIVEAWAY: ChatBoostSourceGiveaway, - } - - if cls is ChatBoostSource and data.get("source") in _class_mapping: - return _class_mapping[data.pop("source")].de_json(data=data, bot=bot) - - if "user" in data: - data["user"] = User.de_json(data.get("user"), bot) - - return super().de_json(data=data, bot=bot) - - -class ChatBoostSourcePremium(ChatBoostSource): - """ - The boost was obtained by subscribing to Telegram Premium or by gifting a Telegram Premium - subscription to another user. - - .. versionadded:: 20.8 - - Args: - user (:class:`telegram.User`): User that boosted the chat. - - Attributes: - source (:obj:`str`): The source of the chat boost. Always - :attr:`~telegram.ChatBoostSource.PREMIUM`. - user (:class:`telegram.User`): User that boosted the chat. - """ - - __slots__ = ("user",) - - def __init__(self, user: User, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(source=self.PREMIUM, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.user: User = user - - -class ChatBoostSourceGiftCode(ChatBoostSource): - """ - The boost was obtained by the creation of Telegram Premium gift codes to boost a chat. Each - such code boosts the chat 4 times for the duration of the corresponding Telegram Premium - subscription. - - .. versionadded:: 20.8 - - Args: - user (:class:`telegram.User`): User for which the gift code was created. - - Attributes: - source (:obj:`str`): The source of the chat boost. Always - :attr:`~telegram.ChatBoostSource.GIFT_CODE`. - user (:class:`telegram.User`): User for which the gift code was created. - """ - - __slots__ = ("user",) - - def __init__(self, user: User, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(source=self.GIFT_CODE, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.user: User = user - - -class ChatBoostSourceGiveaway(ChatBoostSource): - """ - The boost was obtained by the creation of a Telegram Premium giveaway or a Telegram Star. - This boosts the chat 4 times for the duration of the corresponding Telegram Premium - subscription for Telegram Premium giveaways and :attr:`prize_star_count` / 500 times for - one year for Telegram Star giveaways. - - .. versionadded:: 20.8 - - Args: - giveaway_message_id (:obj:`int`): Identifier of a message in the chat with the giveaway; - the message could have been deleted already. May be 0 if the message isn't sent yet. - user (:class:`telegram.User`, optional): User that won the prize in the giveaway if any; - for Telegram Premium giveaways only. - prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between - giveaway winners; for Telegram Star giveaways only. - - .. versionadded:: 21.6 - is_unclaimed (:obj:`bool`, optional): :obj:`True`, if the giveaway was completed, but - there was no user to win the prize. - - Attributes: - source (:obj:`str`): Source of the boost. Always - :attr:`~telegram.ChatBoostSource.GIVEAWAY`. - giveaway_message_id (:obj:`int`): Identifier of a message in the chat with the giveaway; - the message could have been deleted already. May be 0 if the message isn't sent yet. - user (:class:`telegram.User`): Optional. User that won the prize in the giveaway if any. - prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between - giveaway winners; for Telegram Star giveaways only. - - .. versionadded:: 21.6 - is_unclaimed (:obj:`bool`): Optional. :obj:`True`, if the giveaway was completed, but - there was no user to win the prize. - """ - - __slots__ = ("giveaway_message_id", "is_unclaimed", "prize_star_count", "user") - - def __init__( - self, - giveaway_message_id: int, - user: Optional[User] = None, - is_unclaimed: Optional[bool] = None, - prize_star_count: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(source=self.GIVEAWAY, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.giveaway_message_id: int = giveaway_message_id - self.user: Optional[User] = user - self.prize_star_count: Optional[int] = prize_star_count - self.is_unclaimed: Optional[bool] = is_unclaimed - - -class ChatBoost(TelegramObject): - """ - This object contains information about a chat boost. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`boost_id`, :attr:`add_date`, :attr:`expiration_date`, - and :attr:`source` are equal. - - .. versionadded:: 20.8 - - Args: - boost_id (:obj:`str`): Unique identifier of the boost. - add_date (:obj:`datetime.datetime`): Point in time when the chat was boosted. - expiration_date (:obj:`datetime.datetime`): Point in time when the boost - will automatically expire, unless the booster's Telegram Premium subscription is - prolonged. - source (:class:`telegram.ChatBoostSource`): Source of the added boost. - - Attributes: - boost_id (:obj:`str`): Unique identifier of the boost. - add_date (:obj:`datetime.datetime`): Point in time when the chat was boosted. - |datetime_localization| - expiration_date (:obj:`datetime.datetime`): Point in time when the boost - will automatically expire, unless the booster's Telegram Premium subscription is - prolonged. |datetime_localization| - source (:class:`telegram.ChatBoostSource`): Source of the added boost. - """ - - __slots__ = ("add_date", "boost_id", "expiration_date", "source") - - def __init__( - self, - boost_id: str, - add_date: dtm.datetime, - expiration_date: dtm.datetime, - source: ChatBoostSource, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.boost_id: str = boost_id - self.add_date: dtm.datetime = add_date - self.expiration_date: dtm.datetime = expiration_date - self.source: ChatBoostSource = source - - self._id_attrs = (self.boost_id, self.add_date, self.expiration_date, self.source) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatBoost"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["source"] = ChatBoostSource.de_json(data.get("source"), bot) - loc_tzinfo = extract_tzinfo_from_defaults(bot) - data["add_date"] = from_timestamp(data["add_date"], tzinfo=loc_tzinfo) - data["expiration_date"] = from_timestamp(data["expiration_date"], tzinfo=loc_tzinfo) - - return super().de_json(data=data, bot=bot) - - -class ChatBoostUpdated(TelegramObject): - """This object represents a boost added to a chat or changed. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`chat`, and :attr:`boost` are equal. - - .. versionadded:: 20.8 - - Args: - chat (:class:`telegram.Chat`): Chat which was boosted. - boost (:class:`telegram.ChatBoost`): Information about the chat boost. - - Attributes: - chat (:class:`telegram.Chat`): Chat which was boosted. - boost (:class:`telegram.ChatBoost`): Information about the chat boost. - """ - - __slots__ = ("boost", "chat") - - def __init__( - self, - chat: Chat, - boost: ChatBoost, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.chat: Chat = chat - self.boost: ChatBoost = boost - - self._id_attrs = (self.chat.id, self.boost) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatBoostUpdated"]: - """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) - data["boost"] = ChatBoost.de_json(data.get("boost"), bot) - - return super().de_json(data=data, bot=bot) - - -class ChatBoostRemoved(TelegramObject): - """ - This object represents a boost removed from a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`chat`, :attr:`boost_id`, :attr:`remove_date`, and - :attr:`source` are equal. - - Args: - chat (:class:`telegram.Chat`): Chat which was boosted. - boost_id (:obj:`str`): Unique identifier of the boost. - remove_date (:obj:`datetime.datetime`): Point in time when the boost was removed. - source (:class:`telegram.ChatBoostSource`): Source of the removed boost. - - Attributes: - chat (:class:`telegram.Chat`): Chat which was boosted. - boost_id (:obj:`str`): Unique identifier of the boost. - remove_date (:obj:`datetime.datetime`): Point in time when the boost was removed. - |datetime_localization| - source (:class:`telegram.ChatBoostSource`): Source of the removed boost. - """ - - __slots__ = ("boost_id", "chat", "remove_date", "source") - - def __init__( - self, - chat: Chat, - boost_id: str, - remove_date: dtm.datetime, - source: ChatBoostSource, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.chat: Chat = chat - self.boost_id: str = boost_id - self.remove_date: dtm.datetime = remove_date - self.source: ChatBoostSource = source - - self._id_attrs = (self.chat, self.boost_id, self.remove_date, self.source) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatBoostRemoved"]: - """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) - data["source"] = ChatBoostSource.de_json(data.get("source"), bot) - loc_tzinfo = extract_tzinfo_from_defaults(bot) - data["remove_date"] = from_timestamp(data["remove_date"], tzinfo=loc_tzinfo) - - return super().de_json(data=data, bot=bot) - - -class UserChatBoosts(TelegramObject): - """This object represents a list of boosts added to a chat by a user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`boosts` are equal. - - .. versionadded:: 20.8 - - Args: - boosts (Sequence[:class:`telegram.ChatBoost`]): List of boosts added to the chat by the - user. - - Attributes: - boosts (tuple[:class:`telegram.ChatBoost`]): List of boosts added to the chat by the user. - """ - - __slots__ = ("boosts",) - - def __init__( - self, - boosts: Sequence[ChatBoost], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.boosts: tuple[ChatBoost, ...] = parse_sequence_arg(boosts) - - self._id_attrs = (self.boosts,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["UserChatBoosts"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["boosts"] = ChatBoost.de_list(data.get("boosts"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_chatfullinfo.py b/venv/lib/python3.11/site-packages/telegram/_chatfullinfo.py deleted file mode 100755 index ebf8e8e..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatfullinfo.py +++ /dev/null @@ -1,552 +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 ChatFullInfo.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._birthdate import Birthdate -from telegram._chat import Chat, _ChatBase -from telegram._chatlocation import ChatLocation -from telegram._chatpermissions import ChatPermissions -from telegram._files.chatphoto import ChatPhoto -from telegram._reaction import ReactionType -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, BusinessIntro, BusinessLocation, BusinessOpeningHours, Message - - -class ChatFullInfo(_ChatBase): - """ - This object contains full information about a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`~telegram.Chat.id` is equal. - - .. versionadded:: 21.2 - - .. versionchanged:: 21.3 - Explicit support for all shortcut methods known from :class:`telegram.Chat` on this - object. Previously those were only available because this class inherited from - :class:`telegram.Chat`. - - Args: - id (:obj:`int`): Unique identifier for this chat. - type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`, - :attr:`SUPERGROUP` or :attr:`CHANNEL`. - accent_color_id (:obj:`int`, optional): Identifier of the - :class:`accent color ` for the chat name and - backgrounds of the chat photo, reply header, and link preview. See `accent colors`_ - for more details. - - .. versionadded:: 20.8 - max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a - message in the chat. - - .. versionadded:: 21.2 - title (:obj:`str`, optional): Title, for supergroups, channels and group chats. - username (:obj:`str`, optional): Username, for private chats, supergroups and channels if - available. - first_name (:obj:`str`, optional): First name of the other party in a private chat. - last_name (:obj:`str`, optional): Last name of the other party in a private chat. - is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum - (has topics_ enabled). - - .. versionadded:: 20.0 - photo (:class:`telegram.ChatPhoto`, optional): Chat photo. - active_usernames (Sequence[:obj:`str`], optional): If set, the list of all `active chat - usernames `_; for private chats, supergroups and channels. - - .. versionadded:: 20.0 - birthdate (:class:`telegram.Birthdate`, optional): For private chats, - the date of birth of the user. - - .. versionadded:: 21.1 - business_intro (:class:`telegram.BusinessIntro`, optional): For private chats with - business accounts, the intro of the business. - - .. versionadded:: 21.1 - business_location (:class:`telegram.BusinessLocation`, optional): For private chats with - business accounts, the location of the business. - - .. versionadded:: 21.1 - business_opening_hours (:class:`telegram.BusinessOpeningHours`, optional): For private - chats with business accounts, the opening hours of the business. - - .. versionadded:: 21.1 - personal_chat (:class:`telegram.Chat`, optional): For private chats, the personal channel - of the user. - - .. versionadded:: 21.1 - available_reactions (Sequence[:class:`telegram.ReactionType`], optional): List of available - reactions allowed in the chat. If omitted, then all of - :const:`telegram.constants.ReactionEmoji` are allowed. - - .. versionadded:: 20.8 - background_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji chosen - by the chat for the reply header and link preview background. - - .. versionadded:: 20.8 - profile_accent_color_id (:obj:`int`, optional): Identifier of the - :class:`accent color ` for the chat's profile - background. See profile `accent colors`_ for more details. - - .. versionadded:: 20.8 - profile_background_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of - the emoji chosen by the chat for its profile background. - - .. versionadded:: 20.8 - emoji_status_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji - status of the chat or the other party in a private chat. - - .. versionadded:: 20.0 - emoji_status_expiration_date (:class:`datetime.datetime`, optional): Expiration date of - emoji status of the chat or the other party in a private chat, as a datetime object, - if any. - - |datetime_localization| - - .. versionadded:: 20.5 - bio (:obj:`str`, optional): Bio of the other party in a private chat. - has_private_forwards (:obj:`bool`, optional): :obj:`True`, if privacy settings of the other - party in the private chat allows to use ``tg://user?id=`` links only in chats - with the user. - - .. versionadded:: 13.9 - has_restricted_voice_and_video_messages (:obj:`bool`, optional): :obj:`True`, if the - privacy settings of the other party restrict sending voice and video note messages - in the private chat. - - .. versionadded:: 20.0 - join_to_send_messages (:obj:`bool`, optional): :obj:`True`, if users need to join the - supergroup before they can send messages. - - .. versionadded:: 20.0 - join_by_request (:obj:`bool`, optional): :obj:`True`, if all users directly joining the - supergroup without using an invite link need to be approved by supergroup - administrators. - - .. versionadded:: 20.0 - description (:obj:`str`, optional): Description, for groups, supergroups and channel chats. - invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and - channel. - pinned_message (:class:`telegram.Message`, optional): The most recent pinned message - (by sending date). - permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions, - for groups and supergroups. - slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between - consecutive messages sent by each unprivileged user. - unrestrict_boost_count (:obj:`int`, optional): For supergroups, the minimum number of - boosts that a non-administrator user needs to add in order to ignore slow mode and chat - permissions. - - .. versionadded:: 21.0 - message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to - the chat will be automatically deleted; in seconds. - - .. versionadded:: 13.4 - has_aggressive_anti_spam_enabled (:obj:`bool`, optional): :obj:`True`, if aggressive - anti-spam checks are enabled in the supergroup. The field is only available to chat - administrators. - - .. versionadded:: 20.0 - has_hidden_members (:obj:`bool`, optional): :obj:`True`, if non-administrators can only - get the list of bots and administrators in the chat. - - .. versionadded:: 20.0 - has_protected_content (:obj:`bool`, optional): :obj:`True`, if messages from the chat can't - be forwarded to other chats. - - .. versionadded:: 13.9 - has_visible_history (:obj:`bool`, optional): :obj:`True`, if new chat members will have - access to old messages; available only to chat administrators. - - .. versionadded:: 20.8 - sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set. - can_set_sticker_set (:obj:`bool`, optional): :obj:`True`, if the bot can change group the - sticker set. - custom_emoji_sticker_set_name (:obj:`str`, optional): For supergroups, the name of the - group's custom emoji sticker set. Custom emoji from this set can be used by all users - and bots in the group. - - .. versionadded:: 21.0 - linked_chat_id (:obj:`int`, optional): Unique identifier for the linked chat, i.e. the - discussion group identifier for a channel and vice versa; for supergroups and channel - chats. - location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which - the supergroup is connected. - can_send_paid_media (:obj:`bool`, optional): :obj:`True`, if paid media messages can be - sent or forwarded to the channel chat. The field is available only for channel chats. - - .. versionadded:: 21.4 - - Attributes: - id (:obj:`int`): Unique identifier for this chat. - type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`, - :attr:`SUPERGROUP` or :attr:`CHANNEL`. - accent_color_id (:obj:`int`): Optional. Identifier of the - :class:`accent color ` for the chat name and - backgrounds of the chat photo, reply header, and link preview. See `accent colors`_ - for more details. - - .. versionadded:: 20.8 - max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a - message in the chat. - - .. versionadded:: 21.2 - title (:obj:`str`, optional): Title, for supergroups, channels and group chats. - username (:obj:`str`, optional): Username, for private chats, supergroups and channels if - available. - first_name (:obj:`str`, optional): First name of the other party in a private chat. - last_name (:obj:`str`, optional): Last name of the other party in a private chat. - is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum - (has topics_ enabled). - - .. versionadded:: 20.0 - photo (:class:`telegram.ChatPhoto`): Optional. Chat photo. - active_usernames (tuple[:obj:`str`]): Optional. If set, the list of all `active chat - usernames `_; for private chats, supergroups and channels. - - This list is empty if the chat has no active usernames or this chat instance was not - obtained via :meth:`~telegram.Bot.get_chat`. - - .. versionadded:: 20.0 - birthdate (:class:`telegram.Birthdate`): Optional. For private chats, - the date of birth of the user. - - .. versionadded:: 21.1 - business_intro (:class:`telegram.BusinessIntro`): Optional. For private chats with - business accounts, the intro of the business. - - .. versionadded:: 21.1 - business_location (:class:`telegram.BusinessLocation`): Optional. For private chats with - business accounts, the location of the business. - - .. versionadded:: 21.1 - business_opening_hours (:class:`telegram.BusinessOpeningHours`): Optional. For private - chats with business accounts, the opening hours of the business. - - .. versionadded:: 21.1 - personal_chat (:class:`telegram.Chat`): Optional. For private chats, the personal channel - of the user. - - .. versionadded:: 21.1 - available_reactions (tuple[:class:`telegram.ReactionType`]): Optional. List of available - reactions allowed in the chat. If omitted, then all of - :const:`telegram.constants.ReactionEmoji` are allowed. - - .. versionadded:: 20.8 - background_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji chosen - by the chat for the reply header and link preview background. - - .. versionadded:: 20.8 - profile_accent_color_id (:obj:`int`): Optional. Identifier of the - :class:`accent color ` for the chat's profile - background. See profile `accent colors`_ for more details. - - .. versionadded:: 20.8 - profile_background_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of - the emoji chosen by the chat for its profile background. - - .. versionadded:: 20.8 - emoji_status_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji - status of the chat or the other party in a private chat. - - .. versionadded:: 20.0 - emoji_status_expiration_date (:class:`datetime.datetime`): Optional. Expiration date of - emoji status of the chat or the other party in a private chat, as a datetime object, - if any. - - |datetime_localization| - - .. versionadded:: 20.5 - bio (:obj:`str`): Optional. Bio of the other party in a private chat. - has_private_forwards (:obj:`bool`): Optional. :obj:`True`, if privacy settings of the other - party in the private chat allows to use ``tg://user?id=`` links only in chats - with the user. - - .. versionadded:: 13.9 - has_restricted_voice_and_video_messages (:obj:`bool`): Optional. :obj:`True`, if the - privacy settings of the other party restrict sending voice and video note messages - in the private chat. - - .. versionadded:: 20.0 - join_to_send_messages (:obj:`bool`): Optional. :obj:`True`, if users need to join - the supergroup before they can send messages. - - .. versionadded:: 20.0 - join_by_request (:obj:`bool`): Optional. :obj:`True`, if all users directly joining the - supergroup without using an invite link need to be approved by supergroup - administrators. - - .. versionadded:: 20.0 - description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats. - invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and - channel. - pinned_message (:class:`telegram.Message`): Optional. The most recent pinned message - (by sending date). - permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions, - for groups and supergroups. - slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between - consecutive messages sent by each unprivileged user. - unrestrict_boost_count (:obj:`int`): Optional. For supergroups, the minimum number of - boosts that a non-administrator user needs to add in order to ignore slow mode and chat - permissions. - - .. versionadded:: 21.0 - message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to - the chat will be automatically deleted; in seconds. - - .. versionadded:: 13.4 - has_aggressive_anti_spam_enabled (:obj:`bool`): Optional. :obj:`True`, if aggressive - anti-spam checks are enabled in the supergroup. The field is only available to chat - administrators. - - .. versionadded:: 20.0 - has_hidden_members (:obj:`bool`): Optional. :obj:`True`, if non-administrators can only - get the list of bots and administrators in the chat. - - .. versionadded:: 20.0 - has_protected_content (:obj:`bool`): Optional. :obj:`True`, if messages from the chat can't - be forwarded to other chats. - - .. versionadded:: 13.9 - has_visible_history (:obj:`bool`): Optional. :obj:`True`, if new chat members will have - access to old messages; available only to chat administrators. - - .. versionadded:: 20.8 - sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set. - can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the - sticker set. - custom_emoji_sticker_set_name (:obj:`str`): Optional. For supergroups, the name of the - group's custom emoji sticker set. Custom emoji from this set can be used by all users - and bots in the group. - - .. versionadded:: 21.0 - linked_chat_id (:obj:`int`): Optional. Unique identifier for the linked chat, i.e. the - discussion group identifier for a channel and vice versa; for supergroups and channel - chats. - location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which - the supergroup is connected. - can_send_paid_media (:obj:`bool`): Optional. :obj:`True`, if paid media messages can be - sent or forwarded to the channel chat. The field is available only for channel chats. - - .. versionadded:: 21.4 - - .. _accent colors: https://core.telegram.org/bots/api#accent-colors - .. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups - """ - - __slots__ = ( - "accent_color_id", - "active_usernames", - "available_reactions", - "background_custom_emoji_id", - "bio", - "birthdate", - "business_intro", - "business_location", - "business_opening_hours", - "can_send_paid_media", - "can_set_sticker_set", - "custom_emoji_sticker_set_name", - "description", - "emoji_status_custom_emoji_id", - "emoji_status_expiration_date", - "has_aggressive_anti_spam_enabled", - "has_hidden_members", - "has_private_forwards", - "has_protected_content", - "has_restricted_voice_and_video_messages", - "has_visible_history", - "invite_link", - "join_by_request", - "join_to_send_messages", - "linked_chat_id", - "location", - "max_reaction_count", - "message_auto_delete_time", - "permissions", - "personal_chat", - "photo", - "pinned_message", - "profile_accent_color_id", - "profile_background_custom_emoji_id", - "slow_mode_delay", - "sticker_set_name", - "unrestrict_boost_count", - ) - - def __init__( - self, - id: int, - type: str, - accent_color_id: int, - max_reaction_count: int, - title: Optional[str] = None, - username: Optional[str] = None, - first_name: Optional[str] = None, - last_name: Optional[str] = None, - is_forum: Optional[bool] = None, - photo: Optional[ChatPhoto] = None, - active_usernames: Optional[Sequence[str]] = None, - birthdate: Optional[Birthdate] = None, - business_intro: Optional["BusinessIntro"] = None, - business_location: Optional["BusinessLocation"] = None, - business_opening_hours: Optional["BusinessOpeningHours"] = None, - personal_chat: Optional["Chat"] = None, - available_reactions: Optional[Sequence[ReactionType]] = None, - background_custom_emoji_id: Optional[str] = None, - profile_accent_color_id: Optional[int] = None, - profile_background_custom_emoji_id: Optional[str] = None, - emoji_status_custom_emoji_id: Optional[str] = None, - emoji_status_expiration_date: Optional[dtm.datetime] = None, - bio: Optional[str] = None, - has_private_forwards: Optional[bool] = None, - has_restricted_voice_and_video_messages: Optional[bool] = None, - join_to_send_messages: Optional[bool] = None, - join_by_request: Optional[bool] = None, - description: Optional[str] = None, - invite_link: Optional[str] = None, - pinned_message: Optional["Message"] = None, - permissions: Optional[ChatPermissions] = None, - slow_mode_delay: Optional[int] = None, - unrestrict_boost_count: Optional[int] = None, - message_auto_delete_time: Optional[int] = None, - has_aggressive_anti_spam_enabled: Optional[bool] = None, - has_hidden_members: Optional[bool] = None, - has_protected_content: Optional[bool] = None, - has_visible_history: Optional[bool] = None, - sticker_set_name: Optional[str] = None, - can_set_sticker_set: Optional[bool] = None, - custom_emoji_sticker_set_name: Optional[str] = None, - linked_chat_id: Optional[int] = None, - location: Optional[ChatLocation] = None, - can_send_paid_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - id=id, - type=type, - title=title, - username=username, - first_name=first_name, - last_name=last_name, - is_forum=is_forum, - api_kwargs=api_kwargs, - ) - - # Required and unique to this class- - with self._unfrozen(): - self.max_reaction_count: int = max_reaction_count - self.photo: Optional[ChatPhoto] = photo - self.bio: Optional[str] = bio - self.has_private_forwards: Optional[bool] = has_private_forwards - self.description: Optional[str] = description - self.invite_link: Optional[str] = invite_link - self.pinned_message: Optional[Message] = pinned_message - self.permissions: Optional[ChatPermissions] = permissions - self.slow_mode_delay: Optional[int] = slow_mode_delay - self.message_auto_delete_time: Optional[int] = ( - int(message_auto_delete_time) if message_auto_delete_time is not None else None - ) - self.has_protected_content: Optional[bool] = has_protected_content - self.has_visible_history: Optional[bool] = has_visible_history - self.sticker_set_name: Optional[str] = sticker_set_name - self.can_set_sticker_set: Optional[bool] = can_set_sticker_set - self.linked_chat_id: Optional[int] = linked_chat_id - self.location: Optional[ChatLocation] = location - self.join_to_send_messages: Optional[bool] = join_to_send_messages - self.join_by_request: Optional[bool] = join_by_request - self.has_restricted_voice_and_video_messages: Optional[bool] = ( - has_restricted_voice_and_video_messages - ) - self.active_usernames: tuple[str, ...] = parse_sequence_arg(active_usernames) - self.emoji_status_custom_emoji_id: Optional[str] = emoji_status_custom_emoji_id - self.emoji_status_expiration_date: Optional[dtm.datetime] = ( - emoji_status_expiration_date - ) - self.has_aggressive_anti_spam_enabled: Optional[bool] = ( - has_aggressive_anti_spam_enabled - ) - self.has_hidden_members: Optional[bool] = has_hidden_members - self.available_reactions: Optional[tuple[ReactionType, ...]] = parse_sequence_arg( - available_reactions - ) - self.accent_color_id: Optional[int] = accent_color_id - self.background_custom_emoji_id: Optional[str] = background_custom_emoji_id - self.profile_accent_color_id: Optional[int] = profile_accent_color_id - self.profile_background_custom_emoji_id: Optional[str] = ( - profile_background_custom_emoji_id - ) - self.unrestrict_boost_count: Optional[int] = unrestrict_boost_count - self.custom_emoji_sticker_set_name: Optional[str] = custom_emoji_sticker_set_name - self.birthdate: Optional[Birthdate] = birthdate - self.personal_chat: Optional[Chat] = personal_chat - self.business_intro: Optional[BusinessIntro] = business_intro - self.business_location: Optional[BusinessLocation] = business_location - self.business_opening_hours: Optional[BusinessOpeningHours] = business_opening_hours - self.can_send_paid_media: Optional[bool] = can_send_paid_media - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatFullInfo"]: - """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["emoji_status_expiration_date"] = from_timestamp( - data.get("emoji_status_expiration_date"), tzinfo=loc_tzinfo - ) - - data["photo"] = ChatPhoto.de_json(data.get("photo"), bot) - - from telegram import ( # pylint: disable=import-outside-toplevel - BusinessIntro, - BusinessLocation, - BusinessOpeningHours, - Message, - ) - - data["pinned_message"] = Message.de_json(data.get("pinned_message"), bot) - data["permissions"] = ChatPermissions.de_json(data.get("permissions"), bot) - data["location"] = ChatLocation.de_json(data.get("location"), bot) - data["available_reactions"] = ReactionType.de_list(data.get("available_reactions"), bot) - data["birthdate"] = Birthdate.de_json(data.get("birthdate"), bot) - data["personal_chat"] = Chat.de_json(data.get("personal_chat"), bot) - data["business_intro"] = BusinessIntro.de_json(data.get("business_intro"), bot) - data["business_location"] = BusinessLocation.de_json(data.get("business_location"), bot) - data["business_opening_hours"] = BusinessOpeningHours.de_json( - data.get("business_opening_hours"), bot - ) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_chatinvitelink.py b/venv/lib/python3.11/site-packages/telegram/_chatinvitelink.py deleted file mode 100755 index b806724..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatinvitelink.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 an object that represents an invite link for a chat.""" -import datetime as dtm -from typing import TYPE_CHECKING, Optional - -from telegram._telegramobject import TelegramObject -from telegram._user import User -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 ChatInviteLink(TelegramObject): - """This object represents an invite link for a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`invite_link`, :attr:`creator`, :attr:`creates_join_request`, - :attr:`is_primary` and :attr:`is_revoked` are equal. - - .. versionadded:: 13.4 - .. versionchanged:: 20.0 - - * The argument & attribute :attr:`creates_join_request` is now required to comply with the - Bot API. - * Comparing objects of this class now also takes :attr:`creates_join_request` into account. - - Args: - invite_link (:obj:`str`): The invite link. - creator (:class:`telegram.User`): Creator of the link. - creates_join_request (:obj:`bool`): :obj:`True`, if users joining the chat via - the link need to be approved by chat administrators. - - .. versionadded:: 13.8 - is_primary (:obj:`bool`): :obj:`True`, if the link is primary. - is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked. - expire_date (:class:`datetime.datetime`, optional): Date when the link will expire or - has been expired. - - .. versionchanged:: 20.3 - |datetime_localization| - member_limit (:obj:`int`, optional): Maximum number of users that can be members of the - chat simultaneously after joining the chat via this invite link; - :tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`- - :tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`. - name (:obj:`str`, optional): Invite link name. - 0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters. - - .. versionadded:: 13.8 - pending_join_request_count (:obj:`int`, optional): Number of pending join requests - created using this link. - - .. versionadded:: 13.8 - subscription_period (:obj:`int`, optional): The number of seconds the subscription will be - active for before the next payment. - - .. versionadded:: 21.5 - subscription_price (:obj:`int`, optional): The amount of Telegram Stars a user must pay - initially and after each subsequent subscription period to be a member of the chat - using the link. - - .. versionadded:: 21.5 - - Attributes: - invite_link (:obj:`str`): The invite link. If the link was created by another chat - administrator, then the second part of the link will be replaced with ``'…'``. - creator (:class:`telegram.User`): Creator of the link. - creates_join_request (:obj:`bool`): :obj:`True`, if users joining the chat via - the link need to be approved by chat administrators. - - .. versionadded:: 13.8 - is_primary (:obj:`bool`): :obj:`True`, if the link is primary. - is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked. - expire_date (:class:`datetime.datetime`): Optional. Date when the link will expire or - has been expired. - - .. versionchanged:: 20.3 - |datetime_localization| - member_limit (:obj:`int`): Optional. Maximum number of users that can be members - of the chat simultaneously after joining the chat via this invite link; - :tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`- - :tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`. - name (:obj:`str`): Optional. Invite link name. - 0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters. - - .. versionadded:: 13.8 - pending_join_request_count (:obj:`int`): Optional. Number of pending join requests - created using this link. - - .. versionadded:: 13.8 - subscription_period (:obj:`int`): Optional. The number of seconds the subscription will be - active for before the next payment. - - .. versionadded:: 21.5 - subscription_price (:obj:`int`): Optional. The amount of Telegram Stars a user must pay - initially and after each subsequent subscription period to be a member of the chat - using the link. - - .. versionadded:: 21.5 - - """ - - __slots__ = ( - "creates_join_request", - "creator", - "expire_date", - "invite_link", - "is_primary", - "is_revoked", - "member_limit", - "name", - "pending_join_request_count", - "subscription_period", - "subscription_price", - ) - - def __init__( - self, - invite_link: str, - creator: User, - creates_join_request: bool, - is_primary: bool, - is_revoked: bool, - expire_date: Optional[dtm.datetime] = None, - member_limit: Optional[int] = None, - name: Optional[str] = None, - pending_join_request_count: Optional[int] = None, - subscription_period: Optional[int] = None, - subscription_price: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.invite_link: str = invite_link - self.creator: User = creator - self.creates_join_request: bool = creates_join_request - self.is_primary: bool = is_primary - self.is_revoked: bool = is_revoked - - # Optionals - self.expire_date: Optional[dtm.datetime] = expire_date - self.member_limit: Optional[int] = member_limit - self.name: Optional[str] = name - self.pending_join_request_count: Optional[int] = ( - int(pending_join_request_count) if pending_join_request_count is not None else None - ) - self.subscription_period: Optional[int] = subscription_period - self.subscription_price: Optional[int] = subscription_price - - self._id_attrs = ( - self.invite_link, - self.creates_join_request, - self.creator, - self.is_primary, - self.is_revoked, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatInviteLink"]: - """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["creator"] = User.de_json(data.get("creator"), bot) - data["expire_date"] = from_timestamp(data.get("expire_date", None), tzinfo=loc_tzinfo) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_chatjoinrequest.py b/venv/lib/python3.11/site-packages/telegram/_chatjoinrequest.py deleted file mode 100755 index 8730552..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatjoinrequest.py +++ /dev/null @@ -1,213 +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 ChatJoinRequest.""" -import datetime as dtm -from typing import TYPE_CHECKING, Optional - -from telegram._chat import Chat -from telegram._chatinvitelink import ChatInviteLink -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot - - -class ChatJoinRequest(TelegramObject): - """This object represents a join request sent to a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`chat`, :attr:`from_user` and :attr:`date` are equal. - - Note: - * Since Bot API 5.5, bots are allowed to contact users who sent a join request to a chat - where the bot is an administrator with the - :attr:`~telegram.ChatMemberAdministrator.can_invite_users` administrator right - even - if the user never interacted with the bot before. - * Telegram does not guarantee that :attr:`from_user.id ` coincides with the - ``chat_id`` of the user. Please use :attr:`user_chat_id` to contact the user in - response to their join request. - - .. versionadded:: 13.8 - .. versionchanged:: 20.1 - In Bot API 6.5 the argument :paramref:`user_chat_id` was added, which changes the position - of the optional arguments :paramref:`bio` and :paramref:`invite_link`. - - Args: - chat (:class:`telegram.Chat`): Chat to which the request was sent. - from_user (:class:`telegram.User`): User that sent the join request. - date (:class:`datetime.datetime`): Date the request was sent. - - .. versionchanged:: 20.3 - |datetime_localization| - user_chat_id (:obj:`int`): Identifier of a private chat with the user who sent the join - request. This number may have more than 32 significant bits and some programming - languages may have difficulty/silent defects in interpreting it. But it has at most 52 - significant bits, so a 64-bit integer or double-precision float type are safe for - storing this identifier. The bot can use this identifier for 5 minutes to send messages - until the join request is processed, assuming no other administrator contacted the - user. - - .. versionadded:: 20.1 - bio (:obj:`str`, optional): Bio of the user. - invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link that was used - by the user to send the join request. - - Attributes: - chat (:class:`telegram.Chat`): Chat to which the request was sent. - from_user (:class:`telegram.User`): User that sent the join request. - date (:class:`datetime.datetime`): Date the request was sent. - - .. versionchanged:: 20.3 - |datetime_localization| - user_chat_id (:obj:`int`): Identifier of a private chat with the user who sent the join - request. This number may have more than 32 significant bits and some programming - languages may have difficulty/silent defects in interpreting it. But it has at most 52 - significant bits, so a 64-bit integer or double-precision float type are safe for - storing this identifier. The bot can use this identifier for 24 hours to send messages - until the join request is processed, assuming no other administrator contacted the - user. - - .. versionadded:: 20.1 - bio (:obj:`str`): Optional. Bio of the user. - invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link that was used - by the user to send the join request. - - Note: - When a user joins a *public* group via an invite link, this attribute may not - be present. However, this behavior is undocument and may be subject to change. - See `this GitHub thread `_ - for some discussion. - - """ - - __slots__ = ("bio", "chat", "date", "from_user", "invite_link", "user_chat_id") - - def __init__( - self, - chat: Chat, - from_user: User, - date: dtm.datetime, - user_chat_id: int, - bio: Optional[str] = None, - invite_link: Optional[ChatInviteLink] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.chat: Chat = chat - self.from_user: User = from_user - self.date: dtm.datetime = date - self.user_chat_id: int = user_chat_id - - # Optionals - self.bio: Optional[str] = bio - self.invite_link: Optional[ChatInviteLink] = invite_link - - self._id_attrs = (self.chat, self.from_user, self.date) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatJoinRequest"]: - """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["chat"] = Chat.de_json(data.get("chat"), bot) - data["from_user"] = User.de_json(data.pop("from", None), bot) - data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo) - data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot) - - return super().de_json(data=data, bot=bot) - - async def approve( - 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.approve_chat_join_request( - chat_id=update.effective_chat.id, user_id=update.effective_user.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.approve_chat_join_request`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().approve_chat_join_request( - chat_id=self.chat.id, - user_id=self.from_user.id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def decline( - 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.decline_chat_join_request( - chat_id=update.effective_chat.id, user_id=update.effective_user.id, *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.decline_chat_join_request`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return await self.get_bot().decline_chat_join_request( - chat_id=self.chat.id, - user_id=self.from_user.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/_chatlocation.py b/venv/lib/python3.11/site-packages/telegram/_chatlocation.py deleted file mode 100755 index 7e22722..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatlocation.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 location to which a chat is connected.""" - -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._files.location import Location -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ChatLocation(TelegramObject): - """This object represents a location to which a chat is connected. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`location` is equal. - - Args: - location (:class:`telegram.Location`): The location to which the supergroup is connected. - Can't be a live location. - address (:obj:`str`): Location address; - :tg-const:`telegram.ChatLocation.MIN_ADDRESS`- - :tg-const:`telegram.ChatLocation.MAX_ADDRESS` characters, as defined by the chat owner. - Attributes: - location (:class:`telegram.Location`): The location to which the supergroup is connected. - Can't be a live location. - address (:obj:`str`): Location address; - :tg-const:`telegram.ChatLocation.MIN_ADDRESS`- - :tg-const:`telegram.ChatLocation.MAX_ADDRESS` characters, as defined by the chat owner. - - """ - - __slots__ = ("address", "location") - - def __init__( - self, - location: Location, - address: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.location: Location = location - self.address: str = address - - self._id_attrs = (self.location,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatLocation"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["location"] = Location.de_json(data.get("location"), bot) - - return super().de_json(data=data, bot=bot) - - MIN_ADDRESS: Final[int] = constants.LocationLimit.MIN_CHAT_LOCATION_ADDRESS - """:const:`telegram.constants.LocationLimit.MIN_CHAT_LOCATION_ADDRESS` - - .. versionadded:: 20.0 - """ - MAX_ADDRESS: Final[int] = constants.LocationLimit.MAX_CHAT_LOCATION_ADDRESS - """:const:`telegram.constants.LocationLimit.MAX_CHAT_LOCATION_ADDRESS` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_chatmember.py b/venv/lib/python3.11/site-packages/telegram/_chatmember.py deleted file mode 100755 index 85fd2e9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatmember.py +++ /dev/null @@ -1,665 +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 ChatMember.""" - -import datetime as dtm -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._user import User -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 ChatMember(TelegramObject): - """Base class for Telegram ChatMember Objects. - Currently, the following 6 types of chat members are supported: - - * :class:`telegram.ChatMemberOwner` - * :class:`telegram.ChatMemberAdministrator` - * :class:`telegram.ChatMemberMember` - * :class:`telegram.ChatMemberRestricted` - * :class:`telegram.ChatMemberLeft` - * :class:`telegram.ChatMemberBanned` - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`user` and :attr:`status` are equal. - - Examples: - :any:`Chat Member Bot ` - - .. versionchanged:: 20.0 - - * As of Bot API 5.3, :class:`ChatMember` is nothing but the base class for the subclasses - listed above and is no longer returned directly by :meth:`~telegram.Bot.get_chat`. - Therefore, most of the arguments and attributes were removed and you should no longer - use :class:`ChatMember` directly. - * The constant ``ChatMember.CREATOR`` was replaced by :attr:`~telegram.ChatMember.OWNER` - * The constant ``ChatMember.KICKED`` was replaced by :attr:`~telegram.ChatMember.BANNED` - - Args: - user (:class:`telegram.User`): Information about the user. - status (:obj:`str`): The member's status in the chat. Can be - :attr:`~telegram.ChatMember.ADMINISTRATOR`, :attr:`~telegram.ChatMember.OWNER`, - :attr:`~telegram.ChatMember.BANNED`, :attr:`~telegram.ChatMember.LEFT`, - :attr:`~telegram.ChatMember.MEMBER` or :attr:`~telegram.ChatMember.RESTRICTED`. - - Attributes: - user (:class:`telegram.User`): Information about the user. - status (:obj:`str`): The member's status in the chat. Can be - :attr:`~telegram.ChatMember.ADMINISTRATOR`, :attr:`~telegram.ChatMember.OWNER`, - :attr:`~telegram.ChatMember.BANNED`, :attr:`~telegram.ChatMember.LEFT`, - :attr:`~telegram.ChatMember.MEMBER` or :attr:`~telegram.ChatMember.RESTRICTED`. - - """ - - __slots__ = ("status", "user") - - ADMINISTRATOR: Final[str] = constants.ChatMemberStatus.ADMINISTRATOR - """:const:`telegram.constants.ChatMemberStatus.ADMINISTRATOR`""" - OWNER: Final[str] = constants.ChatMemberStatus.OWNER - """:const:`telegram.constants.ChatMemberStatus.OWNER`""" - BANNED: Final[str] = constants.ChatMemberStatus.BANNED - """:const:`telegram.constants.ChatMemberStatus.BANNED`""" - LEFT: Final[str] = constants.ChatMemberStatus.LEFT - """:const:`telegram.constants.ChatMemberStatus.LEFT`""" - MEMBER: Final[str] = constants.ChatMemberStatus.MEMBER - """:const:`telegram.constants.ChatMemberStatus.MEMBER`""" - RESTRICTED: Final[str] = constants.ChatMemberStatus.RESTRICTED - """:const:`telegram.constants.ChatMemberStatus.RESTRICTED`""" - - def __init__( - self, - user: User, - status: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required by all subclasses - self.user: User = user - self.status: str = status - - self._id_attrs = (self.user, self.status) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatMember"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - _class_mapping: dict[str, type[ChatMember]] = { - cls.OWNER: ChatMemberOwner, - cls.ADMINISTRATOR: ChatMemberAdministrator, - cls.MEMBER: ChatMemberMember, - cls.RESTRICTED: ChatMemberRestricted, - cls.LEFT: ChatMemberLeft, - cls.BANNED: ChatMemberBanned, - } - - if cls is ChatMember and data.get("status") in _class_mapping: - return _class_mapping[data.pop("status")].de_json(data=data, bot=bot) - - data["user"] = User.de_json(data.get("user"), bot) - if "until_date" in data: - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["until_date"] = from_timestamp(data["until_date"], tzinfo=loc_tzinfo) - - # 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 cls is ChatMemberRestricted and data.get("can_send_media_messages") is not None: - api_kwargs = {"can_send_media_messages": data.pop("can_send_media_messages")} - return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) - - return super().de_json(data=data, bot=bot) - - -class ChatMemberOwner(ChatMember): - """ - Represents a chat member that owns the chat - and has all administrator privileges. - - .. versionadded:: 13.7 - - Args: - user (:class:`telegram.User`): Information about the user. - is_anonymous (:obj:`bool`): :obj:`True`, if the - user's presence in the chat is hidden. - custom_title (:obj:`str`, optional): Custom title for this user. - - Attributes: - status (:obj:`str`): The member's status in the chat, - always :tg-const:`telegram.ChatMember.OWNER`. - user (:class:`telegram.User`): Information about the user. - is_anonymous (:obj:`bool`): :obj:`True`, if the user's - presence in the chat is hidden. - custom_title (:obj:`str`): Optional. Custom title for - this user. - """ - - __slots__ = ("custom_title", "is_anonymous") - - def __init__( - self, - user: User, - is_anonymous: bool, - custom_title: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(status=ChatMember.OWNER, user=user, api_kwargs=api_kwargs) - with self._unfrozen(): - self.is_anonymous: bool = is_anonymous - self.custom_title: Optional[str] = custom_title - - -class ChatMemberAdministrator(ChatMember): - """ - Represents a chat member that has some additional privileges. - - .. versionadded:: 13.7 - .. versionchanged:: 20.0 - - * Argument and attribute ``can_manage_voice_chats`` were renamed to - :paramref:`can_manage_video_chats` and :attr:`can_manage_video_chats` in accordance to - Bot API 6.0. - * The argument :paramref:`can_manage_topics` was added, which changes the position of the - optional argument :paramref:`custom_title`. - - .. versionchanged:: 21.1 - As of this version, :attr:`can_post_stories`, :attr:`can_edit_stories`, - and :attr:`can_delete_stories` is now required. Thus, the order of arguments had to be - changed. - - Args: - user (:class:`telegram.User`): Information about the user. - can_be_edited (:obj:`bool`): :obj:`True`, if the bot - is allowed to edit administrator privileges of that user. - is_anonymous (:obj:`bool`): :obj:`True`, if the user's - presence in the chat is hidden. - can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, get boost list, see hidden supergroup and channel members, report spam messages - and ignore slow mode. Implied by any other administrator privilege. - can_delete_messages (:obj:`bool`): :obj:`True`, if the - administrator can delete messages of other users. - can_manage_video_chats (:obj:`bool`): :obj:`True`, if the - administrator can manage video chats. - - .. versionadded:: 20.0 - can_restrict_members (:obj:`bool`): :obj:`True`, if the - administrator can restrict, ban or unban chat members. - can_promote_members (:obj:`bool`): :obj:`True`, if the administrator - can add new administrators with a subset of his own privileges or demote - administrators that he has promoted, directly or indirectly (promoted by - administrators that were appointed by the user). - can_change_info (:obj:`bool`): :obj:`True`, if the user can change - the chat title, photo and other settings. - can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite - new users to the chat. - can_post_messages (:obj:`bool`, optional): :obj:`True`, if the - administrator can post messages in the channel, or access channel statistics; - for channels only. - can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the - administrator can edit messages of other users and can pin - messages; for channels only. - can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed - to pin messages; for groups and supergroups only. - can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post - stories to the chat. - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted - by other users, post stories to the chat page, pin chat stories, and access the chat's - story archive - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete - stories posted by other users. - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed - to create, rename, close, and reopen forum topics; for supergroups only. - - .. versionadded:: 20.0 - custom_title (:obj:`str`, optional): Custom title for this user. - - Attributes: - status (:obj:`str`): The member's status in the chat, - always :tg-const:`telegram.ChatMember.ADMINISTRATOR`. - user (:class:`telegram.User`): Information about the user. - can_be_edited (:obj:`bool`): :obj:`True`, if the bot - is allowed to edit administrator privileges of that user. - is_anonymous (:obj:`bool`): :obj:`True`, if the user's - presence in the chat is hidden. - can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, get boost list, see hidden supergroup and channel members, report spam messages - and ignore slow mode. Implied by any other administrator privilege. - can_delete_messages (:obj:`bool`): :obj:`True`, if the - administrator can delete messages of other users. - can_manage_video_chats (:obj:`bool`): :obj:`True`, if the - administrator can manage video chats. - - .. versionadded:: 20.0 - can_restrict_members (:obj:`bool`): :obj:`True`, if the - administrator can restrict, ban or unban chat members, or access supergroup statistics. - can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new - administrators with a subset of their own privileges or demote administrators - that they have promoted, directly or indirectly (promoted by administrators that - were appointed by the user). - can_change_info (:obj:`bool`): :obj:`True`, if the user can change - the chat title, photo and other settings. - can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite - new users to the chat. - can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the - administrator can post messages in the channel or access channel statistics; - for channels only. - can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the - administrator can edit messages of other users and can pin - messages; for channels only. - can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed - to pin messages; for groups and supergroups only. - can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post - stories to the chat. - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted - by other users, post stories to the chat page, pin chat stories, and access the chat's - story archive - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete - stories posted by other users. - - .. versionadded:: 20.6 - .. versionchanged:: 21.0 - |non_optional_story_argument| - can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed - to create, rename, close, and reopen forum topics; for supergroups only - - .. versionadded:: 20.0 - custom_title (:obj:`str`): Optional. Custom title for this user. - """ - - __slots__ = ( - "can_be_edited", - "can_change_info", - "can_delete_messages", - "can_delete_stories", - "can_edit_messages", - "can_edit_stories", - "can_invite_users", - "can_manage_chat", - "can_manage_topics", - "can_manage_video_chats", - "can_pin_messages", - "can_post_messages", - "can_post_stories", - "can_promote_members", - "can_restrict_members", - "custom_title", - "is_anonymous", - ) - - def __init__( - self, - user: User, - can_be_edited: bool, - is_anonymous: bool, - can_manage_chat: bool, - can_delete_messages: bool, - can_manage_video_chats: bool, - can_restrict_members: bool, - can_promote_members: bool, - can_change_info: bool, - can_invite_users: bool, - can_post_stories: bool, - can_edit_stories: bool, - can_delete_stories: bool, - can_post_messages: Optional[bool] = None, - can_edit_messages: Optional[bool] = None, - can_pin_messages: Optional[bool] = None, - can_manage_topics: Optional[bool] = None, - custom_title: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(status=ChatMember.ADMINISTRATOR, user=user, api_kwargs=api_kwargs) - with self._unfrozen(): - self.can_be_edited: bool = can_be_edited - self.is_anonymous: bool = is_anonymous - self.can_manage_chat: bool = can_manage_chat - self.can_delete_messages: bool = can_delete_messages - self.can_manage_video_chats: bool = can_manage_video_chats - self.can_restrict_members: bool = can_restrict_members - self.can_promote_members: bool = can_promote_members - self.can_change_info: bool = can_change_info - self.can_invite_users: bool = can_invite_users - self.can_post_stories: bool = can_post_stories - self.can_edit_stories: bool = can_edit_stories - self.can_delete_stories: bool = can_delete_stories - # Optionals - self.can_post_messages: Optional[bool] = can_post_messages - self.can_edit_messages: Optional[bool] = can_edit_messages - self.can_pin_messages: Optional[bool] = can_pin_messages - self.can_manage_topics: Optional[bool] = can_manage_topics - self.custom_title: Optional[str] = custom_title - - -class ChatMemberMember(ChatMember): - """ - Represents a chat member that has no additional - privileges or restrictions. - - .. versionadded:: 13.7 - - Args: - user (:class:`telegram.User`): Information about the user. - until_date (:class:`datetime.datetime`, optional): Date when the user's subscription will - expire. - - .. versionadded:: 21.5 - - Attributes: - status (:obj:`str`): The member's status in the chat, - always :tg-const:`telegram.ChatMember.MEMBER`. - user (:class:`telegram.User`): Information about the user. - until_date (:class:`datetime.datetime`): Optional. Date when the user's subscription will - expire. - - .. versionadded:: 21.5 - - """ - - __slots__ = ("until_date",) - - def __init__( - self, - user: User, - until_date: Optional[dtm.datetime] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(status=ChatMember.MEMBER, user=user, api_kwargs=api_kwargs) - with self._unfrozen(): - self.until_date: Optional[dtm.datetime] = until_date - - -class ChatMemberRestricted(ChatMember): - """ - Represents a chat member that is under certain restrictions - in the chat. Supergroups only. - - .. versionadded:: 13.7 - .. versionchanged:: 20.0 - All arguments were made positional and their order was changed. - The argument can_manage_topics was added. - - .. versionchanged:: 20.5 - Removed deprecated argument and attribute ``can_send_media_messages``. - - Args: - user (:class:`telegram.User`): Information about the user. - is_member (:obj:`bool`): :obj:`True`, if the user is a - member of the chat at the moment of the request. - can_change_info (:obj:`bool`): :obj:`True`, if the user can change - the chat title, photo and other settings. - can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite - new users to the chat. - can_pin_messages (:obj:`bool`): :obj:`True`, if the user is allowed - to pin messages; groups and supergroups only. - can_send_messages (:obj:`bool`): :obj:`True`, if the user is allowed - to send text messages, contacts, invoices, locations and venues. - can_send_polls (:obj:`bool`): :obj:`True`, if the user is allowed - to send polls. - can_send_other_messages (:obj:`bool`): :obj:`True`, if the user is allowed - to send animations, games, stickers and use inline bots. - can_add_web_page_previews (:obj:`bool`): :obj:`True`, if the user is - allowed to add web page previews to their messages. - can_manage_topics (:obj:`bool`): :obj:`True`, if the user is allowed to create - forum topics. - - .. versionadded:: 20.0 - until_date (:class:`datetime.datetime`): Date when restrictions - will be lifted for this user. - - .. versionchanged:: 20.3 - |datetime_localization| - can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios. - - .. versionadded:: 20.1 - can_send_documents (:obj:`bool`): :obj:`True`, if the user is allowed to send documents. - - .. versionadded:: 20.1 - can_send_photos (:obj:`bool`): :obj:`True`, if the user is allowed to send photos. - - .. versionadded:: 20.1 - can_send_videos (:obj:`bool`): :obj:`True`, if the user is allowed to send videos. - - .. versionadded:: 20.1 - can_send_video_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send video - notes. - - .. versionadded:: 20.1 - can_send_voice_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send voice - notes. - - .. versionadded:: 20.1 - - Attributes: - status (:obj:`str`): The member's status in the chat, - always :tg-const:`telegram.ChatMember.RESTRICTED`. - user (:class:`telegram.User`): Information about the user. - is_member (:obj:`bool`): :obj:`True`, if the user is a - member of the chat at the moment of the request. - can_change_info (:obj:`bool`): :obj:`True`, if the user can change - the chat title, photo and other settings. - can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite - new users to the chat. - can_pin_messages (:obj:`bool`): :obj:`True`, if the user is allowed - to pin messages; groups and supergroups only. - can_send_messages (:obj:`bool`): :obj:`True`, if the user is allowed - to send text messages, contacts, locations and venues. - can_send_polls (:obj:`bool`): :obj:`True`, if the user is allowed - to send polls. - can_send_other_messages (:obj:`bool`): :obj:`True`, if the user is allowed - to send animations, games, stickers and use inline bots. - can_add_web_page_previews (:obj:`bool`): :obj:`True`, if the user is - allowed to add web page previews to their messages. - can_manage_topics (:obj:`bool`): :obj:`True`, if the user is allowed to create - forum topics. - - .. versionadded:: 20.0 - until_date (:class:`datetime.datetime`): Date when restrictions - will be lifted for this user. - - .. versionchanged:: 20.3 - |datetime_localization| - can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios. - - .. versionadded:: 20.1 - can_send_documents (:obj:`bool`): :obj:`True`, if the user is allowed to send documents. - - .. versionadded:: 20.1 - can_send_photos (:obj:`bool`): :obj:`True`, if the user is allowed to send photos. - - .. versionadded:: 20.1 - can_send_videos (:obj:`bool`): :obj:`True`, if the user is allowed to send videos. - - .. versionadded:: 20.1 - can_send_video_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send video - notes. - - .. versionadded:: 20.1 - can_send_voice_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send voice - notes. - - .. versionadded:: 20.1 - - """ - - __slots__ = ( - "can_add_web_page_previews", - "can_change_info", - "can_invite_users", - "can_manage_topics", - "can_pin_messages", - "can_send_audios", - "can_send_documents", - "can_send_messages", - "can_send_other_messages", - "can_send_photos", - "can_send_polls", - "can_send_video_notes", - "can_send_videos", - "can_send_voice_notes", - "is_member", - "until_date", - ) - - def __init__( - self, - user: User, - is_member: bool, - can_change_info: bool, - can_invite_users: bool, - can_pin_messages: bool, - can_send_messages: bool, - can_send_polls: bool, - can_send_other_messages: bool, - can_add_web_page_previews: bool, - can_manage_topics: bool, - until_date: dtm.datetime, - can_send_audios: bool, - can_send_documents: bool, - can_send_photos: bool, - can_send_videos: bool, - can_send_video_notes: bool, - can_send_voice_notes: bool, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(status=ChatMember.RESTRICTED, user=user, api_kwargs=api_kwargs) - with self._unfrozen(): - self.is_member: bool = is_member - self.can_change_info: bool = can_change_info - self.can_invite_users: bool = can_invite_users - self.can_pin_messages: bool = can_pin_messages - self.can_send_messages: bool = can_send_messages - self.can_send_polls: bool = can_send_polls - self.can_send_other_messages: bool = can_send_other_messages - self.can_add_web_page_previews: bool = can_add_web_page_previews - self.can_manage_topics: bool = can_manage_topics - self.until_date: dtm.datetime = until_date - self.can_send_audios: bool = can_send_audios - self.can_send_documents: bool = can_send_documents - self.can_send_photos: bool = can_send_photos - self.can_send_videos: bool = can_send_videos - self.can_send_video_notes: bool = can_send_video_notes - self.can_send_voice_notes: bool = can_send_voice_notes - - -class ChatMemberLeft(ChatMember): - """ - Represents a chat member that isn't currently a member of the chat, - but may join it themselves. - - .. versionadded:: 13.7 - - Args: - user (:class:`telegram.User`): Information about the user. - - Attributes: - status (:obj:`str`): The member's status in the chat, - always :tg-const:`telegram.ChatMember.LEFT`. - user (:class:`telegram.User`): Information about the user. - """ - - __slots__ = () - - def __init__( - self, - user: User, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(status=ChatMember.LEFT, user=user, api_kwargs=api_kwargs) - self._freeze() - - -class ChatMemberBanned(ChatMember): - """ - Represents a chat member that was banned in the chat and - can't return to the chat or view chat messages. - - .. versionadded:: 13.7 - - Args: - user (:class:`telegram.User`): Information about the user. - until_date (:class:`datetime.datetime`): Date when restrictions - will be lifted for this user. - - .. versionchanged:: 20.3 - |datetime_localization| - - Attributes: - status (:obj:`str`): The member's status in the chat, - always :tg-const:`telegram.ChatMember.BANNED`. - user (:class:`telegram.User`): Information about the user. - until_date (:class:`datetime.datetime`): Date when restrictions - will be lifted for this user. - - .. versionchanged:: 20.3 - |datetime_localization| - - """ - - __slots__ = ("until_date",) - - def __init__( - self, - user: User, - until_date: dtm.datetime, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(status=ChatMember.BANNED, user=user, api_kwargs=api_kwargs) - with self._unfrozen(): - self.until_date: dtm.datetime = until_date diff --git a/venv/lib/python3.11/site-packages/telegram/_chatmemberupdated.py b/venv/lib/python3.11/site-packages/telegram/_chatmemberupdated.py deleted file mode 100755 index ca6822f..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatmemberupdated.py +++ /dev/null @@ -1,217 +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 ChatMemberUpdated.""" -import datetime as dtm -from typing import TYPE_CHECKING, Optional, Union - -from telegram._chat import Chat -from telegram._chatinvitelink import ChatInviteLink -from telegram._chatmember import ChatMember -from telegram._telegramobject import TelegramObject -from telegram._user import User -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 ChatMemberUpdated(TelegramObject): - """This object represents changes in the status of a chat member. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`chat`, :attr:`from_user`, :attr:`date`, - :attr:`old_chat_member` and :attr:`new_chat_member` are equal. - - .. versionadded:: 13.4 - - Note: - In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - - Examples: - :any:`Chat Member Bot ` - - Args: - chat (:class:`telegram.Chat`): Chat the user belongs to. - from_user (:class:`telegram.User`): Performer of the action, which resulted in the change. - date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to - :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member. - new_chat_member (:class:`telegram.ChatMember`): New information about the chat member. - invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link, which was used - by the user to join the chat. For joining by invite link events only. - via_chat_folder_invite_link (:obj:`bool`, optional): :obj:`True`, if the user joined the - chat via a chat folder invite link - - .. versionadded:: 20.3 - via_join_request (:obj:`bool`, optional): :obj:`True`, if the user joined the chat after - sending a direct join request without using an invite link and being approved by - an administrator - - .. versionadded:: 21.2 - - Attributes: - chat (:class:`telegram.Chat`): Chat the user belongs to. - from_user (:class:`telegram.User`): Performer of the action, which resulted in the change. - date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to - :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member. - new_chat_member (:class:`telegram.ChatMember`): New information about the chat member. - invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link, which was used - by the user to join the chat. For joining by invite link events only. - via_chat_folder_invite_link (:obj:`bool`): Optional. :obj:`True`, if the user joined the - chat via a chat folder invite link - - .. versionadded:: 20.3 - via_join_request (:obj:`bool`): Optional. :obj:`True`, if the user joined the chat after - sending a direct join request without using an invite link and being approved - by an administrator - - .. versionadded:: 21.2 - - """ - - __slots__ = ( - "chat", - "date", - "from_user", - "invite_link", - "new_chat_member", - "old_chat_member", - "via_chat_folder_invite_link", - "via_join_request", - ) - - def __init__( - self, - chat: Chat, - from_user: User, - date: dtm.datetime, - old_chat_member: ChatMember, - new_chat_member: ChatMember, - invite_link: Optional[ChatInviteLink] = None, - via_chat_folder_invite_link: Optional[bool] = None, - via_join_request: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.chat: Chat = chat - self.from_user: User = from_user - self.date: dtm.datetime = date - self.old_chat_member: ChatMember = old_chat_member - self.new_chat_member: ChatMember = new_chat_member - self.via_chat_folder_invite_link: Optional[bool] = via_chat_folder_invite_link - - # Optionals - self.invite_link: Optional[ChatInviteLink] = invite_link - self.via_join_request: Optional[bool] = via_join_request - - self._id_attrs = ( - self.chat, - self.from_user, - self.date, - self.old_chat_member, - self.new_chat_member, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatMemberUpdated"]: - """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["chat"] = Chat.de_json(data.get("chat"), bot) - data["from_user"] = User.de_json(data.pop("from", None), bot) - data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo) - data["old_chat_member"] = ChatMember.de_json(data.get("old_chat_member"), bot) - data["new_chat_member"] = ChatMember.de_json(data.get("new_chat_member"), bot) - data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot) - - return super().de_json(data=data, bot=bot) - - def _get_attribute_difference(self, attribute: str) -> tuple[object, object]: - try: - old = self.old_chat_member[attribute] - except KeyError: - old = None - - try: - new = self.new_chat_member[attribute] - except KeyError: - new = None - - return old, new - - def difference( - self, - ) -> dict[ - str, - tuple[Union[str, bool, dtm.datetime, User], Union[str, bool, dtm.datetime, User]], - ]: - """Computes the difference between :attr:`old_chat_member` and :attr:`new_chat_member`. - - Example: - .. code:: pycon - - >>> chat_member_updated.difference() - {'custom_title': ('old title', 'new title')} - - Note: - To determine, if the :attr:`telegram.ChatMember.user` attribute has changed, *every* - attribute of the user will be checked. - - .. versionadded:: 13.5 - - Returns: - dict[:obj:`str`, tuple[:class:`object`, :class:`object`]]: A dictionary mapping - attribute names to tuples of the form ``(old_value, new_value)`` - """ - # we first get the names of the attributes that have changed - # user.to_dict() is unhashable, so that needs some special casing further down - old_dict = self.old_chat_member.to_dict() - old_user_dict = old_dict.pop("user") - new_dict = self.new_chat_member.to_dict() - new_user_dict = new_dict.pop("user") - - # Generator for speed: we only need to iterate over it once - # we can't directly use the values from old_dict ^ new_dict b/c that set is unordered - attributes = (entry[0] for entry in set(old_dict.items()) ^ set(new_dict.items())) - - result = {attribute: self._get_attribute_difference(attribute) for attribute in attributes} - if old_user_dict != new_user_dict: - result["user"] = (self.old_chat_member.user, self.new_chat_member.user) - - return result # type: ignore[return-value] diff --git a/venv/lib/python3.11/site-packages/telegram/_chatpermissions.py b/venv/lib/python3.11/site-packages/telegram/_chatpermissions.py deleted file mode 100755 index a7b1b10..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_chatpermissions.py +++ /dev/null @@ -1,249 +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 ChatPermission.""" -from typing import TYPE_CHECKING, Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ChatPermissions(TelegramObject): - """Describes actions that a non-administrator user is allowed to take in a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`can_send_messages`, - :attr:`can_send_polls`, :attr:`can_send_other_messages`, :attr:`can_add_web_page_previews`, - :attr:`can_change_info`, :attr:`can_invite_users`, :attr:`can_pin_messages`, - :attr:`can_send_audios`, :attr:`can_send_documents`, :attr:`can_send_photos`, - :attr:`can_send_videos`, :attr:`can_send_video_notes`, :attr:`can_send_voice_notes`, and - :attr:`can_manage_topics` are equal. - - .. versionchanged:: 20.0 - :attr:`can_manage_topics` is considered as well when comparing objects of - this type in terms of equality. - .. versionchanged:: 20.5 - - * :attr:`can_send_audios`, :attr:`can_send_documents`, :attr:`can_send_photos`, - :attr:`can_send_videos`, :attr:`can_send_video_notes` and :attr:`can_send_voice_notes` - are considered as well when comparing objects of this type in terms of equality. - * Removed deprecated argument and attribute ``can_send_media_messages``. - - - Note: - Though not stated explicitly in the official docs, Telegram changes not only the - permissions that are set, but also sets all the others to :obj:`False`. However, since not - documented, this behavior may change unbeknown to PTB. - - Args: - can_send_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send text - messages, contacts, locations and venues. - can_send_polls (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send polls. - can_send_other_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to - send animations, games, stickers and use inline bots. - can_add_web_page_previews (:obj:`bool`, optional): :obj:`True`, if the user is allowed to - add web page previews to their messages. - can_change_info (:obj:`bool`, optional): :obj:`True`, if the user is allowed to change the - chat title, photo and other settings. Ignored in public supergroups. - can_invite_users (:obj:`bool`, optional): :obj:`True`, if the user is allowed to invite new - users to the chat. - can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin - messages. Ignored in public supergroups. - can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed - to create forum topics. If omitted defaults to the value of - :attr:`can_pin_messages`. - - .. versionadded:: 20.0 - can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios. - - .. versionadded:: 20.1 - can_send_documents (:obj:`bool`): :obj:`True`, if the user is allowed to send documents. - - .. versionadded:: 20.1 - can_send_photos (:obj:`bool`): :obj:`True`, if the user is allowed to send photos. - - .. versionadded:: 20.1 - can_send_videos (:obj:`bool`): :obj:`True`, if the user is allowed to send videos. - - .. versionadded:: 20.1 - can_send_video_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send video - notes. - - .. versionadded:: 20.1 - can_send_voice_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send voice - notes. - - .. versionadded:: 20.1 - - Attributes: - can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text - messages, contacts, locations and venues. - can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send polls, - implies :attr:`can_send_messages`. - can_send_other_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to - send animations, games, stickers and use inline bots. - can_add_web_page_previews (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to - add web page previews to their messages. - can_change_info (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to change the - chat title, photo and other settings. Ignored in public supergroups. - can_invite_users (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to invite - new users to the chat. - can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin - messages. Ignored in public supergroups. - can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed - to create forum topics. If omitted defaults to the value of - :attr:`can_pin_messages`. - - .. versionadded:: 20.0 - can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios. - - .. versionadded:: 20.1 - can_send_documents (:obj:`bool`): :obj:`True`, if the user is allowed to send documents. - - .. versionadded:: 20.1 - can_send_photos (:obj:`bool`): :obj:`True`, if the user is allowed to send photos. - - .. versionadded:: 20.1 - can_send_videos (:obj:`bool`): :obj:`True`, if the user is allowed to send videos. - - .. versionadded:: 20.1 - can_send_video_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send video - notes. - - .. versionadded:: 20.1 - can_send_voice_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send voice - notes. - - .. versionadded:: 20.1 - - """ - - __slots__ = ( - "can_add_web_page_previews", - "can_change_info", - "can_invite_users", - "can_manage_topics", - "can_pin_messages", - "can_send_audios", - "can_send_documents", - "can_send_messages", - "can_send_other_messages", - "can_send_photos", - "can_send_polls", - "can_send_video_notes", - "can_send_videos", - "can_send_voice_notes", - ) - - def __init__( - self, - can_send_messages: Optional[bool] = None, - can_send_polls: Optional[bool] = None, - can_send_other_messages: Optional[bool] = None, - can_add_web_page_previews: Optional[bool] = None, - can_change_info: Optional[bool] = None, - can_invite_users: Optional[bool] = None, - can_pin_messages: Optional[bool] = None, - can_manage_topics: Optional[bool] = None, - can_send_audios: Optional[bool] = None, - can_send_documents: Optional[bool] = None, - can_send_photos: Optional[bool] = None, - can_send_videos: Optional[bool] = None, - can_send_video_notes: Optional[bool] = None, - can_send_voice_notes: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.can_send_messages: Optional[bool] = can_send_messages - self.can_send_polls: Optional[bool] = can_send_polls - self.can_send_other_messages: Optional[bool] = can_send_other_messages - self.can_add_web_page_previews: Optional[bool] = can_add_web_page_previews - self.can_change_info: Optional[bool] = can_change_info - self.can_invite_users: Optional[bool] = can_invite_users - self.can_pin_messages: Optional[bool] = can_pin_messages - self.can_manage_topics: Optional[bool] = can_manage_topics - self.can_send_audios: Optional[bool] = can_send_audios - self.can_send_documents: Optional[bool] = can_send_documents - self.can_send_photos: Optional[bool] = can_send_photos - self.can_send_videos: Optional[bool] = can_send_videos - self.can_send_video_notes: Optional[bool] = can_send_video_notes - self.can_send_voice_notes: Optional[bool] = can_send_voice_notes - - self._id_attrs = ( - self.can_send_messages, - self.can_send_polls, - self.can_send_other_messages, - self.can_add_web_page_previews, - self.can_change_info, - self.can_invite_users, - self.can_pin_messages, - self.can_manage_topics, - self.can_send_audios, - self.can_send_documents, - self.can_send_photos, - self.can_send_videos, - self.can_send_video_notes, - self.can_send_voice_notes, - ) - - self._freeze() - - @classmethod - def all_permissions(cls) -> "ChatPermissions": - """ - This method returns an :class:`ChatPermissions` instance with all attributes - set to :obj:`True`. This is e.g. useful when unrestricting a chat member with - :meth:`telegram.Bot.restrict_chat_member`. - - .. versionadded:: 20.0 - - """ - return cls(*(14 * (True,))) - - @classmethod - def no_permissions(cls) -> "ChatPermissions": - """ - This method returns an :class:`ChatPermissions` instance - with all attributes set to :obj:`False`. - - .. versionadded:: 20.0 - """ - return cls(*(14 * (False,))) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChatPermissions"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - 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 data.get("can_send_media_messages") is not None: - api_kwargs["can_send_media_messages"] = data.pop("can_send_media_messages") - - return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.11/site-packages/telegram/_choseninlineresult.py b/venv/lib/python3.11/site-packages/telegram/_choseninlineresult.py deleted file mode 100755 index ee17d93..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_choseninlineresult.py +++ /dev/null @@ -1,109 +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 ChosenInlineResult.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._files.location import Location -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ChosenInlineResult(TelegramObject): - """ - Represents a result of an inline query that was chosen by the user and sent to their chat - partner. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`result_id` is equal. - - Note: - * In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - * It is necessary to enable inline feedback via `@Botfather `_ in - order to receive these objects in updates. - - Args: - result_id (:obj:`str`): The unique identifier for the result that was chosen. - from_user (:class:`telegram.User`): The user that chose the result. - location (:class:`telegram.Location`, optional): Sender location, only for bots that - require user location. - inline_message_id (:obj:`str`, optional): Identifier of the sent inline message. Available - only if there is an inline keyboard attached to the message. Will be also received in - callback queries and can be used to edit the message. - query (:obj:`str`): The query that was used to obtain the result. - - Attributes: - result_id (:obj:`str`): The unique identifier for the result that was chosen. - from_user (:class:`telegram.User`): The user that chose the result. - location (:class:`telegram.Location`): Optional. Sender location, only for bots that - require user location. - inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message. Available - only if there is an inline keyboard attached to the message. Will be also received in - callback queries and can be used to edit the message. - query (:obj:`str`): The query that was used to obtain the result. - - """ - - __slots__ = ("from_user", "inline_message_id", "location", "query", "result_id") - - def __init__( - self, - result_id: str, - from_user: User, - query: str, - location: Optional[Location] = None, - inline_message_id: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.result_id: str = result_id - self.from_user: User = from_user - self.query: str = query - # Optionals - self.location: Optional[Location] = location - self.inline_message_id: Optional[str] = inline_message_id - - self._id_attrs = (self.result_id,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["ChosenInlineResult"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Required - data["from_user"] = User.de_json(data.pop("from", None), bot) - # Optionals - data["location"] = Location.de_json(data.get("location"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_copytextbutton.py b/venv/lib/python3.11/site-packages/telegram/_copytextbutton.py deleted file mode 100755 index 4a3cdb9..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_copytextbutton.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 an object that represents a Telegram CopyTextButton.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class CopyTextButton(TelegramObject): - """ - This object represents an inline keyboard button that copies specified text to the clipboard. - - 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.7 - - Args: - text (:obj:`str`): The text to be copied to the clipboard; - :tg-const:`telegram.constants.InlineKeyboardButtonLimit.MIN_COPY_TEXT`- - :tg-const:`telegram.constants.InlineKeyboardButtonLimit.MAX_COPY_TEXT` characters - - Attributes: - text (:obj:`str`): The text to be copied to the clipboard; - :tg-const:`telegram.constants.InlineKeyboardButtonLimit.MIN_COPY_TEXT`- - :tg-const:`telegram.constants.InlineKeyboardButtonLimit.MAX_COPY_TEXT` characters - - """ - - __slots__ = ("text",) - - def __init__(self, text: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.text: str = text - - self._id_attrs = (self.text,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_dice.py b/venv/lib/python3.11/site-packages/telegram/_dice.py deleted file mode 100755 index a549aef..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_dice.py +++ /dev/null @@ -1,160 +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 Dice.""" -from typing import Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class Dice(TelegramObject): - """ - This object represents an animated emoji with a random value for currently supported base - emoji. (The singular form of "dice" is "die". However, PTB mimics the Telegram API, which uses - the term "dice".) - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`value` and :attr:`emoji` are equal. - - Note: - If :attr:`emoji` is :tg-const:`telegram.Dice.DARTS`, a value of 6 currently - represents a bullseye, while a value of 1 indicates that the dartboard was missed. - However, this behaviour is undocumented and might be changed by Telegram. - - If :attr:`emoji` is :tg-const:`telegram.Dice.BASKETBALL`, a value of 4 or 5 - currently score a basket, while a value of 1 to 3 indicates that the basket was missed. - However, this behaviour is undocumented and might be changed by Telegram. - - If :attr:`emoji` is :tg-const:`telegram.Dice.FOOTBALL`, a value of 4 to 5 - currently scores a goal, while a value of 1 to 3 indicates that the goal was missed. - However, this behaviour is undocumented and might be changed by Telegram. - - If :attr:`emoji` is :tg-const:`telegram.Dice.BOWLING`, a value of 6 knocks - all the pins, while a value of 1 means all the pins were missed. - However, this behaviour is undocumented and might be changed by Telegram. - - If :attr:`emoji` is :tg-const:`telegram.Dice.SLOT_MACHINE`, each value - corresponds to a unique combination of symbols, which - can be found in our - :wiki:`wiki `. - However, this behaviour is undocumented and might be changed by Telegram. - - .. - In args, some links for limits of `value` intentionally point to constants for only - one emoji of a group to avoid duplication. For example, maximum value for Dice, Darts and - Bowling is linked to a constant for Bowling. - - Args: - value (:obj:`int`): Value of the dice. - :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BOWLING` - for :tg-const:`telegram.Dice.DICE`, :tg-const:`telegram.Dice.DARTS` and - :tg-const:`telegram.Dice.BOWLING` base emoji, - :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BASKETBALL` - for :tg-const:`telegram.Dice.BASKETBALL` and :tg-const:`telegram.Dice.FOOTBALL` - base emoji, - :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_SLOT_MACHINE` - for :tg-const:`telegram.Dice.SLOT_MACHINE` base emoji. - emoji (:obj:`str`): Emoji on which the dice throw animation is based. - - Attributes: - value (:obj:`int`): Value of the dice. - :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BOWLING` - for :tg-const:`telegram.Dice.DICE`, :tg-const:`telegram.Dice.DARTS` and - :tg-const:`telegram.Dice.BOWLING` base emoji, - :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BASKETBALL` - for :tg-const:`telegram.Dice.BASKETBALL` and :tg-const:`telegram.Dice.FOOTBALL` - base emoji, - :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_SLOT_MACHINE` - for :tg-const:`telegram.Dice.SLOT_MACHINE` base emoji. - emoji (:obj:`str`): Emoji on which the dice throw animation is based. - - """ - - __slots__ = ("emoji", "value") - - def __init__(self, value: int, emoji: str, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.value: int = value - self.emoji: str = emoji - - self._id_attrs = (self.value, self.emoji) - - self._freeze() - - DICE: Final[str] = constants.DiceEmoji.DICE - """:const:`telegram.constants.DiceEmoji.DICE`""" - DARTS: Final[str] = constants.DiceEmoji.DARTS - """:const:`telegram.constants.DiceEmoji.DARTS`""" - BASKETBALL: Final[str] = constants.DiceEmoji.BASKETBALL - """:const:`telegram.constants.DiceEmoji.BASKETBALL`""" - FOOTBALL: Final[str] = constants.DiceEmoji.FOOTBALL - """:const:`telegram.constants.DiceEmoji.FOOTBALL`""" - SLOT_MACHINE: Final[str] = constants.DiceEmoji.SLOT_MACHINE - """:const:`telegram.constants.DiceEmoji.SLOT_MACHINE`""" - BOWLING: Final[str] = constants.DiceEmoji.BOWLING - """ - :const:`telegram.constants.DiceEmoji.BOWLING` - - .. versionadded:: 13.4 - """ - ALL_EMOJI: Final[list[str]] = list(constants.DiceEmoji) - """list[:obj:`str`]: A list of all available dice emoji.""" - - MIN_VALUE: Final[int] = constants.DiceLimit.MIN_VALUE - """:const:`telegram.constants.DiceLimit.MIN_VALUE` - - .. versionadded:: 20.0 - """ - - MAX_VALUE_BOWLING: Final[int] = constants.DiceLimit.MAX_VALUE_BOWLING - """:const:`telegram.constants.DiceLimit.MAX_VALUE_BOWLING` - - .. versionadded:: 20.0 - """ - - MAX_VALUE_DARTS: Final[int] = constants.DiceLimit.MAX_VALUE_DARTS - """:const:`telegram.constants.DiceLimit.MAX_VALUE_DARTS` - - .. versionadded:: 20.0 - """ - - MAX_VALUE_DICE: Final[int] = constants.DiceLimit.MAX_VALUE_DICE - """:const:`telegram.constants.DiceLimit.MAX_VALUE_DICE` - - .. versionadded:: 20.0 - """ - - MAX_VALUE_BASKETBALL: Final[int] = constants.DiceLimit.MAX_VALUE_BASKETBALL - """:const:`telegram.constants.DiceLimit.MAX_VALUE_BASKETBALL` - - .. versionadded:: 20.0 - """ - - MAX_VALUE_FOOTBALL: Final[int] = constants.DiceLimit.MAX_VALUE_FOOTBALL - """:const:`telegram.constants.DiceLimit.MAX_VALUE_FOOTBALL` - - .. versionadded:: 20.0 - """ - - MAX_VALUE_SLOT_MACHINE: Final[int] = constants.DiceLimit.MAX_VALUE_SLOT_MACHINE - """:const:`telegram.constants.DiceLimit.MAX_VALUE_SLOT_MACHINE` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__init__.py b/venv/lib/python3.11/site-packages/telegram/_files/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 4f93629cb0f92f7889a977a9e63b2e730ac98af0..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 zIjQMIiMjgmX_+}detdjpUS>&ryk0@&FAkgB{FKt1RJ$TppdBDr6!Qa#56p~=j2{?a JL=iJk3;lFga6SO`15IQpmE+Pu;qC6AJ5#p!$Z z?&fB8XJ%(-W@qaZxl5SF)dxvJ9>Uja z^#aSjNlLlfXXaenb{)EGc$_vY!}Dm<71ZX;G^o3LlQ(?t-zZZ`goW$Bczs@<`^o&= zYm2p4L+x72H(kfDN=jI~&Mm$o4EvfCfu8*3`GuF?x_Vu&U8~K5uy*CmYqiT}!w0#` zHx`{%-~(4`!L)dzZi2e$=_ov{~z&0=lNbd7?-_KO=mf#+DeA8K>{wk+yhA`d0 z>xZKWzM}rE7Wc|I3a#gBkGf4@Hod+=Lx5`6ZW+Q@27c3_J{Pv+;_n59W%{?u^!mCR zNB41Ysl4Gjp2@i2j7qUtYT`896trsizNjvtIeOrj?*&{p*%Ac{BxgA%6}&7~ysE^| zR>^EKI#Y$kR+l_qES0Ksk>O&SCKod6AoWZ063y0=@OIl80jZZS+z*Mk8FKD&gzBynS2FWvQPTe(FgKq+6 zI7}{vnaw7+&++N9>-QsuMq!&XoM)i_@s)k+YCQ8cj~8M({?aUU<6Tz#6t5r+Wc zWG)9j|JFcA$vs#6U%3$SFs@|f11^-YFD1haW)-A(n3V`RI4nwZkXyA6l`vB=M z!Kgy~_$UFk_RwgX=s2Hj2lx^PwE$miCut{v8t813n}d<20wd{IA0trZ5;ZXj9i>dD z!XDuw)O6i+OkdZ-B<%JfkAzw9r;c^RE2YDf$F1fNhx8e+>GDw0bq}YLo9E8gH!7>H z%`3Jc8gAu^yW(D|7_C-ijXP@<%UrIsZuzUObE$msV#PCkexYSF-ZfUZSMmF&R7J<| zc@-UxJv{3IyWF}Zj=~hT$M+TMa=eC@V8r_wfdAYfUyYG$@%NbzGM{LZA8V7_S326{ zM_Oe^t8}!=S7~yJZfE{-_5Rh3)Cc*`&Yau+^+#u3+&S~&MrubpxjSAAnlH5$hl5M4(fc#0dRmf8a z-NQk)yiZu-SIHY>EBV_L_&5*eQca4_*>eTy*S=>Yx(&m9uYkcp|SxBv9^AK%%0=aXZz zA0M0Tj!$l0?VdQ>oqDD_{VXEKpNeE-g3 zlqcVtiLztrbAX*MM+L-440ex3egVKa6FLox1n)o$+%+f_o}@ z*m+WVp$qS`FLh_0@0Kn^qbF5x?Es|7@u%(un{JfBE{#mmZFTcEQ5LBjnfmVb+51mL zBS__A&H_?J63;Icj*;A0bOZ#Q)7iJk;EoP8~P8#$f=^2Mf{L1@YL#xc~qF diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basethumbedmedium.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basethumbedmedium.cpython-311.pyc deleted file mode 100755 index 491b0d3839ca3b6dd87c211e337756561c33e4c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4093 zcmd^C&2JmW6`$quWBH|(EGgEPp^YKfqAQcNRUi(XwsD+9u>#A1r3NjFVzuH7rFFQw z%vBzk{$u!bisXaAFaqlAE(vEyJ)(Wks`zk}qnutrRS(7zFE@ zVy)aFdB;}Pb!Sa+*2>0;sp&=gpA0`Gy2+&dzItt8&XsPI9NjXtq8nM- zD3RASniAZ&`T`(d2e`5UWc0N)%dr;qO#*~8zj$NeMLq98TYSNC+{6-FgW&5+YTj~B z@TsjXjw{B}x*Gwnx@0b52ed5udpz%x4H9Q?DA3UkU5IU?f`DUp!=UCUhPI*TX1-X)MA14nPRIBfH+%=M3NWPG z{&E_Hg)O6`QEdg#bW?E%HEadA$eU%Ys5={JWog}N`_HlI96WECwvGuUxH)Y`(b+OY zr%G0H9GYEb!m4Fcf3r+f9WN^&0bjtE?h0MCvmA=)gEQ+`na+YLvdgwZms45g8fK~} z=!9~==DT2=Gs^m!o?lb)8u&g@$~H*hSPHh*&7!5@HY!7g^FRr3FyZ(z>Gp81gh$r? z0he5XJw8cKLdee?>rioQ~I z$T#`|7rtYS&KCX;tO&Mih3E8tZ^a&z|EU$(-O%==1)ySDNmt)k*Wir15pEzIyM4Wu za-*DP{z&1T-m6Ra9!6%z^W$`BlDLS0E!byIg#mCKuoxIvo~ z3rFX)_u@uXm7gh9wIcw;4}-Gx^-nTumO(OxM)Ou?-deS0Gg_&XxlPR5nWDauDQ!4w zmN}cga3N#s4mn@a@^5IX#Ll!%W=3V2vok8Y_qpB)W_NzsNS8L~Q?S(L`0?vE-ID$a zFxcOR>Z>jEYUbPN40JNfa%=tqY{jfuL3_}3yi|mJ z;5cYo^ev$x*pLD&BBu+lBJ8#8*NuS#y|W$WMSj_b83*lI_O~2n7QftTd&hr@TnY5z zRUj#R4$yS;miSlkO~UR*i?eKu1NJ3U*JC1G?5 zs?D)~Ek03?PgLX6jnij7oc`_fN6*ww&(=@RZqM(m z*AkQekcZw`zqkImJo%YCxwrI@{pn^^o~+69b$Pxj&C@ZE9HJ4#(S=k$3pyrb5UT3N zRMoI>8L}$XO{gkM*8Gu(s$we--4Jo?BBT@06d{MA%%@!u5&^D%DgnvkgB$08iJ9KQ zZjhyvlzjkk)w)SPZskd_sH!QUX#{p2pKls~<+41XeHt3}1dM>DTR$%_9+Eu7sw^6q z+`8r^(A0Dzb>55jhc0=2=v>;9SqrtQ!+{|$#E38&o$w;8C842--K+0?*NZYL#;9xc z!80w0;ZwUmtPhc;PB?_o;VnKRqzn28_9v4nR;@v+1EIm`BM?&wjD68jqC*C#(*!=3T610Q;6{-MBa?n-Ul3_|K#@i&d;jnuRK_)$~SBB&ANPZE8&G-76fL~$N%k)KWvVE@dPHm G`+osiyfWti diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/animation.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/animation.cpython-311.pyc deleted file mode 100755 index bdb8bdd93521299169e202e5e7b639603773080b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4325 zcmeGfO^+PKwR*mL_ItesuWX0H2IH~3J=oYjj3CO!24~mWHIf$#=0I=HRLxF7e+<<< zyR0<_ACNE+QZ67+#DS9|WDfj*T=)agCbE=CpDg8+oZ7OHEKa;v)7`VPS>s5+jh^n; z@72ev_dT!wGBHsmaQ*9(KflwTCgk5pBv(F09$W|HGr~xnFpXtw&B@d=8sb?y>*VS= zh3D+NQ>Ygdp0|rmsb11ZhFm7B@Bv{(p1YkTaVxGz`G`Ha9qB8?ds|!(F~fgRO8k_oHs$RZD-q-45V7-}8PiPC&^7^Zn7tYbe>lf*!VBDiyB4~Tvfcjq7Wfh}brf^+V4)Lki0;hn_nzrSG zKP0-%=~&Wg0Au0OfJ;ZM;_r1WTLjw%UEA_vf9|tgF$d54aJ1x%s%@vKz+nyZP9GgCd6xl z)2T zi03Ctr@ZB&F?R*YY3e1Vr$(p@(KjkKzcvP-KIxEaz;Z5}be zNZ3MwS79(RILvE{u_UX{#;FU1K{UD`<*y0+YXbkY1coA&G!Movk-#JTf7S#Z;r!DR zc!b?AoWPZQSV{_YsHcTBEDXwgsHe3s%&WhZRp{EvR!5lcZdvfZ9TwFd!NN&}r0s#6 zfX+*fA`JTs>*&Z>|rn#2`DwnM9<$+4M z_KH9i(zyaqsDru~H1CYuhBNP^=R%`Su94&94DoYYnfJ4Aku6OlZ^4;^nM!80l9yAk zU&4n0kuwO;OmY@Lr4;6&#o#h5nWk_>V49&0-C0X|H@Lgk`e=CNg35T9^SRyH#rJWJ z8XSmcsZ)Wwss40K(?@pLoy6D8@7Jnr&*4?al1;C=>}_~2Rjp2^y2;(msx2DT&Nj5O z?n}m*GgV&%e4%4C-?cWlUrqkMswReyUroDYqq8j!!Z9~y(+n^YMVDdR{~LfuH_3NL zh(7sI@#Eq@ONahZI@F&#+&^6DKlM!i>1P2(V?>|7PYQbZA%aMONisS6r?>z3_TMLt z-kmrak)nPe(Tc5%l&7bhu4+a<$4wKP{CK8l zn#^meP%wQPx=BE@&_ah2i(uc_y7O^ diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/audio.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/audio.cpython-311.pyc deleted file mode 100755 index 93f7072a492c3f259f8e5448ce7664781fab6bca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4523 zcmeGfU2hvjaL?c8Bu>+&kf<#z6qOn!HU-Lq1&BZawIXSyhA#_oIeXXf!hM*%b3-a4 z^#O^3D)9oMLOk$Pgvt*9i5LC=3aAq1o+|Og+f^-6#1k{?J3AK=1mZ(NVtt;Qxt*Pv zotc}P{d8iYNMQW%{ztEVIYr2iNW>!>Avd1~+0x{X(P)2Dvh^r_?>$vy7)FhiHQ#aE?i(}gY*ZsjKwSk{8V>5ea4$Fu<7Ydm3k ze7W7V8=Nh2Cb~8})z7qD-#shNb7Vht_Vm&T(e#^xkF8+z@Pqf(42* zvaV90=eYDBC7Ny1S>>!&qYvC)Ij*Er+LPRN&v9n>m?ehe`n*>h>}x@;dbNm+D*u3d zdb9>ktgU#yTq)P+Nd}G(Ex{#ixpJ_7G-!^lwMDZ{n~=fa(XI#fgL9d?=2))DhEmag zuugK|P(H@RmEm-9Z`*V~r}j+2JHKlJ_`~aVI&Ne_gAb*na*V5I+MI$Dzo1# zZwUwd7G)p2_mBr8-*mVHm)l_VmXOR*H-7zV^vsYWp=CGGxQ)ho!aD=Ad~+3Y9leFa z7e3_kZaSCM?4QsVZ9S<&#ofWM?55|m6srQNoXShZx!blzmfH|r!(Z?0E_Lzb;!{*{ zL_0u3{y;30y&hE5*j@~CA{I}hAjJVeZmj!!t4HzGb4+2uYE?XHD}GemE5lly6sKys zS`xe3YIJQVI4XdpVjJkgFIA9LACD#IJBwyV7_Y6F&|?I7wM?*}q>y1RBcW|0avZ?~f-wM*4y>dS zd-gzAjSH4SSpvGL8hJo8_~+q|t@h1Z06x$@BtAZk#ud0}{J`8~P9{D6S;v8W~xyO++-6O`ZBINT3h7q5U7DJjK)YINH^36&M-U- zD}J4#ap9LU)wXN%s%^@qTRr8jx(`;(PN#Z~JLjsFXjD7ve%o~(tQuFnzqLYFa9tb-5o@oG&e?<59f9XW^Om4S>xHfdk^Ic)4 zKYgHopxnRhPP}fvD;y*G>@R7}>AxS(s0MJ)c=P zmjC)84PZI9qy|I`B8=}PM7U@egJUM(WCG| z^ufzdzW-=AhSWIOGjln8>CJEgsZu;QiPWB$nnG%COzlHz8mW`l_8p0h*njBqi`S-) zY_nu!)2`S}*!#dAOXZ?G1VoU7PE$Cm%Co`UaT-?!X=qr~Blx9o}hN3&- zrHZYYz@-Hz22EJD0yTk<@~XPT+k%wDiJT zj7rr8tNq&m=4Kzvm=isEqzo(2{y$t(i)0Gb6|u>f`q(OIr2OqmCuYKCM} zR_0ptgQ}uy_Hss=T{4@n-Jv+I9MPw#lu=dU#l|HKo1q$$a*A!U+?-WbbX_h2z~ri- zeNd&crq027P(6itt@LmE_~OaU+07N0@ok)$IhUW3XMTG6;>9`XL+Oci(;aQJ&4t7# zjGF=aTY&vwo=Q~<>}DGJvQ#u#W6~tmTrzZ1QMrlyJjIf9(3;yqT0@-ZK@e|2v_)o$u z$hqU^3S?DSC33*iSq*@MZSZF`2vW$GLLhnlA**DurAHS1^di;}@yn3SsK>YeclH)y zQvz{7V4C%TQd)Gv;1N;gh_b91nk~ya*~f{2vn`_^ZaGo8$S7T*>8KO3s9xMjpW71( z$vj4oWeYpj*q7J7nawVkWtuH3tYBu(nCy*Bj0Zq+5$X{?9afR2h9rvuZoZB?hDM#cl{0 z42a|Xgha(Obx-03WTQ|I+lOQfi3G%nFltws!MZ>wc-TTji12*`--9baE)W4??Nzb~ z{KHQtA|8QXve-hZ09XyKhB&4HZ+CpmeMHp2FM@BA8^Pa%098TdCUj}SG+;6{Y80rn z#9(eQbVBz!SElwtTa@&=X=h5*=F>UHeQuC!%_ue8at!!<7xLQWduev8jyo5O~QIlf%l41@vb zT&q8CDVo*p5K-}Yq-URV=emlbO zGUAa%Ekp)(OOhB|uMsDO#ap}b%1~>CcIIfHZOsAsJN(v&J5C0NZ@l}5cYpuh#(Q55 zjNcm=ulEma^&hP7IZz)yR3ABt%flp}H;W;{KFXTAY8!o88TbM6Q^l5xBH!@FJLk^8%c-7pFfGPd81A}5l;J#GxSI2o1PF62^V zVDz(hU^m)Uyj4+ydx@l9uETruNA<%e>*-@|_h=ZlC!a*f?y=9R8>Sn@B#{hBo8gUL zxiOUDWO)DPftzD)7fK0FGl^1L`zZF1c#qqQT&rr%O$yJr1Fw>OhqgvfZjI*F&R-8- zFKonXp&Yz-Lpe7Pgt-vO$bqfBFKz8Twf4q3y*_bmu@*W7@7>U;h5|t?pYY9_&+>G- zhy4&{+KJf96>u3CddM6~9GQ;jd5aDB4S8Zl_PEBSH$&Id8SxS`a@E#!E2Gk)Qq}D% zie9B0+s?pt6=;`QjTL~n=N=jF+HKP4CLVy_h_5sj)~oC_5D~8yh7@j45Cr!i5iSTd za=uQE*B<@eC;MuhZ=IZ|b-s1-a;@{NlasZb-uuBGmk7eXdT6xP`MQyx1q3km&h&cf NE1vW9Bl7u}{|z|Mm;(R+ diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/contact.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/contact.cpython-311.pyc deleted file mode 100755 index 437b668d877b78d34c522a3eb45499c282e03848..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2645 zcmd5-&2Jk;6rZ)d_S$irq$I5qTDnm~h(qI5+FJyOQY2^&4x%|A3u&_Pj+0H-yJmKr zHkCm=R3b%@xCAvq9CD$kD*pigg?soBzy&P|NT?^?Tkkq?(nts{%6E5{_{<5s+uC?^6wVac^* zIVq7Cd5;+KePSe8;!&KCC-8MzIc217l7e#goyAqtRcnsXu$WqLY@wUBtLnDuEU&SO zP{pb)RL<(0xy%-zQ5TuTR=8eMucLKE6o18#1<6wu>cVtv-2y%rSuF%%P&##nX8??TFBPVwe+xhbz=SCD08n3b><}x+K9fDBq8eehefLK12M0s&9sCB&SJFcw zus3Xv;Qu5N$nFtMx05uJ-%F1`^Q5blh=|U2Fl!#uHVMTsgVv0Jl;}!vkh-4D1W3_L zNmB+X)wLvR-56B~G?;48nq(ItNr@TYP-ALUXiDEvGKUQ%q-O?#ySO+H!0+zytA(qqyY0AYKsywR!7TYLgU#M8Y4#E(mo+`-glo|ZS}rwGTrKZ{p5@UXr3gS_V3vH#|u=!%>D*CPs3^e diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/document.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/document.cpython-311.pyc deleted file mode 100755 index e9f567d333834c79623151a1334e980fe81d51e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3656 zcmeGfO>Y}Tbk^VN#12W5l8{!NQfTXv+O$=BuqYy=fD)+*QUanrbhGx1?P>SJon0qQ zL8lgW05wvI<+58xg+lZh7A_@r^iWw?|6oH40uo)>tBpxxM zW~>mCc+`lSi9$j_A@l(vvFnJ$Y2;oQp*48@R!~V|9%a7{~iOsJ7`4kMNsGxxHA)*w* zBvgo~$p4WP36sdT3W?GviNPDE0LMDANMZ-A0v+Ero&-9vjqU?l?b7A+4OCW0|Mh`F z@&>x96#Bqn=~f~zTi=KwB)!*mRgae{)S_HBaG4o2iJ=|U9cV0s`?W8M*_^T!hT5>0B>D^q7TR%1y~d zuheyexhq+`uxz(uxyy7Z9HQK40Fry3)R7&MTa zZSAsIyhOPJp)XZ+t3pXWk59gtJuRhU+~Cx-mnhL(kqw$uW38h{z#gP!8!k`0=UDecSBqB11=U8O|0qYCdJ?b(4PS&qAZLdtXu}a zTP`lzu9L-6x^)EbC#`v=1(sM~o8u-R*V=nAkLNh6FxZyTbjb<1NNAZ^5c1-RuOYP{ z1-gDQK~K$HsXbll`RViTVaXx0(swL=wq)sX2abS1UuL6;l+{zQo6X}Qm3nz z%ppr>2F#YbAiwCg52S48aOo8nY*?@p@=wlvLd#A*h={>SCw8BlWpvbC2Zzp3ObtUVJuZLM>HpQgKwY)XqsT3wL%> zuQBcNvJMA#D=wKBX{9C7xgWR+cQ6-)O?MQO76Gk~v^ z+sGBY?RF2oYXO1oZX4-zqK484HKL7JBmRSO4+^KXpm;(GYM{HJE@v0(m3vxnMjA-# zlt_&*P?3P2KmkV3J&?54kp{&Unn#Dw3FJhULs!EW(6XYS3n0lK$%JMzQQi+CcuD}M z@DLvmKzJY%ZAIbQpuCmPG-feZ(^@LrvSn_sQcLa(bklDbBDd={71h91t{k<2d>CfUfP;jnsY*h1D|>JeW9r5V;y z1MwsK?|iZ`e0awi-PN9oZGt(ziL;p`e+7tE42lb8ReX=V8YE)YPsFTNg#Q=vOrgY- z|1Y@MtgW$~jDDpJN04-QYot3~cbVa2MG52haS$H<9`OT072)#7iMRalzRh0;QpCdf z0)Q7*6vaD?lo@3mO*hf_dhhc9O|JJoO_W>jeVXXldhg@K&MFX?C&Bu_!H1&z(Jo_B G*?$0Arw8u< diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/file.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/file.cpython-311.pyc deleted file mode 100755 index 6f323277cdc98037a8962cf90dc420ce7e292bdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17262 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 YrJe1BCCkYBr@y`vbN~J?OE}H{0guVypa1{> diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputmedia.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputmedia.cpython-311.pyc deleted file mode 100755 index 1dc12ceb21faa610469832d99d60708a7b7722c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37347 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/location.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/location.cpython-311.pyc deleted file mode 100755 index 33e97ac24deb9f81281844921a37d4377e021c47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4402 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 Z{8{in>%&&5ckZ43gknG4CW)`v{{mE-+qVD! diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/venue.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/venue.cpython-311.pyc deleted file mode 100755 index cb1b1f3ed4fbf46657ac964abcd33d1128b37355..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4611 zcmds4O>7&-6`tkqk|IUPk{U&losDFqW=!oiRt_oQ1a|GniqldCtOhB2SgyE3YL#6s zJ3Evtfq@OwK?%sfch9YD7>;Dwdd}!R&^%0GQGJMru$KLkk$ehsmC)Ih*1v*DFcOc8xe-35e(z zKxZ=0>Cz?JE`z;SOszQ30YX-dg4yPdgs&CNnqzEXSz58T@fIc-zVNQzb-bZ%8K7JO zU(_nPU94FETvz~8ZyDtcDy@TWHnd6^8rOGvc?%EZmLzgq=1lJc^D>TFs>MnIn5O1{9-a%}bzjzGU0FVia+aV9lDB(>>*74j#42!1FX` z41&y&{-ZyJ)IQZC!-|h`%2kYe<}zOtoLaSN6NXPF?nq}hD6KkK1w68aO}mPTBYOtO zu%8u6t2&AgYJR3Fe7TOYjn@|)Ot!!=OtD{--UKS2;EjR`9^*EghYf73*C_t~z&mU$ z|IU&BS9pJt&Z9#6y~6vD;lr@}@9_Q<#YZ{i`-Jy&)QxseST{Lv$Qinu8erKn+|sgG+>r!39qs(?ev0kpv@2Mn)M)F~ZWDq6mZ) z0Unm1vFFjhfc#GQ7*W>REyGzubD+nUK&UQ06z)OKgI=$I>Ovi<0biyb0FKSUOFal& zsKy1H8o&x*4{~lf!q_hY! zp+Jrt1A+928-^nc6IWDKqhe51eFn$6F*yHKmZ3OqR4oyVcX2xIh8%2`o?$qT3+Pb! zov*46GuuB=r5oQ}Q8sJ~!(mK{wsP4n+e?a8ttxPvZz-m+u2gsEhFw{bUwK7w42l=4 zTJb%tj2*>K9u&1?n817Ye|3la04CTSeTV0D{yKjKZO%0y|Ga_zF^yuQx1zVBe-Wp@ z6sMb)TjKPdsI*0;B`Tc=S~%SZ-A?Y$ya2EG{@en*5(k+dH$rW3W?z1tz2|!GADw6X ziG!IFcNgzZKAdSi|0>9j9*Bt#6CWgQjouz@@ZTet8@VA}qnaCBw<%%qb|VDS8mSa} zL54;K84lYop~7HWM@^_bUh0Ry`MyvW97yJ`B08XN08B!2puMk84-A969=Hbpe9#9W zd_A27aoPhPLc=g?_GJ57VfzU6z{B9ME&yX_Hv=b`l(jJ37)Sw!zhz_{tDBBpDabjF zv2=hO2i@cZkaXA`Q6U?5u*%#?n8Vy?cYqr#V@jr&SjY_)O{YJO%s{Kd_9wva2APEl znFq3)^sv&^U@)ly5P%AxVQk{V>mOXdL-$fA+o_X{&_QaVgM`@h{={>?ef8_vh4$>} z`xpPT^2e1=^Lv?d?aa9^7WQVB+q27!P$R!5PJf-6ytRFMn<;5tykBfw-%Fior_Qv* zGh_}XNr!S!(n2nsWV^Bg39YKSaaHv`BcYy9RrZz9?TM-?q%6=3JIXO_Nd8pM0YONK z30oXt=L+8h?g-y=%+a>am+B_F`>=>jQ&rP~=M#3mo%0;Rb|+!v1$dkvLJzpX|8)W{ zhQ$tIWLXf$BRAgaoIs~C`{_mYKdp4eXTr~QCeh1sXNuL3PY#aFbi#~b{_I3qO+?40 zIx$v@qiLxb{OJA82;&lHX1=*__jo7CxKW==F>VaaoorsX`?^2R)bTs-wkKaYG+BRI zul5>>jCTUD@KOf>x$|0cr9HdI>z}TC{`1dPdG*iNTJNgu)dFXZBHso<&COr-6&(`d z(d3?kP?A&NJvRbZn^7qfw(EFk+-d*NlD$Jq_OCrJh6CNcp!dm2*v;Wi`Hiw#qwtj{ zv#ZnL@peVOj~^`Dj!%$h69f8p;#m(+Z;&NmS-_pofOLX_Aaq_r!X=@FmJiU&t)u=2 xXt6c?-$zTW;s5?)0}p~@uv3KN`=Pnk@V^sT69fpy(X^5KmiPSq3H^Lk{|4Dk?hyb0 diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/video.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/video.cpython-311.pyc deleted file mode 100755 index 995a356c56808abf284ff772ff58a5616871e463..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4159 zcmeGfO^*~sw0gdK_KRJXj}?#-5Euh9BEn&!MifCXyAVO6bD+0ps%EF4r+cjK*=5Nb zIFN|O#0vysIB>!k{0UzC17)!j2Y>jFkSTHXEnz500dKC54U zJu;Ff(0;l0)%o%|LViUeZs`bl@F5^K2qP83G?uWmW}=eN5KmgkW~!1>c*;sQGnI_O z(^j^btK>A2Ajb*ITp=vWQ+JYt+=VA>6`keIkb-{c&9e>R(x$`O7N<4G_Do^B)U>Hn zJ@`PiX7T^=cTc*p;HrmZ9 zXVaXCb`yH_(+$US&WKAKr=L7?YUZe@d9_F)_1Y8>4{ibSDQL|}MFY(fOsgbWqLR`{ zc(HXX$x^p8mgZ@efhWr|EC-JcPo8IadaB2l4FR25K@YDQ9|1bIVtf>6y-(LCuadgP z#;%N2@>j`4tuh3b8~4*nfAhHUZ#wgw86JAp zupN(gLbZ;_Ikz0mqDo(2PxqF=CgoYzle2{~J;5M=L|t%6>y8Z7M|t+qg@&j#Xbpm{ z%4ypL@jZt!XTi1{ll8cw`Cy&oFax!U%!=LE231?N_XkR43dVVw2m@PzY20?J3>*K`^foDfXXAJ;Ok! zw4bIXV{wwc5@jOfxu~{5fdBLH|9t#+`3PrD{82CdclkKL^*_wV0lxn}9|zd|qkP14 zEu{Tie2V&d@6_`%;Ti1fy(7y{tCM{OYNNc_62^rE6F#bbR;>}tA5}>2+bu_+zL7%+ zbOgfyq7CpEl2}*zdhZ00qd?bGu?dIQQN+dR#jhpfbI& z98jo(Y7EL_M()6#cYFInDNN3go#X&r`|7oCaG6Sd2aPnQ}_lb4#NtU0BV&YW|wWVTwRd2Y{_EKx1B7QKdJA1od?P;!OG z_qWX21#^zOrT9ZrGBAAHlKNB^TZ?i7Y;kE+#dR@O@Hq6jKLB`inf$Sp=%b%yzsUZa z+x$~*b9Zt}cT1tWaXa3dUI>PWK6RgD^!!5vfdZpsbmGf%pP&12WZS)wZ2`&ZhZR_U ze&^MrU!3f2e-U2qbzdmJYkGO#A$ZMn!&fjCPgX1L`CVWg5Z6PjGxplp9m(%uD#uzd+;vo4>oK~9}YH?mx{p@Vk8F39kD!t(ILc!$@-1K2x6mTa_h~vue~0OA+;{1#*vzcsr5)rB6Z^4`rYy78@Ap2 z=-%Y+RTA`Nc_Q`zv<;P?DdgogAp8szWx}3Qw)A(zVOtEtwrEu0e^MQ0oHf<|q{LIg zpISY!g}<2U07QTI8~WpIPgrgdOFuVs6FT4?KlmUKpZ>XefwtS z&6_vB_h#n#>r^UmqL7fOR73fYBKWWwu14|^ z$w$m+HI|P_K5E9RiF`sqA@m+1vD=8mX=FK!&^F~TUN=>?p9^P1?FQ|IYoH| zRv#itK1@RSh>BE1QY1_wUnwL?qa+4zoW@83UX=nj($+_kP)}^B_ds3k)Jy3*sHBkI z+kN@u9duL4_W&wsPi?Qw_&J7<#Ha;G7Z&pZ0$inzW0WZ#H|7my8U;X-Ssk2=S`Bb> zuwBCQ+Uwf!jFwDdD3>I{vfULLD3^=@oEMqU)+MF_>zsP6X1B}%%fy_HQKc9#0Q(tmhDGFJ2rHEUcgw{E+jTld z2}NfO>j<<|uOb>YX>c8C|3gG~sr&B{oe6n~U~7A^=Fu_@cX86F zG5z|20f)C2mphaZFWr5Ra*?cX6^N&{H?gO-Hx}=Ku424(`6}=gyvR8=egg7^av!;( zwN;kkyAo8;!!14SM$}Lmp+>Y3Ys9}*mLVfr39=%jpayyv>PU9DZoQ|4WVnI!cJ9-N zKrIr;6UeLxS_VxkZEcW6p&9fVI)R+XLg;4r3R+MUbOkgudorQvOqBP63JzHt;%Pzp z1Q7^iqFxlP3(CEOt}~0dy6&lP)0VisM6C{p8P$t8)GTdL)CPE)N*J%p!%o*7fxkGn zM7i~BHe0c)G+Q-z(axT?%l4@(;;C-HL6U(oUSnI?ScVYDV!o|NWNSsNM?&nx@=9;A*uK`}M?R1ja1G)nh>e)ZFH#$;mG7@{Lz>K6dXF8=@tI6 z;Q9oAC3U@-69eC?>mu=L^~80Z*hT45-7(>Y2R008jTeTSnTsIfB1So+jY#6?rCPo# zQq$D+jKT+@%Ms!J79SE)iGYlXjvs&kyur^89gHS?B*^;;+I{5KIe!;AIKGxS=JyRo zC;Waiq4|3RhXS&`d%%y1N(_yR`fgPs1m%S=auS*X)QUSRqS;$y-T0rIoN8%>9v;fJ6q z(04uq;)fMQ@ed>Ag0hOvucN)I-OoCjT7fK6rQ!c_S%U9Ddr~)X@^n)MyV}|K$X>2q)-r4F_oZI@qx|SGfoE9yJlvc zkjMuPNKGrGUZ_A-51dj}^wLW&J#p(Xt&r;ODN+wrZ;L{uh*RH;ckLJg>Y{hSPnuonP%fp;DITh6LUsU7ML*{#ypwpDF zRzohGyKugIiq*VYxVw663x)M2FrPwH6jd~cEJn0SoWv@LG)f~fOyVT*wMKNRLlinm z(Ihcwit1xMTOc#m7Bv}}!Qg??485D;v!bL-Nne#R zBlu7WLMzP(kI&>w_$+}uvO1$2*InL?LTXOpg*jH6!!^i#mEx8FFFY3$cfqk;i}b8Y z%kUnjpdp=8+Z1}sgC0J$_eaWe3^BgQg`O?B6+|dn&88c=1D?q}h1H6_6xaxYM@02uj(sB;M{Iik0C>qk@maOV14(50g!&A|;Dg)TRMVKqoE-2)X zKtTvhXq`ELVRfGx9Kf5X=GZaXA-;7pQwbV&rZLOl}5OWg!Ug;Rv8d% zsb^U_Jz)8?G^8}Z78oafRml4f%s{)A}f{4-dIb9XTAnc$;)=O z{u7WdwL8d@v*B2Q=lw`P_cpEcCQ(~!$J%;3`JJ|s0B!hnhlbkdUM!L}KL@QIL!cRN zBeU03+X;|*b_ld-f>yxN{hl>w&*%c$kB%UbScqMZUqTC-hAx4n?n*vZ&L=o@f5e9+ z$x0$a&+EPp=OE?2VVcZgo@x4N=md4{E>WisS>Esyg4*>>HhOUOt--6N>RhHN; zVcdA~VR6oF&|<^lHMe-qopp~Et!A@0Po4Rq&8o%bqBrL{M+--e6b19>8%?Wr)taTE z=!KVpqA61*imGuInu~lpm|q&{UKJwG--0>u1CWgy=&u|~k9?N8mHO4#^NX>klN;}h z=R3Pz?d;wczy)CJ5z^C{$C3n!45N{kzPSAP<)5^iN~Dh~vbHb3eCpQp+T<~K zl!J6MuNEIkwZ}c({##pd8yg#2P50--D7gOPwyE9m2fGtfUt_#N~xgVdrPVRMn_$n`U0) zJ77u3iax<}QY#gam*v9uKmgY06U4@JBS4ZIN27;toDD|M>xVk~4+hzsemvNY4i|z^ z$)Sj>jphPf3Q07!H%Lj&Ks$B?X~|_!ZtvZbx8Dhdq%<5!p{<=0cRzWUJMfgjzUk+3 z>)>=ZkaFJOdqD7$(D|4%tI+Vrqw*?r%d22k;eOdr_e(DSaQ@D|M$2QiD9FYsx-d$B zzD0aO?jaF-V!Yi=%)9(G5G9o2I*=f)X -# -# 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/]. -"""Common base class for media objects""" -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 - -if TYPE_CHECKING: - from telegram import File - - -class _BaseMedium(TelegramObject): - """Base class for objects representing the various media file types. - 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`, optional): File size. - - Attributes: - file_id (:obj:`str`): File identifier. - 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`): Optional. File size. - - - """ - - __slots__ = ("file_id", "file_size", "file_unique_id") - - def __init__( - self, - file_id: str, - file_unique_id: str, - file_size: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.file_id: str = str(file_id) - self.file_unique_id: str = str(file_unique_id) - # Optionals - self.file_size: Optional[int] = file_size - - self._id_attrs = (self.file_unique_id,) - - 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": - """Convenience wrapper over :meth:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return 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, - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_files/_basethumbedmedium.py b/venv/lib/python3.11/site-packages/telegram/_files/_basethumbedmedium.py deleted file mode 100755 index a3dff3a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/_basethumbedmedium.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/]. -"""Common base class for media objects with thumbnails""" -from typing import TYPE_CHECKING, Optional, TypeVar - -from telegram._files._basemedium import _BaseMedium -from telegram._files.photosize import PhotoSize -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - -# pylint: disable=invalid-name -ThumbedMT_co = TypeVar("ThumbedMT_co", bound="_BaseThumbedMedium", covariant=True) - - -class _BaseThumbedMedium(_BaseMedium): - """ - Base class for objects representing the various media file types that may include a thumbnail. - - 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`, optional): File size. - thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail as defined by the sender. - - .. versionadded:: 20.2 - - Attributes: - file_id (:obj:`str`): File identifier. - 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`): Optional. File size. - thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail as defined by the sender. - - .. versionadded:: 20.2 - - """ - - __slots__ = ("thumbnail",) - - def __init__( - self, - file_id: str, - file_unique_id: str, - file_size: Optional[int] = None, - thumbnail: Optional[PhotoSize] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - api_kwargs=api_kwargs, - ) - - self.thumbnail: Optional[PhotoSize] = thumbnail - - @classmethod - def de_json( - cls: type[ThumbedMT_co], data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional[ThumbedMT_co]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # In case this wasn't already done by the subclass - if not isinstance(data.get("thumbnail"), PhotoSize): - data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), 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 data.get("thumb") is not None: - api_kwargs["thumb"] = data.pop("thumb") - - return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.11/site-packages/telegram/_files/animation.py b/venv/lib/python3.11/site-packages/telegram/_files/animation.py deleted file mode 100755 index 537ffc0..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/animation.py +++ /dev/null @@ -1,102 +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 Animation.""" -from typing import Optional - -from telegram._files._basethumbedmedium import _BaseThumbedMedium -from telegram._files.photosize import PhotoSize -from telegram._utils.types import JSONDict - - -class Animation(_BaseThumbedMedium): - """This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound). - - 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. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - 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. - width (:obj:`int`): Video width as defined by the sender. - height (:obj:`int`): Video height as defined by the sender. - duration (:obj:`int`): Duration of the video in seconds as defined by the sender. - file_name (:obj:`str`, optional): Original animation filename as defined by the sender. - mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender. - file_size (:obj:`int`, optional): File size in bytes. - thumbnail (:class:`telegram.PhotoSize`, optional): Animation thumbnail as defined by - sender. - - .. versionadded:: 20.2 - - 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. - width (:obj:`int`): Video width as defined by the sender. - height (:obj:`int`): Video height as defined by the sender. - duration (:obj:`int`): Duration of the video in seconds as defined by the sender. - file_name (:obj:`str`): Optional. Original animation filename as defined by the sender. - mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender. - file_size (:obj:`int`): Optional. File size in bytes. - thumbnail (:class:`telegram.PhotoSize`): Optional. Animation thumbnail as defined by - sender. - - .. versionadded:: 20.2 - - """ - - __slots__ = ("duration", "file_name", "height", "mime_type", "width") - - def __init__( - self, - file_id: str, - file_unique_id: str, - width: int, - height: int, - duration: int, - file_name: Optional[str] = None, - mime_type: Optional[str] = None, - file_size: Optional[int] = None, - thumbnail: Optional[PhotoSize] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - api_kwargs=api_kwargs, - thumbnail=thumbnail, - ) - with self._unfrozen(): - # Required - self.width: int = width - self.height: int = height - self.duration: int = duration - # Optional - self.mime_type: Optional[str] = mime_type - self.file_name: Optional[str] = file_name diff --git a/venv/lib/python3.11/site-packages/telegram/_files/audio.py b/venv/lib/python3.11/site-packages/telegram/_files/audio.py deleted file mode 100755 index af5e420..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/audio.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/]. -"""This module contains an object that represents a Telegram Audio.""" -from typing import Optional - -from telegram._files._basethumbedmedium import _BaseThumbedMedium -from telegram._files.photosize import PhotoSize -from telegram._utils.types import JSONDict - - -class Audio(_BaseThumbedMedium): - """This object represents an audio file to be treated as music by the Telegram clients. - - 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. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - - 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. - duration (:obj:`int`): Duration of the audio in seconds as defined by the sender. - performer (:obj:`str`, optional): Performer of the audio as defined by the sender or by - audio tags. - title (:obj:`str`, optional): Title of the audio as defined by the sender or by audio tags. - file_name (:obj:`str`, optional): Original filename as defined by the sender. - mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender. - file_size (:obj:`int`, optional): File size in bytes. - thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to - which the music file belongs. - - .. versionadded:: 20.2 - - 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. - duration (:obj:`int`): Duration of the audio in seconds as defined by the sender. - performer (:obj:`str`): Optional. Performer of the audio as defined by the sender or by - audio tags. - title (:obj:`str`): Optional. Title of the audio as defined by the sender or by audio tags. - file_name (:obj:`str`): Optional. Original filename as defined by the sender. - mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender. - file_size (:obj:`int`): Optional. File size in bytes. - thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to - which the music file belongs. - - .. versionadded:: 20.2 - - - """ - - __slots__ = ("duration", "file_name", "mime_type", "performer", "title") - - def __init__( - self, - file_id: str, - file_unique_id: str, - duration: int, - performer: Optional[str] = None, - title: Optional[str] = None, - mime_type: Optional[str] = None, - file_size: Optional[int] = None, - file_name: Optional[str] = None, - thumbnail: Optional[PhotoSize] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - # Required - self.duration: int = duration - # Optional - self.performer: Optional[str] = performer - self.title: Optional[str] = title - self.mime_type: Optional[str] = mime_type - self.file_name: Optional[str] = file_name diff --git a/venv/lib/python3.11/site-packages/telegram/_files/chatphoto.py b/venv/lib/python3.11/site-packages/telegram/_files/chatphoto.py deleted file mode 100755 index 5d6e914..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/chatphoto.py +++ /dev/null @@ -1,176 +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 ChatPhoto.""" -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import File - - -class ChatPhoto(TelegramObject): - """This object represents a chat photo. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`small_file_unique_id` and :attr:`big_file_unique_id` are - equal. - - Args: - small_file_id (:obj:`str`): File identifier of small - (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`) - chat photo. This file_id can be used only for photo download and only for as long - as the photo is not changed. - small_file_unique_id (:obj:`str`): Unique file identifier of small - (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`) - chat photo, which is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - big_file_id (:obj:`str`): File identifier of big - (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`) - chat photo. This file_id can be used only for photo download and only for as long as - the photo is not changed. - big_file_unique_id (:obj:`str`): Unique file identifier of big - (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`) - chat photo, which is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - - Attributes: - small_file_id (:obj:`str`): File identifier of small - (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`) - chat photo. This file_id can be used only for photo download and only for as long - as the photo is not changed. - small_file_unique_id (:obj:`str`): Unique file identifier of small - (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`) - chat photo, which is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - big_file_id (:obj:`str`): File identifier of big - (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`) - chat photo. This file_id can be used only for photo download and only for as long as - the photo is not changed. - big_file_unique_id (:obj:`str`): Unique file identifier of big - (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`) - chat photo, which is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - - """ - - __slots__ = ( - "big_file_id", - "big_file_unique_id", - "small_file_id", - "small_file_unique_id", - ) - - def __init__( - self, - small_file_id: str, - small_file_unique_id: str, - big_file_id: str, - big_file_unique_id: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.small_file_id: str = small_file_id - self.small_file_unique_id: str = small_file_unique_id - self.big_file_id: str = big_file_id - self.big_file_unique_id: str = big_file_unique_id - - self._id_attrs = ( - self.small_file_unique_id, - self.big_file_unique_id, - ) - - self._freeze() - - async def get_small_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": - """Convenience wrapper over :meth:`telegram.Bot.get_file` for getting the small - (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`) - chat photo - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return await self.get_bot().get_file( - file_id=self.small_file_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - async def get_big_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": - """Convenience wrapper over :meth:`telegram.Bot.get_file` for getting the - big (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`) - chat photo - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return await self.get_bot().get_file( - file_id=self.big_file_id, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - api_kwargs=api_kwargs, - ) - - SIZE_SMALL: Final[int] = constants.ChatPhotoSize.SMALL - """:const:`telegram.constants.ChatPhotoSize.SMALL` - - .. versionadded:: 20.0 - """ - SIZE_BIG: Final[int] = constants.ChatPhotoSize.BIG - """:const:`telegram.constants.ChatPhotoSize.BIG` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_files/contact.py b/venv/lib/python3.11/site-packages/telegram/_files/contact.py deleted file mode 100755 index 1ff05b3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/contact.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 an object that represents a Telegram Contact.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class Contact(TelegramObject): - """This object represents a phone contact. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`phone_number` is equal. - - Args: - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`, optional): Contact's last name. - user_id (:obj:`int`, optional): Contact's user identifier in Telegram. - vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard. - - Attributes: - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`): Optional. Contact's last name. - user_id (:obj:`int`): Optional. Contact's user identifier in Telegram. - vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard. - - """ - - __slots__ = ("first_name", "last_name", "phone_number", "user_id", "vcard") - - def __init__( - self, - phone_number: str, - first_name: str, - last_name: Optional[str] = None, - user_id: Optional[int] = None, - vcard: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.phone_number: str = str(phone_number) - self.first_name: str = first_name - # Optionals - self.last_name: Optional[str] = last_name - self.user_id: Optional[int] = user_id - self.vcard: Optional[str] = vcard - - self._id_attrs = (self.phone_number,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_files/document.py b/venv/lib/python3.11/site-packages/telegram/_files/document.py deleted file mode 100755 index 7ddaeaf..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/document.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 an object that represents a Telegram Document.""" -from typing import Optional - -from telegram._files._basethumbedmedium import _BaseThumbedMedium -from telegram._files.photosize import PhotoSize -from telegram._utils.types import JSONDict - - -class Document(_BaseThumbedMedium): - """This object represents a general file - (as opposed to photos, voice messages and audio files). - - 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. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - 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_name (:obj:`str`, optional): Original filename as defined by the sender. - mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender. - file_size (:obj:`int`, optional): File size in bytes. - thumbnail (:class:`telegram.PhotoSize`, optional): Document thumbnail as defined by the - sender. - - .. versionadded:: 20.2 - - 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_name (:obj:`str`): Optional. Original filename as defined by the sender. - mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender. - file_size (:obj:`int`): Optional. File size in bytes. - thumbnail (:class:`telegram.PhotoSize`): Optional. Document thumbnail as defined by the - sender. - - .. versionadded:: 20.2 - - """ - - __slots__ = ("file_name", "mime_type") - - def __init__( - self, - file_id: str, - file_unique_id: str, - file_name: Optional[str] = None, - mime_type: Optional[str] = None, - file_size: Optional[int] = None, - thumbnail: Optional[PhotoSize] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - # Optional - self.mime_type: Optional[str] = mime_type - self.file_name: Optional[str] = file_name diff --git a/venv/lib/python3.11/site-packages/telegram/_files/file.py b/venv/lib/python3.11/site-packages/telegram/_files/file.py deleted file mode 100755 index 38fdac7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/file.py +++ /dev/null @@ -1,371 +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 File.""" -import shutil -import urllib.parse as urllib_parse -from base64 import b64decode -from pathlib import Path -from typing import TYPE_CHECKING, BinaryIO, Optional - -from telegram._passport.credentials import decrypt -from telegram._telegramobject import TelegramObject -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.files import is_local_file -from telegram._utils.types import FilePathInput, JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import FileCredentials - - -class File(TelegramObject): - """ - This object represents a file ready to be downloaded. The file can be e.g. downloaded with - :attr:`download_to_drive`. It is guaranteed that the link will be valid for at least 1 hour. - When the link expires, a new one can be requested by calling :meth:`telegram.Bot.get_file`. - - 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. - - .. versionchanged:: 20.0 - ``download`` was split into :meth:`download_to_drive` and :meth:`download_to_memory`. - - Note: - * Maximum file size to download is - :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD`. - * If you obtain an instance of this class from :attr:`telegram.PassportFile.get_file`, - then it will automatically be decrypted as it downloads when you call e.g. - :meth:`download_to_drive`. - - 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`, optional): File size in bytes, if known. - file_path (:obj:`str`, optional): File path. Use e.g. :meth:`download_to_drive` to get the - file. - - 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`): Optional. File size in bytes, if known. - file_path (:obj:`str`): Optional. File path. Use e.g. :meth:`download_to_drive` to get the - file. - """ - - __slots__ = ( - "_credentials", - "file_id", - "file_path", - "file_size", - "file_unique_id", - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - file_size: Optional[int] = None, - file_path: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.file_id: str = str(file_id) - self.file_unique_id: str = str(file_unique_id) - # Optionals - self.file_size: Optional[int] = file_size - self.file_path: Optional[str] = file_path - - self._credentials: Optional[FileCredentials] = None - - self._id_attrs = (self.file_unique_id,) - - self._freeze() - - def _get_encoded_url(self) -> str: - """Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string.""" - sres = urllib_parse.urlsplit(str(self.file_path)) - return urllib_parse.urlunsplit( - urllib_parse.SplitResult( - sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment - ) - ) - - def _prepare_decrypt(self, buf: bytes) -> bytes: - return decrypt(b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf) - - async def download_to_drive( - self, - custom_path: Optional[FilePathInput] = 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, - ) -> Path: - """ - Download this file. By default, the file is saved in the current working directory with - :attr:`file_path` as file name. If :paramref:`custom_path` is supplied as a :obj:`str` or - :obj:`pathlib.Path`, it will be saved to that path. - - Note: - If :paramref:`custom_path` isn't provided and :attr:`file_path` is the path of a - local file (which is the case when a Bot API Server is running in local mode), this - method will just return the path. - - The only exception to this are encrypted files (e.g. a passport file). For these, a - file with the prefix `decrypted_` will be created in the same directory as the - original file in order to decrypt the file without changing the existing one - in-place. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.0 - - * :paramref:`custom_path` parameter now also accepts :class:`pathlib.Path` as argument. - * Returns :class:`pathlib.Path` object in cases where previously a :obj:`str` was - returned. - * This method was previously called ``download``. It was split into - :meth:`download_to_drive` and :meth:`download_to_memory`. - - .. versionchanged:: 21.7 - Raises :exc:`RuntimeError` if :attr:`file_path` is not set. Note that files without - a :attr:`file_path` could never be downloaded, as this attribute is mandatory for that - operation. - - Args: - custom_path (:class:`pathlib.Path` | :obj:`str` , optional): The path where the file - will be saved to. If not specified, will be saved in the current working directory - with :attr:`file_path` as file name or the :attr:`file_id` if :attr:`file_path` - is not set. - - Keyword Args: - read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - Returns: - :class:`pathlib.Path`: Returns the Path object the file was downloaded to. - - Raises: - RuntimeError: If :attr:`file_path` is not set. - - """ - if not self.file_path: - raise RuntimeError("No `file_path` available for this file. Can not download.") - - local_file = is_local_file(self.file_path) - url = None if local_file else self._get_encoded_url() - - # if _credentials exists we want to decrypt the file - if local_file and self._credentials: - file_to_decrypt = Path(self.file_path) - buf = self._prepare_decrypt(file_to_decrypt.read_bytes()) - if custom_path is not None: - path = Path(custom_path) - else: - path = Path(str(file_to_decrypt.parent) + "/decrypted_" + file_to_decrypt.name) - path.write_bytes(buf) - return path - - if custom_path is not None and local_file: - shutil.copyfile(self.file_path, str(custom_path)) - return Path(custom_path) - - if custom_path: - filename = Path(custom_path) - elif local_file: - return Path(self.file_path) - else: - filename = Path(Path(self.file_path).name) - - buf = await self.get_bot().request.retrieve( - url, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - if self._credentials: - buf = self._prepare_decrypt(buf) - filename.write_bytes(buf) - return filename - - async def download_to_memory( - self, - out: BinaryIO, - *, - read_timeout: ODVInput[float] = DEFAULT_NONE, - write_timeout: ODVInput[float] = DEFAULT_NONE, - connect_timeout: ODVInput[float] = DEFAULT_NONE, - pool_timeout: ODVInput[float] = DEFAULT_NONE, - ) -> None: - """ - Download this file into memory. :paramref:`out` needs to be supplied with a - :obj:`io.BufferedIOBase`, the file contents will be saved to that object using the - :obj:`out.write` method. - - .. seealso:: :wiki:`Working with Files and Media ` - - Hint: - If you want to immediately read the data from ``out`` after calling this method, you - should call ``out.seek(0)`` first. See also :meth:`io.IOBase.seek`. - - .. versionadded:: 20.0 - - .. versionchanged:: 21.7 - Raises :exc:`RuntimeError` if :attr:`file_path` is not set. Note that files without - a :attr:`file_path` could never be downloaded, as this attribute is mandatory for that - operation. - - Args: - out (:obj:`io.BufferedIOBase`): A file-like object. Must be opened for writing in - binary mode. - - Keyword Args: - read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - Raises: - RuntimeError: If :attr:`file_path` is not set. - """ - if not self.file_path: - raise RuntimeError("No `file_path` available for this file. Can not download.") - - local_file = is_local_file(self.file_path) - url = None if local_file else self._get_encoded_url() - path = Path(self.file_path) if local_file else None - if local_file: - buf = path.read_bytes() - else: - buf = await self.get_bot().request.retrieve( - url, - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - if self._credentials: - buf = self._prepare_decrypt(buf) - out.write(buf) - - async def download_as_bytearray( - self, - buf: Optional[bytearray] = 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, - ) -> bytearray: - """Download this file and return it as a bytearray. - - .. versionchanged:: 21.7 - Raises :exc:`RuntimeError` if :attr:`file_path` is not set. Note that files without - a :attr:`file_path` could never be downloaded, as this attribute is mandatory for that - operation. - - Args: - buf (:obj:`bytearray`, optional): Extend the given bytearray with the downloaded data. - - Keyword Args: - read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. versionadded:: 20.0 - write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. versionadded:: 20.0 - connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. versionadded:: 20.0 - pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to - :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to - :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. - - .. versionadded:: 20.0 - - Returns: - :obj:`bytearray`: The same object as :paramref:`buf` if it was specified. Otherwise a - newly allocated :obj:`bytearray`. - - Raises: - RuntimeError: If :attr:`file_path` is not set. - - """ - if not self.file_path: - raise RuntimeError("No `file_path` available for this file. Can not download.") - - if buf is None: - buf = bytearray() - - if is_local_file(self.file_path): - bytes_data = Path(self.file_path).read_bytes() - else: - bytes_data = await self.get_bot().request.retrieve( - self._get_encoded_url(), - read_timeout=read_timeout, - write_timeout=write_timeout, - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - ) - if self._credentials: - buf.extend(self._prepare_decrypt(bytes_data)) - else: - buf.extend(bytes_data) - return buf - - def set_credentials(self, credentials: "FileCredentials") -> None: - """Sets the passport credentials for the file. - - Args: - credentials (:class:`telegram.FileCredentials`): The credentials. - """ - self._credentials = credentials diff --git a/venv/lib/python3.11/site-packages/telegram/_files/inputfile.py b/venv/lib/python3.11/site-packages/telegram/_files/inputfile.py deleted file mode 100755 index 8c88a9d..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/inputfile.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 an object that represents a Telegram InputFile.""" - -import mimetypes -from typing import IO, Optional, Union -from uuid import uuid4 - -from telegram._utils.files import guess_file_name, load_file -from telegram._utils.strings import TextEncoding -from telegram._utils.types import FieldTuple - -_DEFAULT_MIME_TYPE = "application/octet-stream" - - -class InputFile: - """This object represents a Telegram InputFile. - - .. versionchanged:: 20.0 - - * The former attribute ``attach`` was renamed to :attr:`attach_name`. - * Method ``is_image`` was removed. If you pass :obj:`bytes` to :paramref:`obj` and would - like to have the mime type automatically guessed, please pass :paramref:`filename` - in addition. - - Args: - obj (:term:`file object` | :obj:`bytes` | :obj:`str`): An open file descriptor or the files - content as bytes or string. - - Note: - If :paramref:`obj` is a string, it will be encoded as bytes via - :external:obj:`obj.encode('utf-8') `. - - .. versionchanged:: 20.0 - Accept string input. - filename (:obj:`str`, optional): Filename for this InputFile. - 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`. - read_file_handle (:obj:`bool`, optional): If :obj:`True` and :paramref:`obj` is a file - handle, the data will be read from the file handle on initialization of this object. - If :obj:`False`, the file handle will be passed on to the - :attr:`networking backend ` which will have - to handle the reading. Defaults to :obj:`True`. - - Tip: - If you upload extremely large files, you may want to set this to :obj:`False` to - avoid reading the complete file into memory. Additionally, this may be supported - better by the networking backend (in particular it is handled better by - the default :class:`~telegram.request.HTTPXRequest`). - - Important: - If you set this to :obj:`False`, you have to ensure that the file handle is still - open when the request is made. In particular, the following snippet can *not* work - as expected. - - .. code-block:: python - - with open('file.txt', 'rb') as file: - input_file = InputFile(file, read_file_handle=False) - - # here the file handle is already closed and the upload will fail - await bot.send_document(chat_id, input_file) - - .. versionadded:: 21.5 - - - Attributes: - input_file_content (:obj:`bytes` | :class:`IO`): The binary content of the file to send. - attach_name (:obj:`str`): Optional. If present, the parameter this file belongs to in - the request to Telegram should point to the multipart data via a an URI of the form - ``attach://`` URI. - filename (:obj:`str`): Filename for the file to be sent. - mimetype (:obj:`str`): The mimetype inferred from the file to be sent. - - """ - - __slots__ = ("attach_name", "filename", "input_file_content", "mimetype") - - def __init__( - self, - obj: Union[IO[bytes], bytes, str], - filename: Optional[str] = None, - attach: bool = False, - read_file_handle: bool = True, - ): - if isinstance(obj, bytes): - self.input_file_content: Union[bytes, IO[bytes]] = obj - elif isinstance(obj, str): - self.input_file_content = obj.encode(TextEncoding.UTF_8) - elif read_file_handle: - reported_filename, self.input_file_content = load_file(obj) - filename = filename or reported_filename - else: - self.input_file_content = obj - filename = filename or guess_file_name(obj) - - self.attach_name: Optional[str] = "attached" + uuid4().hex if attach else None - - if filename: - self.mimetype: str = ( - mimetypes.guess_type(filename, strict=False)[0] or _DEFAULT_MIME_TYPE - ) - else: - self.mimetype = _DEFAULT_MIME_TYPE - - self.filename: str = filename or self.mimetype.replace("/", ".") - - @property - def field_tuple(self) -> FieldTuple: - """Field tuple representing the contents of the file for upload to the Telegram servers. - - .. versionchanged:: 21.5 - Content may now be a file handle. - - Returns: - tuple[:obj:`str`, :obj:`bytes` | :class:`IO`, :obj:`str`]: - """ - return self.filename, self.input_file_content, self.mimetype - - @property - def attach_uri(self) -> Optional[str]: - """URI to insert into the JSON data for uploading the file. Returns :obj:`None`, if - :attr:`attach_name` is :obj:`None`. - """ - return f"attach://{self.attach_name}" if self.attach_name else None diff --git a/venv/lib/python3.11/site-packages/telegram/_files/inputmedia.py b/venv/lib/python3.11/site-packages/telegram/_files/inputmedia.py deleted file mode 100755 index 0ac17c2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/inputmedia.py +++ /dev/null @@ -1,827 +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 InputMedia Objects.""" -from collections.abc import Sequence -from typing import Final, Optional, Union - -from telegram import constants -from telegram._files.animation import Animation -from telegram._files.audio import Audio -from telegram._files.document import Document -from telegram._files.inputfile import InputFile -from telegram._files.photosize import PhotoSize -from telegram._files.video import Video -from telegram._messageentity import MessageEntity -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE -from telegram._utils.files import parse_file_input -from telegram._utils.types import FileInput, JSONDict, ODVInput -from telegram.constants import InputMediaType - -MediaType = Union[Animation, Audio, Document, PhotoSize, Video] - - -class InputMedia(TelegramObject): - """ - Base class for Telegram InputMedia Objects. - - .. versionchanged:: 20.0 - Added arguments and attributes :attr:`type`, :attr:`media`, :attr:`caption`, - :attr:`caption_entities`, :paramref:`parse_mode`. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - media_type (:obj:`str`): Type of media that the instance represents. - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \ - :class:`pathlib.Path` | :class:`telegram.Animation` | :class:`telegram.Audio` | \ - :class:`telegram.Document` | :class:`telegram.PhotoSize` | \ - :class:`telegram.Video`): File to send. - |fileinputnopath| - Lastly you can pass an existing telegram media object of the corresponding type - to send. - caption (:obj:`str`, optional): Caption of the media to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - parse_mode (:obj:`str`, optional): |parse_mode| - - Attributes: - type (:obj:`str`): Type of the input media. - media (:obj:`str` | :class:`telegram.InputFile`): Media to send. - caption (:obj:`str`): Optional. Caption of the media to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities - parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - - """ - - __slots__ = ("caption", "caption_entities", "media", "parse_mode", "type") - - def __init__( - self, - media_type: str, - media: Union[str, InputFile, MediaType], - caption: Optional[str] = None, - caption_entities: Optional[Sequence[MessageEntity]] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.type: str = enum.get_member(constants.InputMediaType, media_type, media_type) - self.media: Union[str, InputFile, Animation, Audio, Document, PhotoSize, Video] = media - self.caption: Optional[str] = caption - self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities) - self.parse_mode: ODVInput[str] = parse_mode - - self._freeze() - - @staticmethod - def _parse_thumbnail_input(thumbnail: Optional[FileInput]) -> Optional[Union[str, InputFile]]: - # We use local_mode=True because we don't have access to the actual setting and want - # things to work in local mode. - return ( - parse_file_input(thumbnail, attach=True, local_mode=True) - if thumbnail is not None - else thumbnail - ) - - -class InputPaidMedia(TelegramObject): - """ - Base class for Telegram InputPaidMedia Objects. Currently, it can be one of: - - * :class:`telegram.InputMediaPhoto` - * :class:`telegram.InputMediaVideo` - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): Type of media that the instance represents. - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \ - :class:`pathlib.Path` | :class:`telegram.PhotoSize` | :class:`telegram.Video`): File - to send. |fileinputnopath| - Lastly you can pass an existing telegram media object of the corresponding type - to send. - - Attributes: - type (:obj:`str`): Type of the input media. - media (:obj:`str` | :class:`telegram.InputFile`): Media to send. - """ - - PHOTO: Final[str] = constants.InputPaidMediaType.PHOTO - """:const:`telegram.constants.InputPaidMediaType.PHOTO`""" - VIDEO: Final[str] = constants.InputPaidMediaType.VIDEO - """:const:`telegram.constants.InputPaidMediaType.VIDEO`""" - - __slots__ = ("media", "type") - - def __init__( - self, - type: str, # pylint: disable=redefined-builtin - media: Union[str, InputFile, PhotoSize, Video], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.type: str = enum.get_member(constants.InputPaidMediaType, type, type) - self.media: Union[str, InputFile, PhotoSize, Video] = media - - self._freeze() - - -class InputPaidMediaPhoto(InputPaidMedia): - """The paid media to send is a photo. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionadded:: 21.4 - - Args: - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \ - :class:`pathlib.Path` | :class:`telegram.PhotoSize`): File to send. |fileinputnopath| - Lastly you can pass an existing :class:`telegram.PhotoSize` object to send. - - Attributes: - type (:obj:`str`): Type of the media, always - :tg-const:`telegram.constants.InputPaidMediaType.PHOTO`. - media (:obj:`str` | :class:`telegram.InputFile`): Photo to send. - """ - - __slots__ = () - - def __init__( - self, - media: Union[FileInput, PhotoSize], - *, - api_kwargs: Optional[JSONDict] = None, - ): - media = parse_file_input(media, PhotoSize, attach=True, local_mode=True) - super().__init__(type=InputPaidMedia.PHOTO, media=media, api_kwargs=api_kwargs) - self._freeze() - - -class InputPaidMediaVideo(InputPaidMedia): - """ - The paid media to send is a video. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionadded:: 21.4 - - Note: - * When using a :class:`telegram.Video` for the :attr:`media` attribute, it will take the - width, height and duration from that video, unless otherwise specified with the optional - arguments. - * :paramref:`thumbnail` will be ignored for small video files, for which Telegram can - easily generate thumbnails. However, this behaviour is undocumented and might be - changed by Telegram. - - Args: - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \ - :class:`pathlib.Path` | :class:`telegram.Video`): File to send. |fileinputnopath| - Lastly you can pass an existing :class:`telegram.Video` object to send. - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstringnopath| - width (:obj:`int`, optional): Video width. - height (:obj:`int`, optional): Video height. - duration (:obj:`int`, optional): Video duration in seconds. - supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is - suitable for streaming. - - Attributes: - type (:obj:`str`): Type of the media, always - :tg-const:`telegram.constants.InputPaidMediaType.VIDEO`. - media (:obj:`str` | :class:`telegram.InputFile`): Video to send. - thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase| - width (:obj:`int`): Optional. Video width. - height (:obj:`int`): Optional. Video height. - duration (:obj:`int`): Optional. Video duration in seconds. - supports_streaming (:obj:`bool`): Optional. :obj:`True`, if the uploaded video is - suitable for streaming. - """ - - __slots__ = ("duration", "height", "supports_streaming", "thumbnail", "width") - - def __init__( - self, - media: Union[FileInput, Video], - thumbnail: Optional[FileInput] = None, - width: Optional[int] = None, - height: Optional[int] = None, - duration: Optional[int] = None, - supports_streaming: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - if isinstance(media, Video): - width = width if width is not None else media.width - height = height if height is not None else media.height - duration = duration if duration is not None else media.duration - media = media.file_id - else: - # We use local_mode=True because we don't have access to the actual setting and want - # things to work in local mode. - media = parse_file_input(media, attach=True, local_mode=True) - - super().__init__(type=InputPaidMedia.VIDEO, media=media, api_kwargs=api_kwargs) - with self._unfrozen(): - self.thumbnail: Optional[Union[str, InputFile]] = InputMedia._parse_thumbnail_input( - thumbnail - ) - self.width: Optional[int] = width - self.height: Optional[int] = height - self.duration: Optional[int] = duration - self.supports_streaming: Optional[bool] = supports_streaming - - -class InputMediaAnimation(InputMedia): - """Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent. - - Note: - When using a :class:`telegram.Animation` for the :attr:`media` attribute, it will take the - width, height and duration from that animation, unless otherwise specified with the - optional arguments. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_note| - - Args: - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \ - :class:`pathlib.Path` | :class:`telegram.Animation`): File to send. |fileinputnopath| - Lastly you can pass an existing :class:`telegram.Animation` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the animation, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Caption of the animation to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - width (:obj:`int`, optional): Animation width. - height (:obj:`int`, optional): Animation height. - duration (:obj:`int`, optional): Animation duration in seconds. - has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the animation needs to be covered - with a spoiler animation. - - .. versionadded:: 20.0 - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstringnopath| - - .. versionadded:: 20.2 - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.ANIMATION`. - media (:obj:`str` | :class:`telegram.InputFile`): Animation to send. - caption (:obj:`str`): Optional. Caption of the animation to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - width (:obj:`int`): Optional. Animation width. - height (:obj:`int`): Optional. Animation height. - duration (:obj:`int`): Optional. Animation duration in seconds. - has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the animation is covered with a - spoiler animation. - - .. versionadded:: 20.0 - thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase| - - .. versionadded:: 20.2 - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - """ - - __slots__ = ( - "duration", - "has_spoiler", - "height", - "show_caption_above_media", - "thumbnail", - "width", - ) - - def __init__( - self, - media: Union[FileInput, Animation], - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - width: Optional[int] = None, - height: Optional[int] = None, - duration: Optional[int] = None, - caption_entities: Optional[Sequence[MessageEntity]] = None, - filename: Optional[str] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - if isinstance(media, Animation): - width = media.width if width is None else width - height = media.height if height is None else height - duration = media.duration if duration is None else duration - media = media.file_id - else: - # We use local_mode=True because we don't have access to the actual setting and want - # things to work in local mode. - media = parse_file_input(media, filename=filename, attach=True, local_mode=True) - - super().__init__( - InputMediaType.ANIMATION, - media, - caption, - caption_entities, - parse_mode, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumbnail_input( - thumbnail - ) - self.width: Optional[int] = width - self.height: Optional[int] = height - self.duration: Optional[int] = duration - self.has_spoiler: Optional[bool] = has_spoiler - self.show_caption_above_media: Optional[bool] = show_caption_above_media - - -class InputMediaPhoto(InputMedia): - """Represents a photo to be sent. - - .. seealso:: :wiki:`Working with Files and Media ` - - Args: - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \ - :class:`pathlib.Path` | :class:`telegram.PhotoSize`): File to send. |fileinputnopath| - Lastly you can pass an existing :class:`telegram.PhotoSize` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the photo, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional ): Caption of the photo to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the photo needs to be covered - with a spoiler animation. - - .. versionadded:: 20.0 - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.PHOTO`. - media (:obj:`str` | :class:`telegram.InputFile`): Photo to send. - caption (:obj:`str`): Optional. Caption of the photo to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the photo is covered with a - spoiler animation. - - .. versionadded:: 20.0 - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - """ - - __slots__ = ( - "has_spoiler", - "show_caption_above_media", - ) - - def __init__( - self, - media: Union[FileInput, PhotoSize], - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - filename: Optional[str] = None, - has_spoiler: Optional[bool] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # We use local_mode=True because we don't have access to the actual setting and want - # things to work in local mode. - media = parse_file_input(media, PhotoSize, filename=filename, attach=True, local_mode=True) - super().__init__( - InputMediaType.PHOTO, - media, - caption, - caption_entities, - parse_mode, - api_kwargs=api_kwargs, - ) - - with self._unfrozen(): - self.has_spoiler: Optional[bool] = has_spoiler - self.show_caption_above_media: Optional[bool] = show_caption_above_media - - -class InputMediaVideo(InputMedia): - """Represents a video to be sent. - - .. seealso:: :wiki:`Working with Files and Media ` - - Note: - * When using a :class:`telegram.Video` for the :attr:`media` attribute, it will take the - width, height and duration from that video, unless otherwise specified with the optional - arguments. - * :paramref:`thumbnail` will be ignored for small video files, for which Telegram can - easily generate thumbnails. However, this behaviour is undocumented and might be - changed by Telegram. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - Args: - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \ - :class:`pathlib.Path` | :class:`telegram.Video`): File to send. |fileinputnopath| - Lastly you can pass an existing :class:`telegram.Video` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the video, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Caption of the video to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - width (:obj:`int`, optional): Video width. - height (:obj:`int`, optional): Video height. - duration (:obj:`int`, optional): Video duration in seconds. - supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is - suitable for streaming. - has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the video needs to be covered - with a spoiler animation. - - .. versionadded:: 20.0 - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstringnopath| - - .. versionadded:: 20.2 - show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| - - .. versionadded:: 21.3 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.VIDEO`. - media (:obj:`str` | :class:`telegram.InputFile`): Video file to send. - caption (:obj:`str`): Optional. Caption of the video to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - width (:obj:`int`): Optional. Video width. - height (:obj:`int`): Optional. Video height. - duration (:obj:`int`): Optional. Video duration in seconds. - supports_streaming (:obj:`bool`): Optional. :obj:`True`, if the uploaded video is - suitable for streaming. - has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the video is covered with a - spoiler animation. - - .. versionadded:: 20.0 - thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase| - - .. versionadded:: 20.2 - show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med| - - .. versionadded:: 21.3 - """ - - __slots__ = ( - "duration", - "has_spoiler", - "height", - "show_caption_above_media", - "supports_streaming", - "thumbnail", - "width", - ) - - def __init__( - self, - media: Union[FileInput, Video], - caption: Optional[str] = None, - width: Optional[int] = None, - height: Optional[int] = None, - duration: Optional[int] = None, - supports_streaming: Optional[bool] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Optional[Sequence[MessageEntity]] = None, - filename: Optional[str] = None, - has_spoiler: Optional[bool] = None, - thumbnail: Optional[FileInput] = None, - show_caption_above_media: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - if isinstance(media, Video): - width = width if width is not None else media.width - height = height if height is not None else media.height - duration = duration if duration is not None else media.duration - media = media.file_id - else: - # We use local_mode=True because we don't have access to the actual setting and want - # things to work in local mode. - media = parse_file_input(media, filename=filename, attach=True, local_mode=True) - - super().__init__( - InputMediaType.VIDEO, - media, - caption, - caption_entities, - parse_mode, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - self.width: Optional[int] = width - self.height: Optional[int] = height - self.duration: Optional[int] = duration - self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumbnail_input( - thumbnail - ) - self.supports_streaming: Optional[bool] = supports_streaming - self.has_spoiler: Optional[bool] = has_spoiler - self.show_caption_above_media: Optional[bool] = show_caption_above_media - - -class InputMediaAudio(InputMedia): - """Represents an audio file to be treated as music to be sent. - - .. seealso:: :wiki:`Working with Files and Media ` - - Note: - When using a :class:`telegram.Audio` for the :attr:`media` attribute, it will take the - duration, performer and title from that video, unless otherwise specified with the - optional arguments. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - Args: - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \ - :class:`pathlib.Path` | :class:`telegram.Audio`): File to send. |fileinputnopath| - Lastly you can pass an existing :class:`telegram.Audio` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the audio, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Caption of the audio to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - duration (:obj:`int`, optional): Duration of the audio in seconds as defined by the sender. - performer (:obj:`str`, optional): Performer of the audio as defined by the sender or by - audio tags. - title (:obj:`str`, optional): Title of the audio as defined by the sender or by audio tags. - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstringnopath| - - .. versionadded:: 20.2 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.AUDIO`. - media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send. - caption (:obj:`str`): Optional. Caption of the audio to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - duration (:obj:`int`): Optional. Duration of the audio in seconds. - performer (:obj:`str`): Optional. Performer of the audio as defined by the sender or by - audio tags. - title (:obj:`str`): Optional. Title of the audio as defined by the sender or by audio tags. - thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase| - - .. versionadded:: 20.2 - - """ - - __slots__ = ("duration", "performer", "thumbnail", "title") - - def __init__( - self, - media: Union[FileInput, Audio], - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - duration: Optional[int] = None, - performer: Optional[str] = None, - title: Optional[str] = None, - caption_entities: Optional[Sequence[MessageEntity]] = None, - filename: Optional[str] = None, - thumbnail: Optional[FileInput] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - if isinstance(media, Audio): - duration = media.duration if duration is None else duration - performer = media.performer if performer is None else performer - title = media.title if title is None else title - media = media.file_id - else: - # We use local_mode=True because we don't have access to the actual setting and want - # things to work in local mode. - media = parse_file_input(media, filename=filename, attach=True, local_mode=True) - - super().__init__( - InputMediaType.AUDIO, - media, - caption, - caption_entities, - parse_mode, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumbnail_input( - thumbnail - ) - self.duration: Optional[int] = duration - self.title: Optional[str] = title - self.performer: Optional[str] = performer - - -class InputMediaDocument(InputMedia): - """Represents a general file to be sent. - - .. seealso:: :wiki:`Working with Files and Media ` - - .. versionchanged:: 20.5 - |removed_thumb_note| - - Args: - media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \ - | :class:`pathlib.Path` | :class:`telegram.Document`): File to send. |fileinputnopath| - Lastly you can pass an existing :class:`telegram.Document` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the document, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Caption of the document to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after - entities parsing. - parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| - - .. versionchanged:: 20.0 - |sequenceclassargs| - - disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side - content type detection for files uploaded using multipart/form-data. Always - :obj:`True`, if the document is sent as part of an album. - thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \ - optional): |thumbdocstringnopath| - - .. versionadded:: 20.2 - - Attributes: - type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.DOCUMENT`. - media (:obj:`str` | :class:`telegram.InputFile`): File to send. - caption (:obj:`str`): Optional. Caption of the document to be sent, - 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters - after entities parsing. - parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| - - .. versionchanged:: 20.0 - - * |tupleclassattrs| - * |alwaystuple| - disable_content_type_detection (:obj:`bool`): Optional. Disables automatic server-side - content type detection for files uploaded using multipart/form-data. Always - :obj:`True`, if the document is sent as part of an album. - thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase| - - .. versionadded:: 20.2 - """ - - __slots__ = ("disable_content_type_detection", "thumbnail") - - def __init__( - self, - media: Union[FileInput, Document], - caption: Optional[str] = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_content_type_detection: Optional[bool] = None, - caption_entities: Optional[Sequence[MessageEntity]] = None, - filename: Optional[str] = None, - thumbnail: Optional[FileInput] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - # We use local_mode=True because we don't have access to the actual setting and want - # things to work in local mode. - media = parse_file_input(media, Document, filename=filename, attach=True, local_mode=True) - - super().__init__( - InputMediaType.DOCUMENT, - media, - caption, - caption_entities, - parse_mode, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumbnail_input( - thumbnail - ) - self.disable_content_type_detection: Optional[bool] = disable_content_type_detection diff --git a/venv/lib/python3.11/site-packages/telegram/_files/inputsticker.py b/venv/lib/python3.11/site-packages/telegram/_files/inputsticker.py deleted file mode 100755 index 1edc51a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/inputsticker.py +++ /dev/null @@ -1,119 +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 InputSticker.""" - -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional, Union - -from telegram._files.sticker import MaskPosition -from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.files import parse_file_input -from telegram._utils.types import FileInput, JSONDict - -if TYPE_CHECKING: - from telegram._files.inputfile import InputFile - - -class InputSticker(TelegramObject): - """ - This object describes a sticker to be added to a sticker set. - - .. versionadded:: 20.2 - - .. versionchanged:: 21.1 - As of Bot API 7.2, the new argument :paramref:`format` is a required argument, and thus the - order of the arguments has changed. - - Args: - sticker (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \ - | :class:`pathlib.Path`): The - added sticker. |uploadinputnopath| Animated and video stickers can't be uploaded via - HTTP URL. - emoji_list (Sequence[:obj:`str`]): Sequence of - :tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI` - - :tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with the - sticker. - mask_position (:class:`telegram.MaskPosition`, optional): Position where the mask should be - placed on faces. For ":tg-const:`telegram.constants.StickerType.MASK`" stickers only. - keywords (Sequence[:obj:`str`], optional): Sequence of - 0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords - for the sticker with the total length of up to - :tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For - ":tg-const:`telegram.constants.StickerType.REGULAR`" and - ":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only. - format (:obj:`str`): Format of the added sticker, must be one of - :tg-const:`telegram.constants.StickerFormat.STATIC` for a - ``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED` - for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM - video. - - .. versionadded:: 21.1 - - Attributes: - sticker (:obj:`str` | :class:`telegram.InputFile`): The added sticker. - emoji_list (tuple[:obj:`str`]): Tuple of - :tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI` - - :tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with the - sticker. - mask_position (:class:`telegram.MaskPosition`): Optional. Position where the mask should be - placed on faces. For ":tg-const:`telegram.constants.StickerType.MASK`" stickers only. - keywords (tuple[:obj:`str`]): Optional. Tuple of - 0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords - for the sticker with the total length of up to - :tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For - ":tg-const:`telegram.constants.StickerType.REGULAR`" and - ":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only. - ":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only. - format (:obj:`str`): Format of the added sticker, must be one of - :tg-const:`telegram.constants.StickerFormat.STATIC` for a - ``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED` - for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM - video. - - .. versionadded:: 21.1 - """ - - __slots__ = ("emoji_list", "format", "keywords", "mask_position", "sticker") - - def __init__( - self, - sticker: FileInput, - emoji_list: Sequence[str], - format: str, # pylint: disable=redefined-builtin - mask_position: Optional[MaskPosition] = None, - keywords: Optional[Sequence[str]] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # We use local_mode=True because we don't have access to the actual setting and want - # things to work in local mode. - self.sticker: Union[str, InputFile] = parse_file_input( - sticker, - local_mode=True, - attach=True, - ) - self.emoji_list: tuple[str, ...] = parse_sequence_arg(emoji_list) - self.format: str = format - self.mask_position: Optional[MaskPosition] = mask_position - self.keywords: tuple[str, ...] = parse_sequence_arg(keywords) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_files/location.py b/venv/lib/python3.11/site-packages/telegram/_files/location.py deleted file mode 100755 index 87c895b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/location.py +++ /dev/null @@ -1,113 +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 Location.""" - -from typing import Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class Location(TelegramObject): - """This object represents a point on the map. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`longitude` and :attr:`latitude` are equal. - - Args: - longitude (:obj:`float`): Longitude as defined by the sender. - latitude (:obj:`float`): Latitude as defined by the sender. - horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, - measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`. - live_period (:obj:`int`, optional): Time relative to the message sending date, during which - the location can be updated, in seconds. For active live locations only. - heading (:obj:`int`, optional): The direction in which user is moving, in degrees; - :tg-const:`telegram.Location.MIN_HEADING`-:tg-const:`telegram.Location.MAX_HEADING`. - For active live locations only. - proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts about - approaching another chat member, in meters. For sent live locations only. - - Attributes: - longitude (:obj:`float`): Longitude as defined by the sender. - latitude (:obj:`float`): Latitude as defined by the sender. - horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, - measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`. - live_period (:obj:`int`): Optional. Time relative to the message sending date, during which - the location can be updated, in seconds. For active live locations only. - heading (:obj:`int`): Optional. The direction in which user is moving, in degrees; - :tg-const:`telegram.Location.MIN_HEADING`-:tg-const:`telegram.Location.MAX_HEADING`. - For active live locations only. - proximity_alert_radius (:obj:`int`): Optional. Maximum distance for proximity alerts about - approaching another chat member, in meters. For sent live locations only. - - """ - - __slots__ = ( - "heading", - "horizontal_accuracy", - "latitude", - "live_period", - "longitude", - "proximity_alert_radius", - ) - - def __init__( - self, - longitude: float, - latitude: float, - horizontal_accuracy: Optional[float] = None, - live_period: Optional[int] = None, - heading: Optional[int] = None, - proximity_alert_radius: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.longitude: float = longitude - self.latitude: float = latitude - - # Optionals - self.horizontal_accuracy: Optional[float] = horizontal_accuracy - self.live_period: Optional[int] = live_period - self.heading: Optional[int] = heading - self.proximity_alert_radius: Optional[int] = ( - int(proximity_alert_radius) if proximity_alert_radius else None - ) - - self._id_attrs = (self.longitude, self.latitude) - - self._freeze() - - HORIZONTAL_ACCURACY: Final[int] = constants.LocationLimit.HORIZONTAL_ACCURACY - """:const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY` - - .. versionadded:: 20.0 - """ - MIN_HEADING: Final[int] = constants.LocationLimit.MIN_HEADING - """:const:`telegram.constants.LocationLimit.MIN_HEADING` - - .. versionadded:: 20.0 - """ - MAX_HEADING: Final[int] = constants.LocationLimit.MAX_HEADING - """:const:`telegram.constants.LocationLimit.MAX_HEADING` - - .. versionadded:: 20.0 - """ diff --git a/venv/lib/python3.11/site-packages/telegram/_files/photosize.py b/venv/lib/python3.11/site-packages/telegram/_files/photosize.py deleted file mode 100755 index e06dc3b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/photosize.py +++ /dev/null @@ -1,77 +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 PhotoSize.""" - -from typing import Optional - -from telegram._files._basemedium import _BaseMedium -from telegram._utils.types import JSONDict - - -class PhotoSize(_BaseMedium): - """This object represents one size of a photo or a file/sticker thumbnail. - - 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. - width (:obj:`int`): Photo width. - height (:obj:`int`): Photo height. - file_size (:obj:`int`, optional): File size in bytes. - - 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. - width (:obj:`int`): Photo width. - height (:obj:`int`): Photo height. - file_size (:obj:`int`): Optional. File size in bytes. - - - """ - - __slots__ = ("height", "width") - - def __init__( - self, - file_id: str, - file_unique_id: str, - width: int, - height: int, - file_size: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - # Required - self.width: int = width - self.height: int = height diff --git a/venv/lib/python3.11/site-packages/telegram/_files/sticker.py b/venv/lib/python3.11/site-packages/telegram/_files/sticker.py deleted file mode 100755 index d5e6d8b..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/sticker.py +++ /dev/null @@ -1,388 +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 represent stickers.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._files._basethumbedmedium import _BaseThumbedMedium -from telegram._files.file import File -from telegram._files.photosize import PhotoSize -from telegram._telegramobject import TelegramObject -from telegram._utils import enum -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class Sticker(_BaseThumbedMedium): - """This object represents a sticker. - - 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. - - Note: - As of v13.11 :paramref:`is_video` is a required argument and therefore the order of the - arguments had to be changed. Use keyword arguments to make sure that the arguments are - passed correctly. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - 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. - width (:obj:`int`): Sticker width. - height (:obj:`int`): Sticker height. - is_animated (:obj:`bool`): :obj:`True`, if the sticker is animated. - is_video (:obj:`bool`): :obj:`True`, if the sticker is a video sticker. - - .. versionadded:: 13.11 - type (:obj:`str`): Type of the sticker. Currently one of :attr:`REGULAR`, - :attr:`MASK`, :attr:`CUSTOM_EMOJI`. The type of the sticker is independent from its - format, which is determined by the fields :attr:`is_animated` and :attr:`is_video`. - - .. versionadded:: 20.0 - emoji (:obj:`str`, optional): Emoji associated with the sticker - set_name (:obj:`str`, optional): Name of the sticker set to which the sticker belongs. - mask_position (:class:`telegram.MaskPosition`, optional): For mask stickers, the position - where the mask should be placed. - file_size (:obj:`int`, optional): File size in bytes. - - premium_animation (:class:`telegram.File`, optional): For premium regular stickers, - premium animation for the sticker. - - .. versionadded:: 20.0 - custom_emoji_id (:obj:`str`, optional): For custom emoji stickers, unique identifier of the - custom emoji. - - .. versionadded:: 20.0 - thumbnail (:class:`telegram.PhotoSize`, optional): Sticker thumbnail in the ``.WEBP`` or - ``.JPG`` format. - - .. versionadded:: 20.2 - needs_repainting (:obj:`bool`, optional): :obj:`True`, if the sticker must be repainted to - a text color in messages, the color of the Telegram Premium badge in emoji status, - white color on chat photos, or another appropriate color in other places. - - .. versionadded:: 20.2 - - 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. - width (:obj:`int`): Sticker width. - height (:obj:`int`): Sticker height. - is_animated (:obj:`bool`): :obj:`True`, if the sticker is animated. - is_video (:obj:`bool`): :obj:`True`, if the sticker is a video sticker. - - .. versionadded:: 13.11 - type (:obj:`str`): Type of the sticker. Currently one of :attr:`REGULAR`, - :attr:`MASK`, :attr:`CUSTOM_EMOJI`. The type of the sticker is independent from its - format, which is determined by the fields :attr:`is_animated` and :attr:`is_video`. - - .. versionadded:: 20.0 - emoji (:obj:`str`): Optional. Emoji associated with the sticker. - set_name (:obj:`str`): Optional. Name of the sticker set to which the sticker belongs. - mask_position (:class:`telegram.MaskPosition`): Optional. For mask stickers, the position - where the mask should be placed. - file_size (:obj:`int`): Optional. File size in bytes. - - premium_animation (:class:`telegram.File`): Optional. For premium regular stickers, - premium animation for the sticker. - - .. versionadded:: 20.0 - custom_emoji_id (:obj:`str`): Optional. For custom emoji stickers, unique identifier of the - custom emoji. - - .. versionadded:: 20.0 - thumbnail (:class:`telegram.PhotoSize`): Optional. Sticker thumbnail in the ``.WEBP`` or - ``.JPG`` format. - - .. versionadded:: 20.2 - needs_repainting (:obj:`bool`): Optional. :obj:`True`, if the sticker must be repainted to - a text color in messages, the color of the Telegram Premium badge in emoji status, - white color on chat photos, or another appropriate color in other places. - - .. versionadded:: 20.2 - """ - - __slots__ = ( - "custom_emoji_id", - "emoji", - "height", - "is_animated", - "is_video", - "mask_position", - "needs_repainting", - "premium_animation", - "set_name", - "type", - "width", - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - width: int, - height: int, - is_animated: bool, - is_video: bool, - type: str, # pylint: disable=redefined-builtin - emoji: Optional[str] = None, - file_size: Optional[int] = None, - set_name: Optional[str] = None, - mask_position: Optional["MaskPosition"] = None, - premium_animation: Optional["File"] = None, - custom_emoji_id: Optional[str] = None, - thumbnail: Optional[PhotoSize] = None, - needs_repainting: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - # Required - self.width: int = width - self.height: int = height - self.is_animated: bool = is_animated - self.is_video: bool = is_video - self.type: str = enum.get_member(constants.StickerType, type, type) - # Optional - self.emoji: Optional[str] = emoji - self.set_name: Optional[str] = set_name - self.mask_position: Optional[MaskPosition] = mask_position - self.premium_animation: Optional[File] = premium_animation - self.custom_emoji_id: Optional[str] = custom_emoji_id - self.needs_repainting: Optional[bool] = needs_repainting - - REGULAR: Final[str] = constants.StickerType.REGULAR - """:const:`telegram.constants.StickerType.REGULAR`""" - MASK: Final[str] = constants.StickerType.MASK - """:const:`telegram.constants.StickerType.MASK`""" - CUSTOM_EMOJI: Final[str] = constants.StickerType.CUSTOM_EMOJI - """:const:`telegram.constants.StickerType.CUSTOM_EMOJI`""" - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Sticker"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot) - data["mask_position"] = MaskPosition.de_json(data.get("mask_position"), bot) - data["premium_animation"] = File.de_json(data.get("premium_animation"), 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 data.get("thumb") is not None: - api_kwargs["thumb"] = data.pop("thumb") - - return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) - - -class StickerSet(TelegramObject): - """This object represents a sticker set. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`name` is equal. - - Note: - As of v13.11 :paramref:`is_video` is a required argument and therefore the order of the - arguments had to be changed. Use keyword arguments to make sure that the arguments are - passed correctly. - - .. versionchanged:: 20.0 - The parameter ``contains_masks`` has been removed. Use :paramref:`sticker_type` instead. - - - .. versionchanged:: 21.1 - The parameters ``is_video`` and ``is_animated`` are deprecated and now made optional. Thus, - the order of the arguments had to be changed. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - .. versionremoved:: 21.2 - Removed the deprecated arguments and attributes ``is_animated`` and ``is_video``. - - Args: - name (:obj:`str`): Sticker set name. - title (:obj:`str`): Sticker set title. - stickers (Sequence[:class:`telegram.Sticker`]): List of all set stickers. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - sticker_type (:obj:`str`): Type of stickers in the set, currently one of - :attr:`telegram.Sticker.REGULAR`, :attr:`telegram.Sticker.MASK`, - :attr:`telegram.Sticker.CUSTOM_EMOJI`. - - .. versionadded:: 20.0 - thumbnail (:class:`telegram.PhotoSize`, optional): Sticker set thumbnail in the ``.WEBP``, - ``.TGS``, or ``.WEBM`` format. - - .. versionadded:: 20.2 - - Attributes: - name (:obj:`str`): Sticker set name. - title (:obj:`str`): Sticker set title. - stickers (tuple[:class:`telegram.Sticker`]): List of all set stickers. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - sticker_type (:obj:`str`): Type of stickers in the set, currently one of - :attr:`telegram.Sticker.REGULAR`, :attr:`telegram.Sticker.MASK`, - :attr:`telegram.Sticker.CUSTOM_EMOJI`. - - .. versionadded:: 20.0 - thumbnail (:class:`telegram.PhotoSize`): Optional. Sticker set thumbnail in the ``.WEBP``, - ``.TGS``, or ``.WEBM`` format. - - .. versionadded:: 20.2 - """ - - __slots__ = ( - "name", - "sticker_type", - "stickers", - "thumbnail", - "title", - ) - - def __init__( - self, - name: str, - title: str, - stickers: Sequence[Sticker], - sticker_type: str, - thumbnail: Optional[PhotoSize] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.name: str = name - self.title: str = title - self.stickers: tuple[Sticker, ...] = parse_sequence_arg(stickers) - self.sticker_type: str = sticker_type - # Optional - self.thumbnail: Optional[PhotoSize] = thumbnail - self._id_attrs = (self.name,) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["StickerSet"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - if not data: - return None - - data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot) - data["stickers"] = Sticker.de_list(data.get("stickers"), bot) - - api_kwargs = {} - # These are deprecated fields that TG still returns for backwards compatibility - # Let's filter them out to speed up the de-json process - for deprecated_field in ("contains_masks", "thumb", "is_animated", "is_video"): - if deprecated_field in data: - api_kwargs[deprecated_field] = data.pop(deprecated_field) - - return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) - - -class MaskPosition(TelegramObject): - """This object describes the position on faces where a mask should be placed by default. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`point`, :attr:`x_shift`, :attr:`y_shift` and, :attr:`scale` - are equal. - - Args: - point (:obj:`str`): The part of the face relative to which the mask should be placed. - One of :attr:`FOREHEAD`, :attr:`EYES`, :attr:`MOUTH`, or :attr:`CHIN`. - x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face - size, from left to right. For example, choosing ``-1.0`` will place mask just to the - left of the default mask position. - y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face - size, from top to bottom. For example, ``1.0`` will place the mask just below the - default mask position. - scale (:obj:`float`): Mask scaling coefficient. For example, ``2.0`` means double size. - - Attributes: - point (:obj:`str`): The part of the face relative to which the mask should be placed. - One of :attr:`FOREHEAD`, :attr:`EYES`, :attr:`MOUTH`, or :attr:`CHIN`. - x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face - size, from left to right. For example, choosing ``-1.0`` will place mask just to the - left of the default mask position. - y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face - size, from top to bottom. For example, ``1.0`` will place the mask just below the - default mask position. - scale (:obj:`float`): Mask scaling coefficient. For example, ``2.0`` means double size. - - """ - - __slots__ = ("point", "scale", "x_shift", "y_shift") - - FOREHEAD: Final[str] = constants.MaskPosition.FOREHEAD - """:const:`telegram.constants.MaskPosition.FOREHEAD`""" - EYES: Final[str] = constants.MaskPosition.EYES - """:const:`telegram.constants.MaskPosition.EYES`""" - MOUTH: Final[str] = constants.MaskPosition.MOUTH - """:const:`telegram.constants.MaskPosition.MOUTH`""" - CHIN: Final[str] = constants.MaskPosition.CHIN - """:const:`telegram.constants.MaskPosition.CHIN`""" - - def __init__( - self, - point: str, - x_shift: float, - y_shift: float, - scale: float, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.point: str = point - self.x_shift: float = x_shift - self.y_shift: float = y_shift - self.scale: float = scale - - self._id_attrs = (self.point, self.x_shift, self.y_shift, self.scale) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_files/venue.py b/venv/lib/python3.11/site-packages/telegram/_files/venue.py deleted file mode 100755 index c169a52..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/venue.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 an object that represents a Telegram Venue.""" - -from typing import TYPE_CHECKING, Optional - -from telegram._files.location import Location -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class Venue(TelegramObject): - """This object represents a venue. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`location` and :attr:`title` are equal. - - Note: - Foursquare details and Google Place details are mutually exclusive. However, this - behaviour is undocumented and might be changed by Telegram. - - Args: - location (:class:`telegram.Location`): Venue location. - title (:obj:`str`): Name of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue. - foursquare_type (:obj:`str`, optional): Foursquare type of the venue. (For example, - "arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".) - google_place_id (:obj:`str`, optional): Google Places identifier of the venue. - google_place_type (:obj:`str`, optional): Google Places type of the venue. (See - `supported types `_.) - - Attributes: - location (:class:`telegram.Location`): Venue location. - title (:obj:`str`): Name of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue. - foursquare_type (:obj:`str`): Optional. Foursquare type of the venue. (For example, - "arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".) - google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. - google_place_type (:obj:`str`): Optional. Google Places type of the venue. (See - `supported types `_.) - - """ - - __slots__ = ( - "address", - "foursquare_id", - "foursquare_type", - "google_place_id", - "google_place_type", - "location", - "title", - ) - - def __init__( - self, - location: Location, - title: str, - address: str, - foursquare_id: Optional[str] = None, - foursquare_type: Optional[str] = None, - google_place_id: Optional[str] = None, - google_place_type: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - # Required - self.location: Location = location - self.title: str = title - self.address: str = address - # Optionals - self.foursquare_id: Optional[str] = foursquare_id - self.foursquare_type: Optional[str] = foursquare_type - self.google_place_id: Optional[str] = google_place_id - self.google_place_type: Optional[str] = google_place_type - - self._id_attrs = (self.location, self.title) - - self._freeze() - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Venue"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["location"] = Location.de_json(data.get("location"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_files/video.py b/venv/lib/python3.11/site-packages/telegram/_files/video.py deleted file mode 100755 index c5ca6f3..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/video.py +++ /dev/null @@ -1,99 +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 Video.""" -from typing import Optional - -from telegram._files._basethumbedmedium import _BaseThumbedMedium -from telegram._files.photosize import PhotoSize -from telegram._utils.types import JSONDict - - -class Video(_BaseThumbedMedium): - """This object represents a video file. - - 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. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - 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. - width (:obj:`int`): Video width as defined by the sender. - height (:obj:`int`): Video height as defined by the sender. - duration (:obj:`int`): Duration of the video in seconds as defined by the sender. - file_name (:obj:`str`, optional): Original filename as defined by the sender. - mime_type (:obj:`str`, optional): MIME type of a file as defined by the sender. - file_size (:obj:`int`, optional): File size in bytes. - thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail. - - .. versionadded:: 20.2 - - 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. - width (:obj:`int`): Video width as defined by the sender. - height (:obj:`int`): Video height as defined by the sender. - duration (:obj:`int`): Duration of the video in seconds as defined by the sender. - file_name (:obj:`str`): Optional. Original filename as defined by the sender. - mime_type (:obj:`str`): Optional. MIME type of a file as defined by the sender. - file_size (:obj:`int`): Optional. File size in bytes. - thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail. - - .. versionadded:: 20.2 - """ - - __slots__ = ("duration", "file_name", "height", "mime_type", "width") - - def __init__( - self, - file_id: str, - file_unique_id: str, - width: int, - height: int, - duration: int, - mime_type: Optional[str] = None, - file_size: Optional[int] = None, - file_name: Optional[str] = None, - thumbnail: Optional[PhotoSize] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - # Required - self.width: int = width - self.height: int = height - self.duration: int = duration - # Optional - self.mime_type: Optional[str] = mime_type - self.file_name: Optional[str] = file_name diff --git a/venv/lib/python3.11/site-packages/telegram/_files/videonote.py b/venv/lib/python3.11/site-packages/telegram/_files/videonote.py deleted file mode 100755 index edb9e55..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/videonote.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 an object that represents a Telegram VideoNote.""" - -from typing import Optional - -from telegram._files._basethumbedmedium import _BaseThumbedMedium -from telegram._files.photosize import PhotoSize -from telegram._utils.types import JSONDict - - -class VideoNote(_BaseThumbedMedium): - """This object represents a video message (available in Telegram apps as of v.4.0). - - 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. - - .. versionchanged:: 20.5 - |removed_thumb_note| - - 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. - length (:obj:`int`): Video width and height (diameter of the video message) as defined - by sender. - duration (:obj:`int`): Duration of the video in seconds as defined by the sender. - file_size (:obj:`int`, optional): File size in bytes. - thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail. - - .. versionadded:: 20.2 - - 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. - length (:obj:`int`): Video width and height (diameter of the video message) as defined - by sender. - duration (:obj:`int`): Duration of the video in seconds as defined by the sender. - file_size (:obj:`int`): Optional. File size in bytes. - thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail. - - .. versionadded:: 20.2 - - """ - - __slots__ = ("duration", "length") - - def __init__( - self, - file_id: str, - file_unique_id: str, - length: int, - duration: int, - file_size: Optional[int] = None, - thumbnail: Optional[PhotoSize] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - thumbnail=thumbnail, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - # Required - self.length: int = length - self.duration: int = duration diff --git a/venv/lib/python3.11/site-packages/telegram/_files/voice.py b/venv/lib/python3.11/site-packages/telegram/_files/voice.py deleted file mode 100755 index 19c0e85..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_files/voice.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 Voice.""" -from typing import Optional - -from telegram._files._basemedium import _BaseMedium -from telegram._utils.types import JSONDict - - -class Voice(_BaseMedium): - """This object represents a voice note. - - 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. - duration (:obj:`int`): Duration of the audio in seconds as defined by the sender. - mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender. - file_size (:obj:`int`, optional): File size in bytes. - - 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. - duration (:obj:`int`): Duration of the audio in seconds as defined by the sender. - mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender. - file_size (:obj:`int`): Optional. File size in bytes. - - """ - - __slots__ = ("duration", "mime_type") - - def __init__( - self, - file_id: str, - file_unique_id: str, - duration: int, - mime_type: Optional[str] = None, - file_size: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__( - file_id=file_id, - file_unique_id=file_unique_id, - file_size=file_size, - api_kwargs=api_kwargs, - ) - with self._unfrozen(): - # Required - self.duration: int = duration - # Optional - self.mime_type: Optional[str] = mime_type diff --git a/venv/lib/python3.11/site-packages/telegram/_forcereply.py b/venv/lib/python3.11/site-packages/telegram/_forcereply.py deleted file mode 100755 index b24b271..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_forcereply.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 an object that represents a Telegram ForceReply.""" - -from typing import Final, Optional - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class ForceReply(TelegramObject): - """ - Upon receiving a message with this object, Telegram clients will display a reply interface to - the user (act as if the user has selected the bot's message and tapped 'Reply'). This can be - extremely useful if you want to create user-friendly step-by-step interfaces without having - to sacrifice `privacy mode `_. 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 :attr:`selective` is equal. - - .. versionchanged:: 20.0 - The (undocumented) argument ``force_reply`` was removed and instead :attr:`force_reply` - is now always set to :obj:`True` as expected by the Bot API. - - Args: - selective (:obj:`bool`, optional): Use this parameter if you want to force reply from - 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. - - input_field_placeholder (:obj:`str`, optional): The placeholder to be shown in the input - field when the reply is active; - :tg-const:`telegram.ForceReply.MIN_INPUT_FIELD_PLACEHOLDER`- - :tg-const:`telegram.ForceReply.MAX_INPUT_FIELD_PLACEHOLDER` - characters. - - .. versionadded:: 13.7 - - Attributes: - force_reply (:obj:`True`): Shows reply interface to the user, as if they manually selected - the bots message and tapped 'Reply'. - selective (:obj:`bool`): Optional. Force reply from 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. - input_field_placeholder (:obj:`str`): Optional. The placeholder to be shown in the input - field when the reply is active; - :tg-const:`telegram.ForceReply.MIN_INPUT_FIELD_PLACEHOLDER`- - :tg-const:`telegram.ForceReply.MAX_INPUT_FIELD_PLACEHOLDER` - characters. - - .. versionadded:: 13.7 - - """ - - __slots__ = ("force_reply", "input_field_placeholder", "selective") - - def __init__( - self, - selective: Optional[bool] = None, - input_field_placeholder: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.force_reply: bool = True - self.selective: Optional[bool] = selective - self.input_field_placeholder: Optional[str] = input_field_placeholder - - self._id_attrs = (self.selective,) - - self._freeze() - - 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/_forumtopic.py b/venv/lib/python3.11/site-packages/telegram/_forumtopic.py deleted file mode 100755 index 81b64e2..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_forumtopic.py +++ /dev/null @@ -1,215 +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 forum topics.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class ForumTopic(TelegramObject): - """ - This object represents a forum topic. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_thread_id`, :attr:`name` and :attr:`icon_color` - are equal. - - .. versionadded:: 20.0 - - Args: - message_thread_id (:obj:`int`): Unique identifier of the forum topic - name (:obj:`str`): Name of the topic - icon_color (:obj:`int`): Color of the topic icon in RGB format - icon_custom_emoji_id (:obj:`str`, optional): Unique identifier of the custom emoji shown - as the topic icon. - - Attributes: - message_thread_id (:obj:`int`): Unique identifier of the forum topic - name (:obj:`str`): Name of the topic - icon_color (:obj:`int`): Color of the topic icon in RGB format - icon_custom_emoji_id (:obj:`str`): Optional. Unique identifier of the custom emoji shown - as the topic icon. - """ - - __slots__ = ("icon_color", "icon_custom_emoji_id", "message_thread_id", "name") - - def __init__( - self, - message_thread_id: int, - name: str, - icon_color: int, - icon_custom_emoji_id: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.message_thread_id: int = message_thread_id - self.name: str = name - self.icon_color: int = icon_color - self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id - - self._id_attrs = (self.message_thread_id, self.name, self.icon_color) - - self._freeze() - - -class ForumTopicCreated(TelegramObject): - """ - This object represents the content of a service message about a new forum topic created in - the chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`name` and :attr:`icon_color` are equal. - - .. versionadded:: 20.0 - - Args: - name (:obj:`str`): Name of the topic - icon_color (:obj:`int`): Color of the topic icon in RGB format - icon_custom_emoji_id (:obj:`str`, optional): Unique identifier of the custom emoji shown - as the topic icon. - - Attributes: - name (:obj:`str`): Name of the topic - icon_color (:obj:`int`): Color of the topic icon in RGB format - icon_custom_emoji_id (:obj:`str`): Optional. Unique identifier of the custom emoji shown - as the topic icon. - """ - - __slots__ = ("icon_color", "icon_custom_emoji_id", "name") - - def __init__( - self, - name: str, - icon_color: int, - icon_custom_emoji_id: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.name: str = name - self.icon_color: int = icon_color - self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id - - self._id_attrs = (self.name, self.icon_color) - - self._freeze() - - -class ForumTopicClosed(TelegramObject): - """ - This object represents a service message about a forum topic closed in the chat. - Currently holds no information. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(api_kwargs=api_kwargs) - - self._freeze() - - -class ForumTopicReopened(TelegramObject): - """ - This object represents a service message about a forum topic reopened in the chat. - Currently holds no information. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(api_kwargs=api_kwargs) - - self._freeze() - - -class ForumTopicEdited(TelegramObject): - """ - This object represents a service message about an edited forum topic. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`name` and :attr:`icon_custom_emoji_id` are equal. - - .. versionadded:: 20.0 - - Args: - name (:obj:`str`, optional): New name of the topic, if it was edited. - icon_custom_emoji_id (:obj:`str`, optional): New identifier of the custom emoji shown as - the topic icon, if it was edited; an empty string if the icon was removed. - - Attributes: - name (:obj:`str`): Optional. New name of the topic, if it was edited. - icon_custom_emoji_id (:obj:`str`): Optional. New identifier of the custom emoji shown as - the topic icon, if it was edited; an empty string if the icon was removed. - """ - - __slots__ = ("icon_custom_emoji_id", "name") - - def __init__( - self, - name: Optional[str] = None, - icon_custom_emoji_id: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.name: Optional[str] = name - self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id - - self._id_attrs = (self.name, self.icon_custom_emoji_id) - - self._freeze() - - -class GeneralForumTopicHidden(TelegramObject): - """ - This object represents a service message about General forum topic hidden in the chat. - Currently holds no information. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - - self._freeze() - - -class GeneralForumTopicUnhidden(TelegramObject): - """ - This object represents a service message about General forum topic unhidden in the chat. - Currently holds no information. - - .. versionadded:: 20.0 - """ - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_games/__init__.py b/venv/lib/python3.11/site-packages/telegram/_games/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index a2d2c348229d4516b79ff209e5f72d3fb39007a3..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 zIjQMIiMjgm>4~{OetdjpUS>&ryk0@&FAkgB{FKt1RJ$TppdBDr6!Qa#56p~=j2{?a JL=iJk3;wqH6(WZ!YekaqqLH57dp~`=-_x7t z3k&lI+V9`}aOZ3tp+BurHL%OJzXH=U#8HSi<~50vT3EwYcchcJp}xP(UqI4-Rp5=qFEf} zbinQ^n2&&;Kp_T>HI74v*Fu*&-2D;rx~PlB>4TlT!JVGFg?gBK4_l$Ph1PNCTUJH$ zXlxr_Tp_t+kr-r>3-u9+hDre$IU?4hNt%&3?PV%qHuMhpQVVi5GdGwS2t`arv@m3t zlTkKQq;J{2MBSITm}hxR?|#ixUn~1|MMDWQRB41~G1}Rt+>U(%;(PoInF`iIRQ5s36HKp1{PRQn)uYy6Ah#+Aq%7T@wpDhI}&x89Sy&uSUEyzb^ zkflqV^XCH{8}V@tb;0^V2WD0+0kw(KK{P9xGL892wcvt{lSiMcQ$F!qCq-~6Wer1`k@w6#@!`>+MI=Pb<>?gX0iluj!g z^d_bEhD^>7k5ZmR;0DfGW(GJb%URi)EQ2c+X4!~@l$5rydLJNdALCPX!mjcvamE4z z5D;+ny>@Sp-P@D*PHcWQxp;XGIrUSAVtepn{nfb(rQ_%8hyHif)Cbko-L|hzfl)Nf zD38;ANupS+vfrVVHvO%YYuBEvoEmAZ~RZDS-hmqf@w3L z*Fo$#7~{Qj2zT)qeLg{F#>e{vEsc-&*XYCX@xIsaF(l^y;@eAqTkk(_fy&7K19`Vq ArvLx| diff --git a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/game.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/game.cpython-311.pyc deleted file mode 100755 index f2cb20c3be7078b712b7a0a01b601edc0e549858..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9357 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_games/callbackgame.py b/venv/lib/python3.11/site-packages/telegram/_games/callbackgame.py deleted file mode 100755 index 0917a11..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_games/callbackgame.py +++ /dev/null @@ -1,35 +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 CallbackGame.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class CallbackGame(TelegramObject): - """A placeholder, currently holds no information. Use BotFather to set up your game.""" - - __slots__ = () - - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: - super().__init__(api_kwargs=api_kwargs) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_games/game.py b/venv/lib/python3.11/site-packages/telegram/_games/game.py deleted file mode 100755 index ab74276..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_games/game.py +++ /dev/null @@ -1,197 +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 Game.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._files.animation import Animation -from telegram._files.photosize import PhotoSize -from telegram._messageentity import MessageEntity -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 - -if TYPE_CHECKING: - from telegram import Bot - - -class Game(TelegramObject): - """ - This object represents a game. Use `BotFather `_ to create and edit - games, their short names will act as unique identifiers. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`title`, :attr:`description` and :attr:`photo` are equal. - - Args: - title (:obj:`str`): Title of the game. - description (:obj:`str`): Description of the game. - photo (Sequence[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game - message in chats. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - text (:obj:`str`, optional): Brief description of the game or high scores included in the - game message. Can be automatically edited to include current high scores for the game - when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited - using :meth:`telegram.Bot.edit_message_text`. - 0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters. - text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that - appear in text, such as usernames, URLs, bot commands, etc. - - .. versionchanged:: 20.0 - |sequenceclassargs| - - animation (:class:`telegram.Animation`, optional): Animation that will be displayed in the - game message in chats. Upload via `BotFather `_. - - Attributes: - title (:obj:`str`): Title of the game. - description (:obj:`str`): Description of the game. - photo (tuple[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game - message in chats. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - text (:obj:`str`): Optional. Brief description of the game or high scores included in the - game message. Can be automatically edited to include current high scores for the game - when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited - using :meth:`telegram.Bot.edit_message_text`. - 0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters. - text_entities (tuple[:class:`telegram.MessageEntity`]): Optional. Special entities that - appear in text, such as usernames, URLs, bot commands, etc. - This tuple is empty if the message does not contain text entities. - - .. versionchanged:: 20.0 - |tupleclassattrs| - - animation (:class:`telegram.Animation`): Optional. Animation that will be displayed in the - game message in chats. Upload via `BotFather `_. - - """ - - __slots__ = ( - "animation", - "description", - "photo", - "text", - "text_entities", - "title", - ) - - def __init__( - self, - title: str, - description: str, - photo: Sequence[PhotoSize], - text: Optional[str] = None, - text_entities: Optional[Sequence[MessageEntity]] = None, - animation: Optional[Animation] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.title: str = title - self.description: str = description - self.photo: tuple[PhotoSize, ...] = parse_sequence_arg(photo) - # Optionals - self.text: Optional[str] = text - self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities) - self.animation: Optional[Animation] = animation - - self._id_attrs = (self.title, self.description, self.photo) - - self._freeze() - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Game"]: - """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) - data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot) - data["animation"] = Animation.de_json(data.get("animation"), bot) - - return super().de_json(data=data, bot=bot) - - def parse_text_entity(self, entity: MessageEntity) -> str: - """Returns the text from a given :class:`telegram.MessageEntity`. - - 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 this message. - - Returns: - :obj:`str`: The text of the given entity. - - Raises: - RuntimeError: If this game has no text. - - """ - if not self.text: - raise RuntimeError("This Game has no 'text'.") - - entity_text = self.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_text_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 message filtered by their - :attr:`~telegram.MessageEntity.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_text_entity` for more info. - - Args: - types (list[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as - strings. If the :attr:`~telegram.MessageEntity.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: self.parse_text_entity(entity) - for entity in self.text_entities - if entity.type in types - } diff --git a/venv/lib/python3.11/site-packages/telegram/_games/gamehighscore.py b/venv/lib/python3.11/site-packages/telegram/_games/gamehighscore.py deleted file mode 100755 index ad3dbd7..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_games/gamehighscore.py +++ /dev/null @@ -1,75 +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 GameHighScore.""" - -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 GameHighScore(TelegramObject): - """This object represents one row of the high scores table for a game. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`position`, :attr:`user` and :attr:`score` are equal. - - Args: - position (:obj:`int`): Position in high score table for the game. - user (:class:`telegram.User`): User. - score (:obj:`int`): Score. - - Attributes: - position (:obj:`int`): Position in high score table for the game. - user (:class:`telegram.User`): User. - score (:obj:`int`): Score. - - """ - - __slots__ = ("position", "score", "user") - - def __init__( - self, position: int, user: User, score: int, *, api_kwargs: Optional[JSONDict] = None - ): - super().__init__(api_kwargs=api_kwargs) - self.position: int = position - self.user: User = user - self.score: int = score - - self._id_attrs = (self.position, self.user, self.score) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["GameHighScore"]: - """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) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_gifts.py b/venv/lib/python3.11/site-packages/telegram/_gifts.py deleted file mode 100755 index d711320..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_gifts.py +++ /dev/null @@ -1,153 +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 classes related to gifs sent by bots.""" -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._files.sticker import Sticker -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 - - -class Gift(TelegramObject): - """This object represents a gift that can be sent by the 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. - - .. versionadded:: 21.8 - - Args: - id (:obj:`str`): Unique identifier of the gift - sticker (:class:`~telegram.Sticker`): The sticker that represents the gift - star_count (:obj:`int`): The number of Telegram Stars that must be paid to send the sticker - total_count (:obj:`int`, optional): The total number of the gifts of this type that can be - sent; for limited gifts only - remaining_count (:obj:`int`, optional): The number of remaining gifts of this type that can - be sent; for limited gifts only - upgrade_star_count (:obj:`int`, optional): The number of Telegram Stars that must be paid - to upgrade the gift to a unique one - - .. versionadded:: 21.10 - - Attributes: - id (:obj:`str`): Unique identifier of the gift - sticker (:class:`~telegram.Sticker`): The sticker that represents the gift - star_count (:obj:`int`): The number of Telegram Stars that must be paid to send the sticker - total_count (:obj:`int`): Optional. The total number of the gifts of this type that can be - sent; for limited gifts only - remaining_count (:obj:`int`): Optional. The number of remaining gifts of this type that can - be sent; for limited gifts only - upgrade_star_count (:obj:`int`): Optional. The number of Telegram Stars that must be paid - to upgrade the gift to a unique one - - .. versionadded:: 21.10 - - """ - - __slots__ = ( - "id", - "remaining_count", - "star_count", - "sticker", - "total_count", - "upgrade_star_count", - ) - - def __init__( - self, - id: str, - sticker: Sticker, - star_count: int, - total_count: Optional[int] = None, - remaining_count: Optional[int] = None, - upgrade_star_count: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.id: str = id - self.sticker: Sticker = sticker - self.star_count: int = star_count - self.total_count: Optional[int] = total_count - self.remaining_count: Optional[int] = remaining_count - self.upgrade_star_count: Optional[int] = upgrade_star_count - - self._id_attrs = (self.id,) - - self._freeze() - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gift"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["sticker"] = Sticker.de_json(data.get("sticker"), bot) - return super().de_json(data=data, bot=bot) - - -class Gifts(TelegramObject): - """This object represent a list of gifts. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal if their :attr:`gifts` are equal. - - .. versionadded:: 21.8 - - Args: - gifts (Sequence[:class:`Gift`]): The sequence of gifts - - Attributes: - gifts (tuple[:class:`Gift`]): The sequence of gifts - - """ - - __slots__ = ("gifts",) - - def __init__( - self, - gifts: Sequence[Gift], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.gifts: tuple[Gift, ...] = parse_sequence_arg(gifts) - - self._id_attrs = (self.gifts,) - - self._freeze() - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gifts"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["gifts"] = Gift.de_list(data.get("gifts"), bot) - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_giveaway.py b/venv/lib/python3.11/site-packages/telegram/_giveaway.py deleted file mode 100755 index 67c6b23..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_giveaway.py +++ /dev/null @@ -1,393 +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 objects that are related to Telegram giveaways.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._chat import Chat -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, Message - - -class Giveaway(TelegramObject): - """This object represents a message about a scheduled giveaway. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`chats`, :attr:`winners_selection_date` and - :attr:`winner_count` are equal. - - .. versionadded:: 20.8 - - Args: - chats (tuple[:class:`telegram.Chat`]): The list of chats which the user must join to - participate in the giveaway. - winners_selection_date (:class:`datetime.datetime`): The date when the giveaway winner will - be selected. |datetime_localization| - winner_count (:obj:`int`): The number of users which are supposed to be selected as winners - of the giveaway. - only_new_members (:obj:`True`, optional): If :obj:`True`, only users who join the chats - after the giveaway started should be eligible to win. - has_public_winners (:obj:`True`, optional): :obj:`True`, if the list of giveaway winners - will be visible to everyone - prize_description (:obj:`str`, optional): Description of additional giveaway prize - country_codes (Sequence[:obj:`str`]): A list of two-letter ISO 3166-1 alpha-2 - country codes indicating the countries from which eligible users for the giveaway must - come. If empty, then all users can participate in the giveaway. Users with a phone - number that was bought on Fragment can always participate in giveaways. - prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between - giveaway winners; for Telegram Star giveaways only. - - .. versionadded:: 21.6 - premium_subscription_month_count (:obj:`int`, optional): The number of months the Telegram - Premium subscription won from the giveaway will be active for; for Telegram Premium - giveaways only. - - Attributes: - chats (Sequence[:class:`telegram.Chat`]): The list of chats which the user must join to - participate in the giveaway. - winners_selection_date (:class:`datetime.datetime`): The date when the giveaway winner will - be selected. |datetime_localization| - winner_count (:obj:`int`): The number of users which are supposed to be selected as winners - of the giveaway. - only_new_members (:obj:`True`): Optional. If :obj:`True`, only users who join the chats - after the giveaway started should be eligible to win. - has_public_winners (:obj:`True`): Optional. :obj:`True`, if the list of giveaway winners - will be visible to everyone - prize_description (:obj:`str`): Optional. Description of additional giveaway prize - country_codes (tuple[:obj:`str`]): Optional. A tuple of two-letter ISO 3166-1 alpha-2 - country codes indicating the countries from which eligible users for the giveaway must - come. If empty, then all users can participate in the giveaway. Users with a phone - number that was bought on Fragment can always participate in giveaways. - prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between - giveaway winners; for Telegram Star giveaways only. - - .. versionadded:: 21.6 - premium_subscription_month_count (:obj:`int`): Optional. The number of months the Telegram - Premium subscription won from the giveaway will be active for; for Telegram Premium - giveaways only. - """ - - __slots__ = ( - "chats", - "country_codes", - "has_public_winners", - "only_new_members", - "premium_subscription_month_count", - "prize_description", - "prize_star_count", - "winner_count", - "winners_selection_date", - ) - - def __init__( - self, - chats: Sequence[Chat], - winners_selection_date: dtm.datetime, - winner_count: int, - only_new_members: Optional[bool] = None, - has_public_winners: Optional[bool] = None, - prize_description: Optional[str] = None, - country_codes: Optional[Sequence[str]] = None, - premium_subscription_month_count: Optional[int] = None, - prize_star_count: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.chats: tuple[Chat, ...] = tuple(chats) - self.winners_selection_date: dtm.datetime = winners_selection_date - self.winner_count: int = winner_count - self.only_new_members: Optional[bool] = only_new_members - self.has_public_winners: Optional[bool] = has_public_winners - self.prize_description: Optional[str] = prize_description - self.country_codes: tuple[str, ...] = parse_sequence_arg(country_codes) - self.premium_subscription_month_count: Optional[int] = premium_subscription_month_count - self.prize_star_count: Optional[int] = prize_star_count - - self._id_attrs = ( - self.chats, - self.winners_selection_date, - self.winner_count, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["Giveaway"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["chats"] = tuple(Chat.de_list(data.get("chats"), bot)) - data["winners_selection_date"] = from_timestamp( - data.get("winners_selection_date"), tzinfo=loc_tzinfo - ) - - return super().de_json(data=data, bot=bot) - - -class GiveawayCreated(TelegramObject): - """This object represents a service message about the creation of a scheduled giveaway. - - Args: - prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be - split between giveaway winners; for Telegram Star giveaways only. - - .. versionadded:: 21.6 - - Attributes: - prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be - split between giveaway winners; for Telegram Star giveaways only. - - .. versionadded:: 21.6 - - """ - - __slots__ = ("prize_star_count",) - - def __init__( - self, prize_star_count: Optional[int] = None, *, api_kwargs: Optional[JSONDict] = None - ): - super().__init__(api_kwargs=api_kwargs) - self.prize_star_count: Optional[int] = prize_star_count - - self._freeze() - - -class GiveawayWinners(TelegramObject): - """This object represents a message about the completion of a giveaway with public winners. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`chat`, :attr:`giveaway_message_id`, - :attr:`winners_selection_date`, :attr:`winner_count` and :attr:`winners` are equal. - - .. versionadded:: 20.8 - - Args: - chat (:class:`telegram.Chat`): The chat that created the giveaway - giveaway_message_id (:obj:`int`): Identifier of the message with the giveaway in the chat - winners_selection_date (:class:`datetime.datetime`): Point in time when winners of the - giveaway were selected. |datetime_localization| - winner_count (:obj:`int`): Total number of winners in the giveaway - winners (Sequence[:class:`telegram.User`]): List of up to - :tg-const:`telegram.constants.GiveawayLimit.MAX_WINNERS` winners of the giveaway - prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between - giveaway winners; for Telegram Star giveaways only. - - .. versionadded:: 21.6 - additional_chat_count (:obj:`int`, optional): The number of other chats the user had to - join in order to be eligible for the giveaway - premium_subscription_month_count (:obj:`int`, optional): The number of months the Telegram - Premium subscription won from the giveaway will be active for - unclaimed_prize_count (:obj:`int`, optional): Number of undistributed prizes - only_new_members (:obj:`True`, optional): :obj:`True`, if only users who had joined the - chats after the giveaway started were eligible to win - was_refunded (:obj:`True`, optional): :obj:`True`, if the giveaway was canceled because the - payment for it was refunded - prize_description (:obj:`str`, optional): Description of additional giveaway prize - - Attributes: - chat (:class:`telegram.Chat`): The chat that created the giveaway - giveaway_message_id (:obj:`int`): Identifier of the message with the giveaway in the chat - winners_selection_date (:class:`datetime.datetime`): Point in time when winners of the - giveaway were selected. |datetime_localization| - winner_count (:obj:`int`): Total number of winners in the giveaway - winners (tuple[:class:`telegram.User`]): tuple of up to - :tg-const:`telegram.constants.GiveawayLimit.MAX_WINNERS` winners of the giveaway - additional_chat_count (:obj:`int`): Optional. The number of other chats the user had to - join in order to be eligible for the giveaway - prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between - giveaway winners; for Telegram Star giveaways only. - - .. versionadded:: 21.6 - premium_subscription_month_count (:obj:`int`): Optional. The number of months the Telegram - Premium subscription won from the giveaway will be active for - unclaimed_prize_count (:obj:`int`): Optional. Number of undistributed prizes - only_new_members (:obj:`True`): Optional. :obj:`True`, if only users who had joined the - chats after the giveaway started were eligible to win - was_refunded (:obj:`True`): Optional. :obj:`True`, if the giveaway was canceled because the - payment for it was refunded - prize_description (:obj:`str`): Optional. Description of additional giveaway prize - """ - - __slots__ = ( - "additional_chat_count", - "chat", - "giveaway_message_id", - "only_new_members", - "premium_subscription_month_count", - "prize_description", - "prize_star_count", - "unclaimed_prize_count", - "was_refunded", - "winner_count", - "winners", - "winners_selection_date", - ) - - def __init__( - self, - chat: Chat, - giveaway_message_id: int, - winners_selection_date: dtm.datetime, - winner_count: int, - winners: Sequence[User], - additional_chat_count: Optional[int] = None, - premium_subscription_month_count: Optional[int] = None, - unclaimed_prize_count: Optional[int] = None, - only_new_members: Optional[bool] = None, - was_refunded: Optional[bool] = None, - prize_description: Optional[str] = None, - prize_star_count: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.chat: Chat = chat - self.giveaway_message_id: int = giveaway_message_id - self.winners_selection_date: dtm.datetime = winners_selection_date - self.winner_count: int = winner_count - self.winners: tuple[User, ...] = tuple(winners) - self.additional_chat_count: Optional[int] = additional_chat_count - self.premium_subscription_month_count: Optional[int] = premium_subscription_month_count - self.unclaimed_prize_count: Optional[int] = unclaimed_prize_count - self.only_new_members: Optional[bool] = only_new_members - self.was_refunded: Optional[bool] = was_refunded - self.prize_description: Optional[str] = prize_description - self.prize_star_count: Optional[int] = prize_star_count - - self._id_attrs = ( - self.chat, - self.giveaway_message_id, - self.winners_selection_date, - self.winner_count, - self.winners, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["GiveawayWinners"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["chat"] = Chat.de_json(data.get("chat"), bot) - data["winners"] = tuple(User.de_list(data.get("winners"), bot)) - data["winners_selection_date"] = from_timestamp( - data.get("winners_selection_date"), tzinfo=loc_tzinfo - ) - - return super().de_json(data=data, bot=bot) - - -class GiveawayCompleted(TelegramObject): - """This object represents a service message about the completion of a giveaway without public - winners. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`winner_count` and :attr:`unclaimed_prize_count` are equal. - - .. versionadded:: 20.8 - - - Args: - winner_count (:obj:`int`): Number of winners in the giveaway - unclaimed_prize_count (:obj:`int`, optional): Number of undistributed prizes - giveaway_message (:class:`telegram.Message`, optional): Message with the giveaway that was - completed, if it wasn't deleted - is_star_giveaway (:obj:`bool`, optional): :obj:`True`, if the giveaway is a Telegram Star - giveaway. Otherwise, currently, the giveaway is a Telegram Premium giveaway. - - .. versionadded:: 21.6 - Attributes: - winner_count (:obj:`int`): Number of winners in the giveaway - unclaimed_prize_count (:obj:`int`): Optional. Number of undistributed prizes - giveaway_message (:class:`telegram.Message`): Optional. Message with the giveaway that was - completed, if it wasn't deleted - is_star_giveaway (:obj:`bool`): Optional. :obj:`True`, if the giveaway is a Telegram Star - giveaway. Otherwise, currently, the giveaway is a Telegram Premium giveaway. - - .. versionadded:: 21.6 - """ - - __slots__ = ("giveaway_message", "is_star_giveaway", "unclaimed_prize_count", "winner_count") - - def __init__( - self, - winner_count: int, - unclaimed_prize_count: Optional[int] = None, - giveaway_message: Optional["Message"] = None, - is_star_giveaway: Optional[bool] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - - self.winner_count: int = winner_count - self.unclaimed_prize_count: Optional[int] = unclaimed_prize_count - self.giveaway_message: Optional[Message] = giveaway_message - self.is_star_giveaway: Optional[bool] = is_star_giveaway - - self._id_attrs = ( - self.winner_count, - self.unclaimed_prize_count, - ) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["GiveawayCompleted"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - # Unfortunately, this needs to be here due to cyclic imports - from telegram._message import Message # pylint: disable=import-outside-toplevel - - data["giveaway_message"] = Message.de_json(data.get("giveaway_message"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__init__.py b/venv/lib/python3.11/site-packages/telegram/_inline/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index bc12d0cd4719a9bbc8db98071786933cfba99846..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 193 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 M%6h&$pr1MP-_-Q~TmS$7 diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequery.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequery.cpython-311.pyc deleted file mode 100755 index 3a8e20973e2c4071fd28def369e93817ccfc4600..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9499 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 CM+_JM diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultarticle.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultarticle.cpython-311.pyc deleted file mode 100755 index e6a7e7f5a7fcd6279c9e87efbb945bab893657fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5897 zcmeGgOK%&;d6sWdqNum!xUyCjY=^EzT9TbMgzHAH+H!2gm1)!_kStf+k+}A9mziB! zroa|15TI^gv^}_pQTQPA;37zVK#y&XJu!ufZWjn(pr_o{umc!5^_$sUk}Fw4l0MKw zhRd1xW@hJme>30yA(>1dDF1lyyPLm1fY3iF;FYl3dG;&le1IfWKoTbf6s{5|1S-Ko zkfU%=301;{FzbhuNF`c`vVK^JRpNy>>qnGCrK`}z`cb93k}M=yKc@6lQiT+UaDYT$ zuej1%=_~YcD1go*De)eXx^VPy5TTFY@03En)O{7Dlbb8~vaItJO{yuFFKMbF%Bs#A zWdIaW*D>vj22XI6U>&OlpT`PbCt`(PQWaUnKdxa?U%`4!F=mM&mlT}&oT5kvtYrSi zl|^Cx!s7g!OUvi2*jrUY)>KhRbJn2q@|(E6s)2jy^Rpa9^h~X z+y!u~1Mc22pWFfW037dFpV|TU0-R{iuMOWrYn;^gUaHV_58dGkRL29>$Sz^IsuG`p z*)jvrR&U}`hnjU>{0f>*BzP!`cf?9n!FrBCbR;LL^<2@x%Fk&Ae-^uIGBUH8Rn0h8 zbl%Qn_}iH1psP|@RM)YT%kk5vGH2Y)R&YhTjU{H0lB-t$MY3M2fChn16(GYP@@mZh zYb_Rya;>r|oG2DE4uV;--a(oy@vr89+gwpMNHLw`uc`98HO$Kr>?W_tnDA>F0d(LM zVDVtqCtGYW){ON@a1-6g6%E%DGP}f^xxBP2EG-C^7MIWGFBB)g$quvEJ9gmb>cCv4 zwT~ei;I4i~@@!07W1@0MZ@(Z@;}OzHi_e+t{2;vU{#gn||#fh97WB6NcoS=#pOJywi&>9+J*(Iut zy+)Ky5&1U0wsOg1W~ZpiUQT2}o;`zFCB+O|&pVJb6q%C~}wn>lXF^!W{0Q7A6rdJJG#s~I(d zc?gM~kLeknQ7@`Iu2hXW4_*NAkr#DJ?Jg8>78qER+A@`}ULrD6(4MlrTGogG476A7 zVU)~MRZ&(t#ZBGPuPRWZyFu#(*GDO{)J0uSr$V8n9a2O|@&d|qi@DY=!iFpvWseV8 zHT;P4G>}m8K(w&#n<6P=dA&@1jYXY(us9398XCsTY%A=wL$3kHpohziaJiR+EEdAR zPW9cviyowz*_Hg#{G~;Rp^iv-2#`Cr{Wfsw|5t$%!nAk8%KS$Ir*Gr08#sM0e;YXI zopgsEwUzeo2Tq@~ul)}Lrw{ReEpYCE$$>k3@D$(+?B{BpV2kE6%7p?keHB74% zt$JuRK&wGo_0wtusuEpH3kUxw{AqUg>}LS|miqu1bkr@6q5a4M&{oGxYY-WscK>E8 zPi%0Fu8%o??#Q7A+Ui){e$S8R3=q}`G?3tBz^D-fDB`VegaD#+v(g9y6l+0|pN|=o zXSWzsL~fA+Qt)vAID)@Zq|nD<{|I1?zDP$LRZx3|6#11Q;o;s8-0v(iWaMCHzk z1o^szcJ3{qt7rmEAw9GaxD&jAHaHI50B#{0hnaL_nZQQ?v>9giw#`x=?t)&z!WTVT zEAD?|bCaU|FKoPbLHnG_0|fiYzP90!zwH49`06L zsHtm2+r(;z1-6ZkDudAP8he^yI%$P;tgI25g1&T*eGM205Lf~t2s+h7>Cqe&w6=T7PzJf zM%HN{%OiE?z9_n1DynsI81Qb6@5 z^0$MT?SrrVG4Q9&W^Cls*vfWnr5Rf>lYPH_=lyp+O^$9SM{P71U*MeDJUnr4;r>PQ z+|_#v+ug_P2%63lBQT}YAovEEpsT3uv5HNMJ6gVroSz-|VK`LY;+errYpn*dVPd~`mDF*hU;lmG058k%>7}$?S_^sfBpV|Wq97L}i z*_wDXY7a4R7#*6}nt3$YB5-K*;q~poW4o!eJ1E}2{|rRt$ZR=1K#l`oMIiNnRFcrM zgQ>(i>Um)Bl)grs;p41bc17ag%1~ cWYhoH5uM{`Y}&hNj-7hyOh4ae6%)(90QbRrdH?_b diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultaudio.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultaudio.cpython-311.pyc deleted file mode 100755 index 6e39d530245183bceaff22c66061a8a982552b56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5736 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 Tdikq0e)?;7_?uU7aRdGnNxk&= diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcacheddocument.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcacheddocument.cpython-311.pyc deleted file mode 100755 index 40ac907fc197b238e87f9a19495e6b36b2ccabc7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5741 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 diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedgif.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedgif.cpython-311.pyc deleted file mode 100755 index 7a6e7e3832496573e8c35a5ae188f98089875168..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5875 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 vox1~IS@%DU2O0Jz3a}b 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 Fe**kuFFODL diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcontact.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcontact.cpython-311.pyc deleted file mode 100755 index 3cc469a31a78bd71a5f5e3f9ae5cb6c9d0506512..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5394 zcmeGgO>Y~=b(Y_xNPXCnB|C96u^LBAEmF4f0kCmknsRM9Hr>ifVH0RpOYTryd%4T( z4yDjw03QO>EesS0T*L@`(8)!R{(v6a9DAY*6=nBipr_t8aEcl^_08-q$rUBT3D6V; zI^w>0Z|2RsH}gJbM!!v^5(vuQ?tOOSvnhoB&IqrBUF69oAfF-`m5?mR0ad66N`ZQ? z6ciX8R73S}Da`SZ8mUK1QI3bzSUp~fb3CFZ>LaBQ0g-?afiY1vSx=Qx0t%q>NREAs zBi%89EeJ#uSxt)`f`uFFl8;EJwMNzqJ9Ye1-yX%dD@6dR;r5R+&W zuMw4O7*ZXtXsV)-pEilnS|w&vr3E&+LNothBGLgXwRZg{=fuK=bA@+Tis!A^l?GLG zO;Xc>HR%j~m$b^dWXP8#<7Tq~?GrWc+vTXm9MEi#ic(dG%q6%ZFt{frl8p7LPAjx$X=PtD@Ac- zS-fQtR?2d_6H`6YGud8L zf(~Br?-zlLofRHhnxv>=(@^)d;d{{M#&BT69TxOhA5nJ zo-8*JJ==MQatu2sGleU~wR~Z1eZYr&QTG4*)=%{P{Pf)U4Ytp_-}aI6t@B$tZYBD+3TtZ5W6X;8ZV*;-@cLpU2M=9q zyr1?RMXXf61t-0Hc-D2K1GzZy5%9%Uw8!C9_Z;cA{y%BH`q+P zw1xJ_?*#u7PC#w6J;3epBIK9z1}N4Jw2|mNI8i$Y6w{QKb_l3wkBR~n>rr8#*y?#{ zM}XoFT1K{GKzVCN?Kn_u?|5k^fMQ$6iwuuj89fZZ>fv(=JY3OLG>1+iGqe@>FnAqp z2?Dwfx;j1SK+%8~GfIzIVYAsFh7}VYim*Tx@DpL%&6|-3H_q>s!%p zyL8G5nMAD`(=glak^MpYSslcR{JJNKCR?a?Nn!QvZ{%!EuahiX3@du}qQ0RoWu-$*ieRve1w!H{soCX1zB;7S_t1*IB267l+YuE=3jh!P96N zM?mhamxoSz_u$HS`&9)t^Irg--bVk#C_ehj=-udFV>5q_&HUwXX6NvmzYqN3Rwp*| zD7Ly2TkXVFyQzs^zyGWEAEl1&q>kEXB)%*-u=~o%JIg!CqusfMJIi;k*b%hwCLqP` zJfkmm&s=i4FZ`U<$GeNCS^ZM?RG!tiyHsHH%l34CN@wD)xR9?0L=B4F4}bdf>3&^< z?Iw%YKZf$?>_qU(iO|`p=$A7Bz;v|elys6g7kj^mqLmOu=f5F+^?GFjZ8F=iPT3m*4olV8GHK0Fqr5F z0`vurqCR|_9J9lmjG*Zwc9f$rG&N(#IhsI|FWxWQJ8h3}GKr>VJF`nWhhDc+ykQjK z`Of_5o!NKnG2Sqa#%Jya?|x)YaPk0}!P~)mAK3>vIf;%O+n#%H)SlwxA@suB_R@oe zo{CdP?_b-QJU*}|*2-Z2(|WX@qe0$>LPL9mY_;kwX4*B+zSI(z*dqaSztzb-n{@&CF*1H0(; nj{o;KIBp|BSm=gMbo@U%QWgZ30QRpsvx{Fj-CsY0i!b@#1WW+K diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultdocument.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultdocument.cpython-311.pyc deleted file mode 100755 index e2fe813b27018e84e5302b9cf459a5eab920e151..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7055 zcmeHM-)|Jh9iP2B`+oS&zm1K-c(DWF0G|yGqP-Bn*al4OgJ9FbRb;)s9ovidb}zGg zCWo#PQX-X9k@`XvRPn$QZA$-uzBW&NJStb+u2c!BPkp=Z$qB6j9ePEsF+EaEV|Ys|LS>6}(2oB0r}p zvWnj;V^X<_^|E5jXoYeSSpGsqq&X|Lh(9P}wSdzhE46gv%B(Pbad!IMx!eUScDZE8 znkp*5)@u*+F0QO-B9RtEvQaKUeb+VtP?=i5x-PEaS=Eq@3RHBLM51FscSH#yS%cc- z%^1BV&;JgEAHj}el;>dALlTz{OQC#33fq6U#VxJIp%i(@NiDclYK31EelhsPF_dN9_nDct}@W0O`EQ18_EYLxa+)tl$iPuEI-rRRjzj z1-JnoX*GXaRup~(^9*(?6$Z+(jtMjv>%6G)ngb#xpdd0T!%ry&CaP%2n^>tF4t(+!X5ZD3}pqFq#UX`)L%mjMyU?~O` zC0<))y4iD?E)xQcRJ5il6+Uxi<~%4X@tOSG6*e)Q>Eld{4PDk{bIy&^pFiPcM6; zZepT?{T0?lbqz}}`01lR|u0G27Jnt`kK7*k|T&w3qX zi9eLpR&HgNb%QLYv-~wx2Gi$d308ux8R1toVowm<2;FC|FBO!i79tBVroX8TZvz5o-1*z_h9uDUG zePGvJ*Ouj{ZA`iVksJp}k>+fFa2+Pbc3KIxGNNke8OI~d%SGA9Oix`|n!B8H*Mo=6 zBw_)uuX{71Yb&lo6;JoUkO3>yT>^X>bFlp<1c1QQ1JkHBc&gsm&fEoW>vfeq}0)(KA$n+;Iw#sDTA;(+cO$z6J(Oceii0amB@ zO;G^^U%NW*pcLC~$&*l&i&!uqG&J>GfO?+QJ08GsCGLJxhj5g~V2ZE)(!0t|QL(nw>EB&-*R%y8vbA+U~%>l!h@jW#$PrJ6wtpWeTZJKC#|Ss@>XZ_fzxX9 zotmtq-z2TR9nULP+&dCliN@jBO8U=MR%auu+X`E$Mh%=pt&RrC;5MdWy9|vP62}et_(y*)E!O(X5AN12pTS8GLCY(oeH)nhnwn?x_%=-}hu6WChAX z69>Om_=Vy3{4P*GR1~O`N5z10R}59#fa>ttl0bEOR0=4%B`isB{U@QvA&?0_JHa&_T12Dh7}6uR zLm!53pxYdWZoqu)mUJjbhJZEQZMEp-5++tm5M)(01c6Y6teAWHvEo8mT_xHbtnLU3 z1^~JaHVT?B5(GuM(~9U=Stay3Ysb-=y1x=#pqaozpdjdUX{g=#(%rA|__|iaZmloo zZ}i^GrQz?>3e^Ds3Fo8{3TQ3E1xQUwO&?!@#4kHn*8-T-TdD~rbf<9 zhQFAMoI4r)BFjMzr~z=QB774IRzeW$yJILP1>u9Ts5mWAL4aL>YJi2VXoe0@rWfc| z819G&wQxcWn^5Z`)O`?Y%T^dZdI+^owvSfI!Bhb&iXfypauAwyYRhNIo0N+pjb)>> zA#ZQzU1a~&LpiP`R!1yf4yC$U@6Oc^qmhH=fwXz@ZF6eYd}G2qea?LIh?yQU4`=E_ zBQ3D2Jc8nWRz!{bS+b+v!pK(CKUj~lVhnZm)Z?s}K)wC-Hdaic?!gD6_lN2!Mz*6} z`yLeT->i2qvJ>?W*M=vzcD+^aVinzpKU6#P&erhhdJn7UMSVjL7Vj_A`xv&zw$^kUMKMLRfVSP6v2hrfjqtS;$^*xN-OS?=y9P?%b176?iJ-B^Z zb>9?UU49NrY%g{$JwT2CVRaNVMZpDnsi9}Yl>*yIs}(-^;F5_@pU<}1I^f!H#9ghm0YzrpBy^0V`N#YWO_qqS_v3aCfc*#9S-D=$n^s3JB+HQj#oGDg6M`QwC47^{*PT9tD znw)|#&$3$<{c6zqgKMQx(5yy?0k)yTXQ*S*N;;74f`K!hs`_gXy>J?mU0sjHICh#Kw diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgame.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgame.cpython-311.pyc deleted file mode 100755 index 1c07d0e6570896790b0bb7e9af2afad8c509e5de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2891 zcmeHJ&2JM&6rWjtt&I%|C6uqgsudrmWG$3btt?cLDl|<>9F>F$d|cs1$MPo3Ym)`KZ+P+VSq&_h#O_ znfbjp@A+XWl|ayb{qmcu-vRfV5P}wIGiwXL+(Q=1BMV!KgUd=@!GaGtp>jAMmVDTW zl%x5m%kxyWxpb2Ef?jTDg(FY-f9>d#e`5jh#7NrxnX66=crjJY8qx!kl}rtw7(9Fs93c#~_CR48G@<=Px^NQs(dZPImYmwa3$w0428s>3JDGSUAK z_S4u`XDZzGT+;!5PfPV9Qd{s$YE7GTsak>lflVgF#Hrbt+_+ufzz=Rxn5$Jtp?wDV z+0ho(^1yrwm=To6fSY3Be8^Jr;W)AqR>%r}i>(NWSW$RmBuZlYJ5~fbMD5B&bp;i% z6~D79A74Q?aXtY^?bu>7;=ty8!1O|Z4%196D}l?-^EObrP@C5i2@Tp9EwQZRgk)RV ziLAG9H9OBZolj@Ai>`gGN}wN*wu?5QTG6B60dNt(4;Y{7%oX#qyfh3xW4vdzO_1r+ zlR0B@+&F(OH!=6&{P4fAFm|cOg7$um6Q+0Ul;C^@Tl6S5TwpgGX;utqa=hrVLxG3Y-8z$2{+VNY>SF4O+|X4DIkS#J6~Y(Tw zA7RxBp}uMuwrg|4pu(^p7D4aFjjCIu-Yw$NozUBbF&*{8j5x&&-4b1xWyqUv7))$g z+!^imD>Jj`l}QGYL&3{Tc_nWoV^%7e>%_gDaqNXmrN$RMcSJvZI>T&EhAU=a39dKG z1i3c@8x&P4)A~SerL|Tfl}V^lqXV$ot;3rx@r1}x!SO~xhy4g-{Wkh@H;V84EOs~c zi@NV8b>GkX_0|0&-(UD)s;=&Prp~OYGj(;QksA2o%I8;}rG{2hLroNpPvaJC92{C1 zzdO-5@y^QlYEpZC_PqEGHRD~Cmf{OJ>1EH+9>=4fXc3-Efwt;k{$WLr;%~ z$KHxP)iKaC&Ow<2r;2247=FSqTK@}xPa4Lxs_C>xVuoRP1?UF1F~{Q!*btO3Dnglx zXr;o75?nvkc5Q(;j$x!R9fTn!uEklpS7^lpa!3q30s=S(zozn9L~SBLPNIR)+mp>C zdiP8-zB2-tCecZ~nUXB((&x!t&4?7E=)h1jCRr7|ex!b6WOeUoXYSz8*OylJ9NTQ5 z*<j1fQk{$rTk3t2p-I9dDKN-|pyovimi4K!Nsf11%_Slo)OY5maf3pw<18wGigzW}@k B9B2Rl diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgif.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgif.cpython-311.pyc deleted file mode 100755 index 8a3be7976208766392b0b0104297b0b55e84538d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7611 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 MHv6k5NHGQe3*Wzv?*IS* diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultlocation.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultlocation.cpython-311.pyc deleted file mode 100755 index e594dca22ac9e451726ad0a259a4416f792f0ba5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8658 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