Compare commits

...

8 Commits

Author SHA1 Message Date
harshil21 2877bc068b Add chango fragment for PR #5271 2026-06-17 20:39:58 +00:00
Harshil 430bde6e0e Remove functionality deprecated in Bot API 10.0 2026-06-17 16:35:29 -04:00
renovate[bot] 6775884282 Update Ruff to v0.15.16 (#5265)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-14 02:11:40 +00:00
renovate[bot] 8504e323b6 Update dependency tornado to v6.5.6 [SECURITY] (#5264)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-12 23:04:49 +00:00
Poolitzer afb9fc4898 Fix: Delete the chango here
I wasn't able to in the PR, it was too quick
2026-06-12 10:03:03 +02:00
Poolitzer 5d663af824 Bump version to v22.8 (#5262) 2026-06-12 10:02:13 +02:00
Harshil 0dd6afc177 Documentation Improvements (#5240)
Co-authored-by: Poolitzer <github@poolitzer.eu>
2026-06-12 09:46:44 +02:00
Harshil 4c710a3455 Support Python 3.15 beta (#5259) 2026-06-12 09:36:40 +02:00
85 changed files with 429 additions and 1194 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15.0-beta.2']
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- python-version: '3.14t'
+1 -1
View File
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.15.15'
rev: 'v0.15.16'
hooks:
# Run the linter:
- id: ruff-check
@@ -0,0 +1,6 @@
documentation = "Documentation Improvements"
pull_requests = [
{ uid = "5240", author_uids = ["harshil21", "Poolitzer"] },
{ uid = "5241", author_uids = ["harshil21"] },
]
@@ -0,0 +1,9 @@
other = """Support Python 3.15 Beta
* Python 3.15 free threading is not fully supported yet, as the optional dependency ``cryptography`` is not yet compatible with it.
"""
[[pull_requests]]
uid = "5259"
author_uids = ["harshil21"]
closes_threads = ["5231"]
@@ -0,0 +1,5 @@
other = "Bump Version to 22.8"
[[pull_requests]]
uid = "5262"
author_uids = ["Poolitzer"]
closes_threads = []
@@ -0,0 +1,5 @@
dependencies = "Update dependency tornado to v6.5.6 [SECURITY]"
[[pull_requests]]
uid = "5264"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,5 @@
internal = "Update Ruff to v0.15.16"
[[pull_requests]]
uid = "5265"
author_uids = ["renovate[bot]"]
closes_threads = []
@@ -0,0 +1,6 @@
breaking = "Remove functionality deprecated in Bot API 10.0"
features = "Remove functionality deprecated in Bot API 10.0"
[[pull_requests]]
uid = "5271"
author_uids = ["harshil21"]
closes_threads = []
@@ -83,6 +83,13 @@ get_updates_read_timeout_addition = [
" ``2``.",
]
RAISES_BLOCK = [
"Raises:",
"",
" :class:`telegram.error.TelegramError`",
"",
]
def find_insert_pos_for_kwargs(lines: list[str]) -> int:
"""Finds the correct position to insert the keyword arguments and returns the index."""
@@ -92,6 +99,13 @@ def find_insert_pos_for_kwargs(lines: list[str]) -> int:
return False
def find_insert_pos_for_raises(lines: list[str]) -> int:
"""Finds the correct position to insert the Raises block and returns the index."""
if "Raises:" in lines:
return -1 # Don't insert if there's already a Raises block
return len(lines) # Insert at the end if there's no Raises block
def check_timeout_and_api_kwargs_presence(obj: object) -> int:
"""Checks if the method has timeout and api_kwargs keyword only parameters."""
sig = inspect.signature(obj)
+18 -4
View File
@@ -27,9 +27,11 @@ from sphinx.application import Sphinx
import telegram
import telegram.ext
from docs.auxil.admonition_inserter import AdmonitionInserter
from docs.auxil.kwargs_insertion import (
from docs.auxil.bot_insertion import (
RAISES_BLOCK,
check_timeout_and_api_kwargs_presence,
find_insert_pos_for_kwargs,
find_insert_pos_for_raises,
get_updates_read_timeout_addition,
keyword_args,
media_write_timeout_change,
@@ -85,8 +87,8 @@ def autodoc_process_docstring(
app: Sphinx, what, name: str, obj: object, options, lines: list[str]
):
"""We do the following things:
1) Use this method to automatically insert the Keyword Args and "Shortcuts" admonitions
for the Bot methods.
1) Use this method to automatically insert the Keyword Args, "Shortcuts" admonitions,
and the Raises block, wherever applicable, for the Bot methods.
2) Use this method to automatically insert "Returned in" admonition into classes
that are returned from the Bot methods
@@ -102,13 +104,15 @@ def autodoc_process_docstring(
"""
# 1) Insert the Keyword Args and "Shortcuts" admonitions for the Bot methods
method_name = name.rsplit(".", maxsplit=1)[0]
method_name = name.rsplit(".", maxsplit=1)[-1]
if (
name.startswith("telegram.Bot.")
and what == "method"
and method_name.islower()
and check_timeout_and_api_kwargs_presence(obj)
):
# Logic for inserting keyword args into docstrings:
# -------------------------------------------------
insert_index = find_insert_pos_for_kwargs(lines)
if not insert_index:
raise ValueError(
@@ -134,6 +138,16 @@ def autodoc_process_docstring(
lines[insert_idx:insert_idx] = effective_insert
insert_idx += len(effective_insert)
# Logic for inserting Raises:
# -------------------------------------------------
# We will only insert the Raises block if there isn't already one.
insert_index = find_insert_pos_for_raises(lines)
if insert_index != -1:
lines[insert_index:insert_index] = RAISES_BLOCK
# Logic for inserting "Shortcuts" admonition:
# -------------------------------------------
ADMONITION_INSERTER.insert_admonitions(
obj=typing.cast("collections.abc.Callable", obj),
docstring_lines=lines,
+1
View File
@@ -165,6 +165,7 @@ Available Types
telegram.poll
telegram.pollanswer
telegram.pollmedia
telegram.polloption
telegram.polloptionadded
telegram.polloptiondeleted
telegram.preparedkeyboardbutton
+2 -1
View File
@@ -36,6 +36,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
]
dependencies = [
"httpx >=0.27,<0.29",
@@ -133,7 +134,7 @@ docs = [
]
linting = [
"prek",
"ruff==0.15.15",
"ruff==0.15.16",
"mypy==1.20.2",
"pylint==4.0.5"
]
+19 -18
View File
@@ -343,19 +343,7 @@ __all__ = (
"warnings",
)
from telegram._inputchecklist import InputChecklist, InputChecklistTask
from telegram._payment.stars.staramount import StarAmount
from telegram._payment.stars.startransactions import StarTransaction, StarTransactions
from telegram._payment.stars.transactionpartner import (
TransactionPartner,
TransactionPartnerAffiliateProgram,
TransactionPartnerChat,
TransactionPartnerFragment,
TransactionPartnerOther,
TransactionPartnerTelegramAds,
TransactionPartnerTelegramApi,
TransactionPartnerUser,
)
__lazy_modules__: list[str] = ["constants", "error", "helpers", "request", "warnings"]
from . import _version, constants, error, helpers, request, warnings
from ._birthdate import Birthdate
@@ -431,11 +419,6 @@ from ._copytextbutton import CopyTextButton
from ._dice import Dice
from ._directmessagepricechanged import DirectMessagePriceChanged
from ._directmessagestopic import DirectMessagesTopic
from ._files._inputstorycontent import (
InputStoryContent,
InputStoryContentPhoto,
InputStoryContentVideo,
)
from ._files.animation import Animation
from ._files.audio import Audio
from ._files.chatphoto import ChatPhoto
@@ -467,6 +450,11 @@ from ._files.inputprofilephoto import (
InputProfilePhotoStatic,
)
from ._files.inputsticker import InputSticker
from ._files.inputstorycontent import (
InputStoryContent,
InputStoryContentPhoto,
InputStoryContentVideo,
)
from ._files.livephoto import LivePhoto
from ._files.location import Location
from ._files.photosize import PhotoSize
@@ -523,6 +511,7 @@ from ._inline.inputmessagecontent import InputMessageContent
from ._inline.inputtextmessagecontent import InputTextMessageContent
from ._inline.inputvenuemessagecontent import InputVenueMessageContent
from ._inline.preparedinlinemessage import PreparedInlineMessage
from ._inputchecklist import InputChecklist, InputChecklistTask
from ._keyboardbutton import KeyboardButton
from ._keyboardbuttonpolltype import KeyboardButtonPollType
from ._keyboardbuttonrequest import (
@@ -596,6 +585,18 @@ from ._payment.stars.revenuewithdrawalstate import (
RevenueWithdrawalStatePending,
RevenueWithdrawalStateSucceeded,
)
from ._payment.stars.staramount import StarAmount
from ._payment.stars.startransactions import StarTransaction, StarTransactions
from ._payment.stars.transactionpartner import (
TransactionPartner,
TransactionPartnerAffiliateProgram,
TransactionPartnerChat,
TransactionPartnerFragment,
TransactionPartnerOther,
TransactionPartnerTelegramAds,
TransactionPartnerTelegramApi,
TransactionPartnerUser,
)
from ._payment.successfulpayment import SuccessfulPayment
from ._poll import (
InputPollOption,
+44 -642
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -37,7 +37,7 @@ class BotAccessSettings(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`is_access_restricted` and :attr:`added_users` are equal.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
is_access_restricted (:obj:`bool`): :obj:`True`, if only selected users can access the bot.
+4 -7
View File
@@ -33,7 +33,6 @@ from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import (
CorrectOptionID,
CorrectOptionIds,
FileInput,
JSONDict,
@@ -1110,7 +1109,7 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_message_draft`.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
Bot API 10.0 makes the ``text`` argument optional.
Returns:
@@ -1392,7 +1391,7 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_live_photo`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:class:`telegram.Message`: On success, instance representing the message posted.
@@ -2358,7 +2357,6 @@ class _ChatBase(TelegramObject):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: CorrectOptionID | None = None,
is_closed: bool | None = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "ReplyMarkup | None" = None,
@@ -2413,7 +2411,6 @@ class _ChatBase(TelegramObject):
is_anonymous=is_anonymous,
type=type, # pylint=pylint,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
correct_option_ids=correct_option_ids,
@@ -4155,7 +4152,7 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_message_reaction`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -4195,7 +4192,7 @@ class _ChatBase(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_all_message_reactions`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
+3 -8
View File
@@ -521,7 +521,7 @@ class ChatMemberRestricted(ChatMember):
can_react_to_messages (:obj:`bool`): :obj:`True`, if the user is allowed to react to
messages.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
tag (:obj:`str`, optional): Tag of the member.
.. versionadded:: 22.7
@@ -582,7 +582,7 @@ class ChatMemberRestricted(ChatMember):
can_react_to_messages (:obj:`bool`): :obj:`True`, if the user is allowed to react to
messages.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
tag (:obj:`str`): Optional. Tag of the member.
.. versionadded:: 22.7
@@ -631,18 +631,13 @@ class ChatMemberRestricted(ChatMember):
can_send_video_notes: bool,
can_send_voice_notes: bool,
can_edit_tag: bool,
can_react_to_messages: bool,
tag: str | None = None,
# tags: NEXT.VERSION
# temporarily optional to make it not breaking
can_react_to_messages: bool | None = None,
*,
api_kwargs: JSONDict | None = None,
):
super().__init__(status=ChatMember.RESTRICTED, user=user, api_kwargs=api_kwargs)
if can_react_to_messages is None:
raise TypeError("`can_react_to_messages` is required and cannot be None")
with self._unfrozen():
self.is_member: bool = is_member
self.can_change_info: bool = can_change_info
+3 -3
View File
@@ -50,7 +50,7 @@ class ChatPermissions(TelegramObject):
.. versionchanged:: 22.7
:attr:`can_edit_tag` is considered as well when comparing objects of
this type in terms of equality.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
:attr:`can_react_to_messages` is considered as well when comparing objects of
this type in terms of equality.
@@ -106,7 +106,7 @@ class ChatPermissions(TelegramObject):
can_react_to_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to react
to messages. If omitted, defaults to the value of :attr:`can_send_messages`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text
@@ -155,7 +155,7 @@ class ChatPermissions(TelegramObject):
can_react_to_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to react
to messages. If omitted, defaults to the value of :attr:`can_send_messages`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
+33 -33
View File
@@ -176,7 +176,7 @@ class InputPaidMedia(TelegramObject):
LIVE_PHOTO: Final[str] = constants.InputPaidMediaType.LIVE_PHOTO
""":const:`telegram.constants.InputPaidMediaType.LIVE_PHOTO`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = ("media", "type")
@@ -342,7 +342,7 @@ class InputPaidMediaLivePhoto(InputPaidMedia):
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
@@ -404,8 +404,8 @@ class InputMediaAnimation(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
.. versionadded:: 22.8
.. deprecated:: 22.8
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the animation to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
@@ -441,7 +441,7 @@ class InputMediaAnimation(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This parameter is now keyword-only.
Attributes:
@@ -494,7 +494,7 @@ class InputMediaAnimation(InputMedia):
height: int | None = None,
duration: TimePeriod | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated NEXT.VERSION
# tag: deprecated 22.8
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
@@ -509,7 +509,7 @@ class InputMediaAnimation(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"22.8",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -565,8 +565,8 @@ class InputMediaPhoto(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
.. versionadded:: 22.8
.. deprecated:: 22.8
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional ): Caption of the photo to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
@@ -590,7 +590,7 @@ class InputMediaPhoto(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This parameter is now keyword-only.
Attributes:
@@ -626,7 +626,7 @@ class InputMediaPhoto(InputMedia):
caption: str | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated NEXT.VERSION
# tag: deprecated 22.8
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
@@ -640,7 +640,7 @@ class InputMediaPhoto(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"22.8",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -693,8 +693,8 @@ class InputMediaVideo(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
.. versionadded:: 22.8
.. deprecated:: 22.8
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the video to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
@@ -738,7 +738,7 @@ class InputMediaVideo(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This parameter is now keyword-only.
Attributes:
@@ -803,7 +803,7 @@ class InputMediaVideo(InputMedia):
supports_streaming: bool | None = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated NEXT.VERSION
# tag: deprecated 22.8
filename_depr: str | None = None,
# -
has_spoiler: bool | None = None,
@@ -820,7 +820,7 @@ class InputMediaVideo(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"22.8",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -869,7 +869,7 @@ class InputMediaVideo(InputMedia):
class InputMediaLocation(_BaseInputMedia):
"""Represents a location to be sent.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
latitude (:obj:`float`): Latitude of the location.
@@ -905,7 +905,7 @@ class InputMediaLocation(_BaseInputMedia):
class InputMediaVenue(_BaseInputMedia):
"""Represents a venue to be sent.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
latitude (:obj:`float`): Latitude of the location.
@@ -976,7 +976,7 @@ class InputMediaSticker(_BaseInputMedia):
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
@@ -1039,8 +1039,8 @@ class InputMediaAudio(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
.. versionadded:: 22.8
.. deprecated:: 22.8
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the audio to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
@@ -1070,7 +1070,7 @@ class InputMediaAudio(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This parameter is now keyword-only.
Attributes:
@@ -1111,7 +1111,7 @@ class InputMediaAudio(InputMedia):
performer: str | None = None,
title: str | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated NEXT.VERSION
# tag: deprecated 22.8
filename_depr: str | None = None,
# -
thumbnail: "FileInput | None" = None,
@@ -1124,7 +1124,7 @@ class InputMediaAudio(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"22.8",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -1181,8 +1181,8 @@ class InputMediaDocument(InputMedia):
filename_depr (:obj:`str`, optional): Positional placeholder for keyword only parameter
:paramref:`filename`. For backward compatibility.
.. versionadded:: NEXT.VERSION
.. deprecated:: NEXT.VERSION
.. versionadded:: 22.8
.. deprecated:: 22.8
This parameter is deprecated, use :paramref:`filename` instead.
caption (:obj:`str`, optional): Caption of the document to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
@@ -1207,7 +1207,7 @@ class InputMediaDocument(InputMedia):
:obj:`tempfile` module.
.. versionadded:: 13.1
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This parameter is now keyword-only.
Attributes:
@@ -1240,7 +1240,7 @@ class InputMediaDocument(InputMedia):
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_content_type_detection: bool | None = None,
caption_entities: Sequence[MessageEntity] | None = None,
# tag: deprecated NEXT.VERSION
# tag: deprecated 22.8
filename_depr: str | None = None,
# -
thumbnail: "FileInput | None" = None,
@@ -1253,7 +1253,7 @@ class InputMediaDocument(InputMedia):
if filename_depr is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"22.8",
"Positional passing of `filename` or keyword usage of `filename_depr`"
" is deprecated. `filename` will become a keyword-only argument.",
),
@@ -1285,7 +1285,7 @@ class InputMediaLivePhoto(InputMedia):
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
@@ -1364,7 +1364,7 @@ InputPollMedia: TypeAlias = (
)
"""Type alias for InputPollMedia objects.
versionadded:: NEXT.VERSION
versionadded:: 22.8
"""
InputPollOptionMedia: TypeAlias = (
@@ -1378,5 +1378,5 @@ InputPollOptionMedia: TypeAlias = (
)
"""Type alias for InputPollOptionMedia objects.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
+1 -1
View File
@@ -39,7 +39,7 @@ class LivePhoto(_BaseMedium):
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.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
file_id (:obj:`str`): Identifier for the video file which can be used to download or reuse
+1 -1
View File
@@ -105,7 +105,7 @@ class Video(_BaseThumbedMedium):
.. deprecated:: v22.2
|time-period-int-deprecated|
qualities (Sequence[:class:`telegram.VideoQuality`]): Optional. List of available qualities
qualities (tuple[:class:`telegram.VideoQuality`]): Optional. List of available qualities
of the video
.. versionadded:: 22.7
+2 -2
View File
@@ -130,7 +130,7 @@ class KeyboardButton(TelegramObject):
in the `@BotFather <https://telegram.me/BotFather>` Mini App. Available in private
chats only.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
@@ -185,7 +185,7 @@ class KeyboardButton(TelegramObject):
in the `@BotFather <https://telegram.me/BotFather>` Mini App. Available in private
chats only.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = (
+1 -1
View File
@@ -280,7 +280,7 @@ class KeyboardButtonRequestManagedBot(TelegramObject):
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:: NEXT.VERSION
.. versionadded:: 22.8
Args:
request_id (:obj:`int`): Signed 32-bit identifier of the request. Must be unique
+2 -2
View File
@@ -38,7 +38,7 @@ class ManagedBotCreated(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`bot` is equal.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
bot (:class:`telegram.User`): Information about the bot. The bot's token can be fetched
@@ -79,7 +79,7 @@ class ManagedBotUpdated(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`user` and :attr:`bot` are equal.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
user (:class:`telegram.User`): User that created the bot.
+22 -25
View File
@@ -81,7 +81,6 @@ 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,
CorrectOptionIds,
JSONDict,
MarkdownVersion,
@@ -693,46 +692,46 @@ class Message(MaybeInaccessibleMessage):
.. versionadded:: 22.7
sender_tag (:obj:`str`, optional): Tag or custom title of the sender of the message; for
supergroups only
supergroups only.
.. versionadded:: 22.7
poll_option_added (:class:`telegram.PollOptionAdded`, optional): Service message:
answer option was added to a poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
poll_option_deleted (:class:`telegram.PollOptionDeleted`, optional): Service message:
answer option was deleted from a poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
reply_to_poll_option_id (:obj:`str`, optional): Persistent
identifier of the specific poll option that is being replied to.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
managed_bot_created (:class:`telegram.ManagedBotCreated`, optional): Service message: user
created a bot that will be managed by the current bot.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
guest_bot_caller_user (:class:`telegram.User`, optional): For a message sent by a guest
bot, this is the user whose original message triggered the bot's response.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
guest_bot_caller_chat (:class:`telegram.Chat`, optional): For a message sent by a guest
bot, this is the chat whose original message triggered the bot's response.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
guest_query_id (:obj:`str`, optional): The unique identifier for the guest query. Use this
identifier with the method :meth:`telegram.Bot.answer_guest_query` to send a response
message. If non-empty, the message belongs to the chat where the guest bot was
summoned, which may not coincide with other existing bot chats sharing the same
identifier.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
live_photo (:class:`telegram.LivePhoto`, optional): Message is a live photo, information
about the live photo. For backward compatibility, when this field is set, the photo
field will also be set.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances
@@ -1146,45 +1145,45 @@ class Message(MaybeInaccessibleMessage):
.. versionadded:: 22.7
sender_tag (:obj:`str`): Optional. Tag or custom title of the sender of the message; for
supergroups only
supergroups only.
.. versionadded:: 22.7
poll_option_added (:class:`telegram.PollOptionAdded`): Optional. Service message:
answer option was added to a poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
poll_option_deleted (:class:`telegram.PollOptionDeleted`): Optional. Service message:
answer option was deleted from a poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
reply_to_poll_option_id (:obj:`str`): Optional. Persistent
identifier of the specific poll option that is being replied to.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
managed_bot_created (:class:`telegram.ManagedBotCreated`): Optional. Service message: user
created a bot that will be managed by the current bot.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
guest_bot_caller_user (:class:`telegram.User`): Optional. For a message sent by a guest
bot, this is the user whose original message triggered the bot's response.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
guest_bot_caller_chat (:class:`telegram.Chat`): Optional. For a message sent by a guest
bot, this is the chat whose original message triggered the bot's response.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
guest_query_id (:obj:`str`): Optional. The unique identifier for the guest query. Use this
identifier with the method :meth:`telegram.Bot.answer_guest_query` to send a response
message. If non-empty, the message belongs to the chat where the guest bot was
summoned, which may not coincide with other existing bot chats sharing the same
identifier.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
live_photo (:class:`telegram.LivePhoto`): Optional. Message is a live photo, information
about the live photo. For backward compatibility, when this field is set, the photo
field will also be set.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
.. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
@@ -2279,7 +2278,7 @@ class Message(MaybeInaccessibleMessage):
.. versionadded:: 22.6
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
Bot API 10.0 makes the ``text`` argument optional.
Returns:
@@ -2756,7 +2755,7 @@ class Message(MaybeInaccessibleMessage):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_live_photo`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Keyword Args:
do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
@@ -3663,7 +3662,6 @@ class Message(MaybeInaccessibleMessage):
is_anonymous: bool | None = None,
type: str | None = None, # pylint: disable=redefined-builtin
allows_multiple_answers: bool | None = None,
correct_option_id: CorrectOptionID | None = None,
is_closed: bool | None = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "ReplyMarkup | None" = None,
@@ -3739,7 +3737,6 @@ class Message(MaybeInaccessibleMessage):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
correct_option_ids=correct_option_ids,
@@ -5400,7 +5397,7 @@ class Message(MaybeInaccessibleMessage):
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_message_reaction`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:obj:`bool` On success, :obj:`True` is returned.
@@ -5436,7 +5433,7 @@ class Message(MaybeInaccessibleMessage):
For the documentation of the arguments, please see :meth:`telegram.Bot.answer_guest_query`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:class:`telegram.SentGuestMessage`: On success, a
+1 -1
View File
@@ -262,7 +262,7 @@ class PaidMediaLivePhoto(PaidMedia):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`live_photo` are equal.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.LIVE_PHOTO`
+48 -135
View File
@@ -51,8 +51,6 @@ from telegram._utils.datetime import (
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.entities import parse_message_entities, parse_message_entity
from telegram._utils.types import JSONDict, ODVInput, TimePeriod
from telegram._utils.warnings import warn
from telegram.warnings import PTBDeprecationWarning
if TYPE_CHECKING:
from telegram import Bot, InputPollOptionMedia, MaybeInaccessibleMessage
@@ -65,7 +63,7 @@ class PollMedia(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if all of their attributes are equal.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
animation (:class:`telegram.Animation`, optional): Media is an animation, information about
@@ -195,7 +193,7 @@ class InputPollOption(TelegramObject):
This list is empty if the text does not contain entities.
media (:class:`telegram.InputPollOptionMedia`, optional): Media added to the poll option.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
text (:obj:`str`): Option text,
@@ -210,7 +208,7 @@ class InputPollOption(TelegramObject):
This list is empty if the text does not contain entities.
media (:class:`telegram.InputPollOptionMedia`): Optional. Media added to the poll option.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = ("media", "text", "text_entities", "text_parse_mode")
@@ -234,30 +232,6 @@ class InputPollOption(TelegramObject):
self._freeze()
# tags: deprecated NEXT.VERSION
@classmethod
def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "InputPollOption":
"""See :meth:`telegram.TelegramObject.de_json`. The :paramref:`media` field will
not be included for deserialization.
.. deprecated:: NEXT.VERSION
This class is input only and will be removed in the next version.
"""
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"`InputPollOption.de_json` is deprecated. This class is input only and will be "
"removed in the next version. The `media` field will not be included for "
"deserialization.",
),
stacklevel=2,
)
data = cls._parse_data(data)
data["text_entities"] = de_list_optional(data.get("text_entities"), MessageEntity, bot)
return super().de_json(data=data, bot=bot)
class PollOption(TelegramObject):
"""
@@ -267,7 +241,7 @@ class PollOption(TelegramObject):
considered equal, if their :attr:`text`, :attr:`voter_count` and :attr:`persistent_id`
are equal.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
Added attribute :attr:`persistent_id` to equality checks.
@@ -275,7 +249,7 @@ class PollOption(TelegramObject):
persistent_id (:obj:`str`): Unique identifier of the option, persistent on option addition
and deletion.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
text (:obj:`str`): Option text,
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
characters.
@@ -287,25 +261,25 @@ class PollOption(TelegramObject):
.. versionadded:: 21.2
media (:class:`telegram.PollMedia`, optional): Media added to the poll option.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
added_by_user (:class:`telegram.User`, optional): User who added the option;
omitted if the option wasn't added by a user after poll creation.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
added_by_chat (:class:`telegram.Chat`, optional): Chat that added the option;
omitted if the option wasn't added by a chat after poll creation.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
addition_date (:obj:`datetime.datetime`, optional): Point in time
when the option was added; omitted if the option existed in the original poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
persistent_id (:obj:`str`): Unique identifier of the option, persistent on option addition
and deletion.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
text (:obj:`str`): Option text,
:tg-const:`telegram.PollOption.MIN_LENGTH`-:tg-const:`telegram.PollOption.MAX_LENGTH`
characters.
@@ -318,19 +292,19 @@ class PollOption(TelegramObject):
.. versionadded:: 21.2
media (:class:`telegram.PollMedia`): Optional. Media added to the poll option.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
added_by_user (:class:`telegram.User`): Optional. User who added the option;
omitted if the option wasn't added by a user after poll creation.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
added_by_chat (:class:`telegram.Chat`): Optional. Chat that added the option;
omitted if the option wasn't added by a chat after poll creation.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
addition_date (:obj:`datetime.datetime`): Optional. Point in time
when the option was added; omitted if the option existed in the original poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = (
@@ -348,20 +322,15 @@ class PollOption(TelegramObject):
self,
text: str,
voter_count: int,
persistent_id: str,
text_entities: Sequence[MessageEntity] | None = None,
added_by_user: User | None = None,
added_by_chat: Chat | None = None,
addition_date: dtm.datetime | None = None,
media: PollMedia | None = None,
# tags: required in NEXT.VERSION, bot api 9.6
# temporarily optional to avoid breaking changes
persistent_id: str | None = None,
*,
api_kwargs: JSONDict | None = None,
):
if persistent_id is None:
raise TypeError("`persistent_id` is a required argument since Bot API 9.6")
super().__init__(api_kwargs=api_kwargs)
self.text: str = text
self.voter_count: int = voter_count
@@ -474,7 +443,7 @@ class PollAnswer(TelegramObject):
option_persistent_ids (Sequence[:obj:`str`]): Persistent identifiers of the
chosen answer options. May be empty if the vote was retracted.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
user (:class:`telegram.User`, optional): The user that changed the answer to the poll,
if the voter isn't anonymous. If the voter is anonymous, this field will contain the
user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility.
@@ -496,7 +465,7 @@ class PollAnswer(TelegramObject):
option_persistent_ids (tuple[:obj:`str`]): Persistent identifiers of the
chosen answer options. May be empty if the vote was retracted.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
user (:class:`telegram.User`): Optional. The user, who changed the answer to the
poll, if the voter isn't anonymous. If the voter is anonymous, this field will contain
the user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility
@@ -515,17 +484,12 @@ class PollAnswer(TelegramObject):
self,
poll_id: str,
option_ids: Sequence[int],
option_persistent_ids: Sequence[str],
user: User | None = None,
voter_chat: Chat | None = None,
# tags: required in NEXT.VERSION, bot api 9.6
# temporarily optional to avoid breaking changes
option_persistent_ids: Sequence[str] | None = None,
*,
api_kwargs: JSONDict | None = None,
):
if option_persistent_ids is None:
raise TypeError("`option_persistent_ids` is a required argument since Bot API 9.6")
super().__init__(api_kwargs=api_kwargs)
self.poll_id: str = poll_id
self.voter_chat: Chat | None = voter_chat
@@ -560,7 +524,7 @@ class PollOptionAdded(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`option_persistent_id`, and :attr:`option_text` are equal.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
option_persistent_id (:obj:`str`): Unique identifier of the added option.
@@ -675,7 +639,7 @@ class PollOptionDeleted(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`option_persistent_id`, :attr:`option_text` are equal.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
option_persistent_id (:obj:`str`): Unique identifier of the deleted option.
@@ -805,17 +769,15 @@ class Poll(TelegramObject):
is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous.
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers.
allows_revoting (:obj:`bool`): :obj:`True`, if the poll allows to
change the chosen answer options.
.. versionadded:: 22.8
members_only (:obj:`bool`): :obj:`True`, if voting is limited to users who have been
members of the chat where the poll was originally sent for more than
:tg-const:`telegram.Poll.MIN_MEMBERSHIP_HOURS` hours.
.. versionadded:: NEXT.VERSION
correct_option_id (:obj:`int`, optional): A zero based identifier of the correct answer
option. Available only for closed polls in the quiz mode, which were sent
(not forwarded), by the bot or to a private chat with the bot.
.. deprecated:: NEXT.VERSION
Use :paramref:`correct_option_ids` instead.
.. versionadded:: 22.8
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.
@@ -831,7 +793,7 @@ class Poll(TelegramObject):
explanation_media (:class:`telegram.PollMedia`, optional): Media added to the quiz
explanation.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
open_period (:obj:`int` | :class:`datetime.timedelta`, optional): Amount of time in seconds
the poll will be active after creation.
@@ -847,33 +809,29 @@ class Poll(TelegramObject):
in poll questions.
.. versionadded:: 21.2
allows_revoting (:obj:`bool`, optional): :obj:`True`, if the poll allows to
change the chosenanswer options.
.. versionadded:: NEXT.VERSION
correct_option_ids (Sequence[:class:`int`], optional): Array of 0-based identifiers of
the correct answer options. Available only for polls in quiz mode which are closed or
were sent (not forwarded) by the bot or to the private chat with the bot.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
country_codes (Sequence[:obj:`str`], optional): A list of two-letter ``ISO 3166-1 alpha-2``
country codes indicating the countries from which users can vote in the poll. The
country code ``"FT"`` is used for users with anonymous numbers. If omitted, then users
from any country can participate in the poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
description (:obj:`str`, optional): Description of the poll;
for polls inside the :class:`~telegram.Message` object only.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
description_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special
entities like usernames, URLs, bot commands, etc. that appear in the description
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
media (:class:`telegram.PollMedia`, optional): Media added to the poll description;
for polls inside the :class:`~telegram.Message` object only.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
id (:obj:`str`): Unique poll identifier.
@@ -888,11 +846,15 @@ class Poll(TelegramObject):
is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous.
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers.
allows_revoting (:obj:`bool`): :obj:`True`, if the poll
allows to change the chosen answer options
.. versionadded:: 22.8
members_only (:obj:`bool`): :obj:`True`, if voting is limited to users who have been
members of the chat where the poll was originally sent for more than
:tg-const:`telegram.Poll.MIN_MEMBERSHIP_HOURS` hours.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
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.
@@ -908,7 +870,7 @@ class Poll(TelegramObject):
explanation_media (:class:`telegram.PollMedia`): Optional. Media added to the quiz
explanation.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
open_period (:obj:`int` | :class:`datetime.timedelta`): Optional. Amount of time in seconds
the poll will be active after creation.
@@ -925,33 +887,29 @@ class Poll(TelegramObject):
This list is empty if the question does not contain entities.
.. versionadded:: 21.2
allows_revoting (:obj:`bool`): :obj:`True`, if the poll
allows to change the chosenanswer options
.. versionadded:: NEXT.VERSION
correct_option_ids (tuple[:class:`int`]): Array of 0-based identifiers of the
correct answer options. Available only for polls in quiz mode which are closed or were
sent (not forwarded) by the bot or to the private chat with the bot.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
country_codes (tuple[:obj:`str`]): Optional. A list of two-letter ``ISO 3166-1 alpha-2``
country codes indicating the countries from which users can vote in the poll. The
country code ``"FT"`` is used for users with anonymous numbers. If omitted, then users
from any country can participate in the poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
description (:obj:`str`): Optional. Description of the poll;
for polls inside the Message object only
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
description_entities (tuple[:class:`telegram.MessageEntity`]): Special
entities like usernames, URLs, bot commands, etc. that appear in the description
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
media (:class:`telegram.PollMedia`): Optional. Media added to the poll description;
for polls inside the Message object only.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
@@ -989,20 +947,13 @@ class Poll(TelegramObject):
is_anonymous: bool,
type: str, # pylint: disable=redefined-builtin
allows_multiple_answers: bool,
# tags: deprecated NEXT.VERSION
# Removed in bot api 9.6:
correct_option_id: int | None = None,
# ---
allows_revoting: bool,
members_only: bool,
explanation: str | None = None,
explanation_entities: Sequence[MessageEntity] | None = None,
open_period: TimePeriod | None = None,
close_date: dtm.datetime | None = None,
question_entities: Sequence[MessageEntity] | None = None,
# tags: required in NEXT.VERSION
# temporarily optional to avoid breaking changes
allows_revoting: bool | None = None,
members_only: bool | None = None,
# ---
correct_option_ids: Sequence[int] | None = None,
description: str | None = None,
description_entities: Sequence[MessageEntity] | None = None,
@@ -1012,12 +963,6 @@ class Poll(TelegramObject):
*,
api_kwargs: JSONDict | None = None,
):
if allows_revoting is None:
raise TypeError("`allows_revoting` is a required argument since Bot API 9.6")
if members_only is None:
raise TypeError("`members_only` is a required argument since Bot API 10.0")
super().__init__(api_kwargs=api_kwargs)
self.id: str = id
self.question: str = question
@@ -1030,19 +975,6 @@ class Poll(TelegramObject):
self.allows_revoting: bool = allows_revoting
self.members_only: bool = members_only
# tag: deprecated NEXT.VERSION
if correct_option_id is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"The parameter `correct_option_id` is deprecated. "
"Use `correct_option_ids` instead.",
),
stacklevel=2,
)
if correct_option_ids is None:
correct_option_ids = [correct_option_id]
self.correct_option_ids: tuple[int, ...] = parse_sequence_arg(correct_option_ids)
self.description: str | None = description
self.description_entities: tuple[MessageEntity, ...] = parse_sequence_arg(
@@ -1196,7 +1128,7 @@ class Poll(TelegramObject):
"""Returns the text in :attr:`description` from a given :class:`telegram.MessageEntity` of
:attr:`description_entities`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Note:
This method is present because Telegram calculates the offset and length in
@@ -1227,7 +1159,7 @@ class Poll(TelegramObject):
It contains entities from this polls description filtered by their ``type`` attribute as
the key, and the text that each entity belongs to as the value of the :obj:`dict`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Note:
This method should always be used instead of the :attr:`description_entities`
@@ -1249,25 +1181,6 @@ class Poll(TelegramObject):
return parse_message_entities(self.description, self.description_entities, types)
@property
def correct_option_id(self) -> int | None:
"""A zero based identifier of the correct answer
option. Available only for closed polls in the quiz mode, which were sent
(not forwarded), by the bot or to a private chat with the bot.
.. deprecated:: NEXT.VERSION
Use :attr:`correct_option_ids` instead.
"""
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"The attribute `correct_option_id` is deprecated. "
"Use `correct_option_ids` instead.",
),
stacklevel=2,
)
return self.correct_option_ids[0] if self.correct_option_ids else None
REGULAR: Final[str] = constants.PollType.REGULAR
""":const:`telegram.constants.PollType.REGULAR`"""
QUIZ: Final[str] = constants.PollType.QUIZ
@@ -1325,10 +1238,10 @@ class Poll(TelegramObject):
MAX_DESCRIPTION_CHARACTERS: Final[int] = constants.PollLimit.MAX_DESCRIPTION_CHARACTERS
""":const:`telegram.constants.PollLimit.MAX_DESCRIPTION_CHARACTERS`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
MIN_MEMBERSHIP_HOURS: Final[int] = constants.PollLimit.MIN_MEMBERSHIP_HOURS
""":const:`telegram.constants.PollLimit.MIN_MEMBERSHIP_HOURS`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
+1 -1
View File
@@ -31,7 +31,7 @@ class PreparedKeyboardButton(TelegramObject):
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:: NEXT.VERSION
.. versionadded:: 22.8
Args:
id (:obj:`str`): Unique identifier of the keyboard button.
+4 -4
View File
@@ -118,7 +118,7 @@ class ExternalReplyInfo(TelegramObject):
live_photo (:class:`telegram.LivePhoto`, optional): Message is a live photo, information
about the live photo.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
origin (:class:`telegram.MessageOrigin`): Origin of the message replied to by the given
@@ -174,7 +174,7 @@ class ExternalReplyInfo(TelegramObject):
live_photo (:class:`telegram.LivePhoto`): Optional. Message is a live photo, information
about the live photo.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
@@ -427,7 +427,7 @@ class ReplyParameters(TelegramObject):
poll_option_id (:obj:`str`, optional): Persistent
identifier of the specific poll option to be replied to.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
message_id (:obj:`int`): Identifier of the message that will be replied to in the current
@@ -458,7 +458,7 @@ class ReplyParameters(TelegramObject):
poll_option_id (:obj:`str`): Optional. Persistent
identifier of the specific poll option to be replied to.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = (
+1 -1
View File
@@ -28,7 +28,7 @@ class SentGuestMessage(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`inline_message_id` are equal.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
inline_message_id (:obj:`str`): Identifier of the sent inline message.
+10 -10
View File
@@ -167,12 +167,12 @@ class Update(TelegramObject):
managed_bot (:class:`telegram.ManagedBotUpdated`, optional): A new bot was created to be
managed by the bot, or token or owner of a managed bot was changed.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
guest_message (:class:`telegram.Message`, optional): New guest message. The bot can use
the field :attr:`telegram.Message.guest_query_id` and the method
:meth:`telegram.Bot.answer_guest_query` to send a message in response.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
@@ -289,12 +289,12 @@ class Update(TelegramObject):
managed_bot (:class:`telegram.ManagedBotUpdated`): Optional. A new bot was created to be
managed by the bot, or token or owner of a managed bot was changed.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
guest_message (:class:`telegram.Message`): Optional. New guest message. The bot can use
the field :attr:`telegram.Message.guest_query_id` and the method
:meth:`telegram.Bot.answerGuestQuery` to send a message in response.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = (
@@ -428,12 +428,12 @@ class Update(TelegramObject):
MANAGED_BOT: Final[str] = constants.UpdateType.MANAGED_BOT
""":const:`telegram.constants.UpdateType.MANAGED_BOT`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
GUEST_MESSAGE: Final[str] = constants.UpdateType.GUEST_MESSAGE
""":const:`telegram.constants.UpdateType.GUEST_MESSAGE`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
ALL_TYPES: Final[list[str]] = list(constants.UpdateType)
@@ -533,7 +533,7 @@ class Update(TelegramObject):
.. versionchanged:: 21.6
This property now also considers :attr:`purchased_paid_media`.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This property now also considers :attr:`managed_bot`, :attr:`guest_message`,
:attr:`channel_post`, and :attr:`edited_channel_post`.
@@ -626,7 +626,7 @@ class Update(TelegramObject):
is present.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This property now also considers :attr:`guest_message`.
Example:
@@ -683,7 +683,7 @@ class Update(TelegramObject):
This property now also considers :attr:`business_message`,
:attr:`edited_business_message`, and :attr:`deleted_business_messages`.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This property now also considers :attr:`guest_message`.
Example:
@@ -747,7 +747,7 @@ class Update(TelegramObject):
This property now also considers :attr:`business_message`, and
:attr:`edited_business_message`.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This property now also considers :attr:`guest_message`.
Tip:
+12 -15
View File
@@ -28,7 +28,6 @@ from telegram._menubutton import MenuButton
from telegram._telegramobject import TelegramObject
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import (
CorrectOptionID,
CorrectOptionIds,
JSONDict,
ODVInput,
@@ -132,12 +131,12 @@ class User(TelegramObject):
can_manage_bots (:obj:`bool`, optional): :obj:`True`, if other bots can be created to be
controlled by the bot. Returned only in :meth:`telegram.Bot.get_me`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
supports_guest_queries (:obj:`bool`, optional): :obj:`True`, if the bot supports guest
queries from chats it is not a member of. Returned only in
:meth:`telegram.Bot.get_me`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Attributes:
id (:obj:`int`): Unique identifier for this user or bot.
@@ -181,12 +180,12 @@ class User(TelegramObject):
can_manage_bots (:obj:`bool`): Optional. :obj:`True`, if other bots can be created to be
controlled by the bot. Returned only in :meth:`telegram.Bot.get_me`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
supports_guest_queries (:obj:`bool`): Optional. :obj:`True`, if the bot supports guest
queries from chats it is not a member of. Returned only in
:meth:`telegram.Bot.get_me`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
.. |user_chat_id_note| replace:: This shortcuts build on the assumption that :attr:`User.id`
coincides with the :attr:`Chat.id` of the private chat with the user. This has been the
@@ -567,7 +566,7 @@ class User(TelegramObject):
.. versionadded:: 22.6
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
Bot API 10.0 makes the ``text`` argument optional.
Returns:
@@ -756,7 +755,7 @@ class User(TelegramObject):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_live_photo`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Note:
|user_chat_id_note|
@@ -1818,7 +1817,6 @@ class User(TelegramObject):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: CorrectOptionID | None = None,
is_closed: bool | None = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "ReplyMarkup | None" = None,
@@ -1876,7 +1874,6 @@ class User(TelegramObject):
is_anonymous=is_anonymous,
type=type, # pylint=pylint,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
correct_option_ids=correct_option_ids,
@@ -2859,7 +2856,7 @@ class User(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.replace_managed_bot_token`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:obj:`str`: On success, :obj:`str` is returned.
@@ -2893,7 +2890,7 @@ class User(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.get_managed_bot_access_settings`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:class:`telegram.BotAccessSettings`: On success, returns the access settings of the bot
@@ -2931,7 +2928,7 @@ class User(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.set_managed_bot_access_settings`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -2972,7 +2969,7 @@ class User(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_message_reaction`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@@ -3010,7 +3007,7 @@ class User(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.get_user_personal_chat_messages`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
tuple[:class:`telegram.Message`]: On success, a tuple of messages from the personal
@@ -3050,7 +3047,7 @@ class User(TelegramObject):
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_all_message_reactions`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
+1 -3
View File
@@ -91,11 +91,9 @@ HTTPVersion: TypeAlias = Literal["1.1", "2.0", "2"]
.. versionadded:: 20.4"""
CorrectOptionID: TypeAlias = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # pylint: disable=invalid-name
CorrectOptionIds: TypeAlias = Sequence[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]]
"""
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
MarkdownVersion: TypeAlias = Literal[1, 2]
+1 -1
View File
@@ -51,6 +51,6 @@ class Version(NamedTuple):
__version_info__: Final[Version] = Version(
major=22, minor=7, micro=0, releaselevel="final", serial=0
major=22, minor=8, micro=0, releaselevel="final", serial=0
)
__version__: Final[str] = str(__version_info__)
+18 -18
View File
@@ -1527,7 +1527,7 @@ class BaseInputMediaType(StringEnum):
:class:`telegram.InputPollMedia` and :class:`telegram.InputPollOptionMedia`. The enum
members of this enumeration are instances of :class:`str` and can be treated as such.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = ()
@@ -1556,7 +1556,7 @@ class InputMediaType(StringEnum):
"""This enum contains the available types of :class:`telegram.InputMedia`. The enum
members of this enumeration are instances of :class:`str` and can be treated as such.
.. deprecated:: NEXT.VERSION
.. deprecated:: 22.8
Use :class:`telegram.constants.BaseInputMediaType` instead.
.. versionadded:: 20.0
@@ -1577,7 +1577,7 @@ class InputMediaType(StringEnum):
LIVE_PHOTO = "live_photo"
""":obj:`str`: Type of :class:`telegram.InputMediaLivePhoto`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
@@ -1597,7 +1597,7 @@ class InputPaidMediaType(StringEnum):
LIVE_PHOTO = "live_photo"
""":obj:`str`: Type of :class:`telegram.InputPaidMediaLivePhoto`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
@@ -2014,7 +2014,7 @@ class MessageAttachmentType(StringEnum):
LIVE_PHOTO = "live_photo"
""":obj:`str`: Messages with :attr:`telegram.Message.live_photo`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
LOCATION = "location"
""":obj:`str`: Messages with :attr:`telegram.Message.location`."""
@@ -2401,7 +2401,7 @@ class MessageType(StringEnum):
LIVE_PHOTO = "live_photo"
""":obj:`str`: Messages with :attr:`telegram.Message.live_photo`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
LOCATION = "location"
""":obj:`str`: Messages with :attr:`telegram.Message.location`."""
@@ -2430,12 +2430,12 @@ class MessageType(StringEnum):
POLL_OPTION_ADDED = "poll_option_added"
""":obj:`str`: Messages with :attr:`telegram.Message.poll_option_added`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
POLL_OPTION_DELETED = "poll_option_deleted"
""":obj:`str`: Messages with :attr:`telegram.Message.poll_option_deleted`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
SUGGESTED_POST_APPROVAL_FAILED = "suggested_post_approval_failed"
""":obj:`str`: Messages with :attr:`telegram.Message.suggested_post_approval_failed`.
@@ -2627,7 +2627,7 @@ class PaidMediaType(StringEnum):
LIVE_PHOTO = "live_photo"
""":obj:`str`: The type of :class:`telegram.PaidMediaLivePhoto`
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
@@ -2636,7 +2636,7 @@ class PersonalChatMessagesLimit(IntEnum):
:paramref:`telegram.Bot.get_user_personal_chat_messages.limit`.
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = ()
@@ -3512,7 +3512,7 @@ class PollLimit(IntEnum):
to the :paramref:`~telegram.Bot.send_poll.options` parameter of
:meth:`telegram.Bot.send_poll`.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
Bot API 10.0 decreased this value from ``2`` to ``1``.
"""
MAX_OPTION_NUMBER = 12
@@ -3545,27 +3545,27 @@ class PollLimit(IntEnum):
Also used in the :paramref:`~telegram.Bot.send_poll.close_date` parameter of
:meth:`telegram.Bot.send_poll`.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
Changed from ``600`` to ``2628000`` since Bot API 9.6.
"""
MAX_DESCRIPTION_CHARACTERS = 1024
""":obj:`int`: Maximum value allowed for the
:paramref:`~telegram.Bot.send_poll.description` parameter of :meth:`telegram.Bot.send_poll`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
MIN_MEMBERSHIP_HOURS = 24
""":obj:`int`: Minimum number of hours a user must have been a member of the chat
before they can vote in a members-only poll.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
MAX_COUNTRY_CODES = 12
""":obj:`int`: Maximum number of two-letter ``ISO 3166-1 alpha-2`` country codes passed in a
:obj:`list` to the :paramref:`~telegram.Bot.send_poll.country_codes` parameter of
:meth:`telegram.Bot.send_poll`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
@@ -3719,12 +3719,12 @@ class UpdateType(StringEnum):
MANAGED_BOT = "managed_bot"
""":obj:`str`: Updates with :attr:`telegram.Update.managed_bot`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
GUEST_MESSAGE = "guest_message"
""":obj:`str`: Updates with :attr:`telegram.Update.guest_message`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
@@ -4149,7 +4149,7 @@ class ManagedBotAccessLimit(IntEnum):
"""This enum contains limitations for :meth:`~telegram.Bot.set_managed_bot_access_settings`.
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
__slots__ = ()
-3
View File
@@ -101,7 +101,6 @@ from telegram._utils.logging import get_logger
from telegram._utils.repr import build_repr_with_selected_attrs
from telegram._utils.types import (
BaseUrl,
CorrectOptionID,
CorrectOptionIds,
FileInput,
JSONDict,
@@ -3269,7 +3268,6 @@ class ExtBot(Bot, Generic[RLARGS]):
is_anonymous: bool | None = None,
type: str | None = None, # pylint: disable=redefined-builtin
allows_multiple_answers: bool | None = None,
correct_option_id: CorrectOptionID | None = None,
is_closed: bool | None = None,
disable_notification: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "ReplyMarkup | None" = None,
@@ -3315,7 +3313,6 @@ class ExtBot(Bot, Generic[RLARGS]):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
is_closed=is_closed,
disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id,
@@ -34,7 +34,7 @@ class ManagedBotUpdatedHandler(BaseHandler[Update, CCT, RT]):
"""Handler class to handle
:attr:`updated Telegram Managed Bots <telegram.Update.managed_bot>`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
Args:
callback (:term:`coroutine function`): The callback function for this handler. Will be
+8
View File
@@ -26,6 +26,7 @@ Warning:
the changelog.
"""
import sys
from collections import UserDict
from collections.abc import Mapping
from typing import Final, Generic, TypeVar
@@ -111,6 +112,13 @@ class TrackingDict(UserDict, Generic[_KT, _VT]):
return super().pop(key)
return super().pop(key, default)
# Python 3.15 added a popitem() to UserDict, which does LIFO instead of the FIFO behaviour
# of MutableMapping.popitem(). So we keep it consistent across versions by overriding here.
if sys.version_info >= (3, 15):
def popitem(self) -> tuple[_KT, _VT]:
return super(UserDict, self).popitem()
def clear(self) -> None:
self.__track_write(set(super().keys()))
super().clear()
+5 -5
View File
@@ -274,7 +274,7 @@ class BaseFilter:
:attr:`~telegram.Update.business_message`
or :attr:`~telegram.Update.edited_business_message`.
.. versionchanged:: NEXT.VERSION
.. versionchanged:: 22.8
This filter now also returns :obj:`True` if the update contains
:attr:`~telegram.Update.guest_message`.
@@ -1668,7 +1668,7 @@ class _LivePhoto(MessageFilter):
LIVE_PHOTO = _LivePhoto(name="filters.LIVE_PHOTO")
"""Messages that contain :attr:`telegram.Message.live_photo`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
@@ -2374,7 +2374,7 @@ class StatusUpdate:
POLL_OPTION_ADDED = _PollOptionAdded(name="filters.StatusUpdate.POLL_OPTION_ADDED")
"""Messages that contain :attr:`telegram.Message.poll_option_added`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
class _PollOptionDeleted(MessageFilter):
@@ -2385,7 +2385,7 @@ class StatusUpdate:
POLL_OPTION_DELETED = _PollOptionDeleted(name="filters.StatusUpdate.POLL_OPTION_DELETED")
"""Messages that contain :attr:`telegram.Message.poll_option_deleted`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
class _ProximityAlertTriggered(MessageFilter):
@@ -2924,7 +2924,7 @@ class UpdateType:
GUEST_MESSAGE = _GuestMessage(name="filters.UpdateType.GUEST_MESSAGE")
"""Updates with :attr:`telegram.Update.guest_message`.
.. versionadded:: NEXT.VERSION
.. versionadded:: 22.8
"""
+1 -1
View File
@@ -24,11 +24,11 @@ from collections.abc import Sequence
from dataclasses import dataclass
from typing import final
from telegram._files._inputstorycontent import InputStoryContent
from telegram._files.inputfile import InputFile
from telegram._files.inputmedia import InputMedia, InputPaidMedia
from telegram._files.inputprofilephoto import InputProfilePhoto, InputProfilePhotoStatic
from telegram._files.inputsticker import InputSticker
from telegram._files.inputstorycontent import InputStoryContent
from telegram._telegramobject import TelegramObject
from telegram._utils.datetime import to_timestamp
from telegram._utils.enum import StringEnum
+7 -1
View File
@@ -671,7 +671,13 @@ class TestFilters:
assert not filters.Document.AUDIO.check_update(update)
update.message.document.mime_type = "application/octet-stream"
assert filters.Document.EXE.check_update(update)
# Python 3.15 changes the "exe" mime type to application/vnd.microsoft.portable-executable
if int(platform.python_version_tuple()[1]) <= 14:
assert filters.Document.EXE.check_update(update)
else:
assert not filters.Document.EXE.check_update(update)
update.message.document.mime_type = "application/vnd.microsoft.portable-executable"
assert filters.Document.EXE.check_update(update)
assert filters.Document.APPLICATION.check_update(update)
assert not filters.Document.DOCX.check_update(update)
assert not filters.Document.AUDIO.check_update(update)
+5 -39
View File
@@ -105,7 +105,7 @@ from telegram.error import BadRequest, EndPointNotFound, InvalidToken, TimedOut
from telegram.ext import ExtBot, InvalidCallbackData
from telegram.helpers import escape_markdown
from telegram.request import BaseRequest, HTTPXRequest, RequestData
from telegram.warnings import PTBDeprecationWarning, PTBUserWarning
from telegram.warnings import PTBUserWarning
from tests.auxil.bot_method_checks import check_defaults_handling
from tests.auxil.ci_bots import FALLBACKS
from tests.auxil.envvars import GITHUB_ACTIONS
@@ -3003,40 +3003,6 @@ class TestBotWithoutRequest:
await offline_bot.set_chat_member_tag(1234, 5678, "This is a tag")
async def test_send_poll_warn_correct_option_id(self, offline_bot, monkeypatch, recwarn):
async def make_first_assert(url, request_data: RequestData, *args, **kwargs):
assert request_data.parameters.get("correct_option_ids") == [1]
assert request_data.parameters.get("correct_option_id") is None
return make_message("dummy reply").to_dict()
async def make_second_assert(url, request_data: RequestData, *args, **kwargs):
assert request_data.parameters.get("correct_option_ids") == [1, 2]
assert request_data.parameters.get("correct_option_id") is None
return make_message("dummy reply").to_dict()
monkeypatch.setattr(offline_bot.request, "post", make_first_assert)
await offline_bot.send_poll(
1,
question="question",
options=["option1", "option2"],
correct_option_id=1,
)
w = recwarn.pop()
assert issubclass(w.category, PTBDeprecationWarning)
assert "correct_option_id" in str(w.message)
# Test that correct_option_ids takes priority when both correct_option_id(s) are given
monkeypatch.setattr(offline_bot.request, "post", make_second_assert)
assert await offline_bot.send_poll(
1,
question="question",
options=["option1", "option2"],
correct_option_id=1,
correct_option_ids=[1, 2],
)
# TODO: If we create a managed bot, we could test this for real
async def test_get_managed_bot_token(self, offline_bot, monkeypatch):
@@ -3349,7 +3315,7 @@ class TestBotWithRequest:
question=question,
options=answers,
type=Poll.QUIZ,
correct_option_id=2,
correct_option_ids=[2],
is_closed=True,
explanation=explanation,
explanation_parse_mode=ParseMode.MARKDOWN_V2,
@@ -3388,7 +3354,7 @@ class TestBotWithRequest:
assert poll.total_voter_count == 0
message_quiz = await quiz_task
assert message_quiz.poll.correct_option_id == 2
assert message_quiz.poll.correct_option_ids == (2,)
assert message_quiz.poll.type == Poll.QUIZ
assert message_quiz.poll.is_closed
assert message_quiz.poll.explanation == "Here is a link"
@@ -3475,7 +3441,7 @@ class TestBotWithRequest:
chat_id,
"question",
options=["a", "b"],
correct_option_id=0,
correct_option_ids=[0],
type=Poll.QUIZ,
explanation=test_string,
explanation_entities=entities,
@@ -3526,7 +3492,7 @@ class TestBotWithRequest:
question=question,
options=answers,
type=Poll.QUIZ,
correct_option_id=2,
correct_option_ids=[2],
is_closed=True,
explanation=explanation_markdown,
**i,
+1 -1
View File
@@ -33,7 +33,7 @@ from telegram import (
StoryAreaTypeUniqueGift,
User,
)
from telegram._files._inputstorycontent import InputStoryContentVideo
from telegram._files.inputstorycontent import InputStoryContentVideo
from telegram._files.sticker import Sticker
from telegram._gifts import AcceptedGiftTypes, Gift
from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton
-12
View File
@@ -684,18 +684,6 @@ class TestChatMemberRestrictedWithoutRequest(ChatMemberTestBase):
"tag": chat_member_restricted.tag,
}
def test_can_react_to_messages_raises(self, chat_member_restricted):
with pytest.raises(
TypeError, match="`can_react_to_messages` is required and cannot be None"
):
ChatMemberRestricted(
*[
getattr(chat_member_restricted, k)
for k in chat_member_restricted.__slots__
if k != "can_react_to_messages"
]
)
def test_equality(self, chat_member_restricted):
a = chat_member_restricted
b = deepcopy(chat_member_restricted)
+2 -15
View File
@@ -86,10 +86,7 @@ class ParamTypeCheckingExceptions:
# too complex to compare/predict with official API
# structure: class/method_name: {param_name: reduced form of annotation}
COMPLEX_TYPES = {
"send_poll": {
# "correct_option_id": int,
"correct_option_ids": Sequence[int]
},
"send_poll": {"correct_option_ids": Sequence[int]},
"get_file": {
"file_id": str, # actual: Union[str, objs_with_file_id_attr]
},
@@ -185,10 +182,6 @@ PTB_EXTRA_PARAMS = {
"InputProfilePhoto": {"type"}, # attributes common to all subclasses
"InputPollOptionMedia": {"args", "kwargs"}, # UnionType's __init__ signature
"InputPollMedia": {"args", "kwargs"}, # UnionType's __init__ signature
# backwards compatibility for api 10.0 changes
# tags: deprecated NEXT.VERSION, bot api 10.0
"Poll": {"correct_option_id"},
"send_poll": {"correct_option_id"},
}
@@ -244,13 +237,7 @@ def ignored_param_requirements(object_name: str) -> set[str]:
# Arguments that are optional arguments for now for backwards compatibility
BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {
"PollOption": {"persistent_id"},
"PollAnswer": {"option_persistent_ids"},
"Poll": {"allows_revoting", "members_only"},
"ChatMemberRestricted": {"can_react_to_messages"},
"send_poll": {"correct_option_id"},
}
BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {}
def backwards_compat_kwargs(object_name: str) -> set[str]:
+1
View File
@@ -109,6 +109,7 @@ def cached_type_hints(obj: Any, is_class: bool) -> dict[str, Any]:
@functools.cache
def resolve_forward_refs_in_type(obj: type) -> type:
"""Resolves forward references in a type hint."""
# TODO: Refactor test_official to properly use annotationlib
return _eval_type(obj, localns=tg_objects, globalns=None)
+4
View File
@@ -17,10 +17,14 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import inspect
import platform
from typing import TYPE_CHECKING
import pytest
if platform.python_version_tuple() >= ("3", "15"):
pytest.skip("Running on Python version > 3.15 is not supported yet!", allow_module_level=True)
import telegram
from tests.auxil.envvars import RUN_TEST_OFFICIAL
from tests.test_official.arg_type_checker import (
+6 -94
View File
@@ -78,30 +78,6 @@ class TestInputPollOptionWithoutRequest(InputPollOptionTestBase):
"duplicate slot"
)
# tags: deprecated NEXT.VERSION
def test_de_json(self):
json_dict = {
"text": self.text,
"text_parse_mode": self.text_parse_mode,
"text_entities": [e.to_dict() for e in self.text_entities],
}
input_poll_option = InputPollOption.de_json(json_dict, None)
assert input_poll_option.api_kwargs == {}
assert input_poll_option.text == self.text
assert input_poll_option.text_parse_mode == self.text_parse_mode
assert input_poll_option.text_entities == tuple(self.text_entities)
def test_de_json_deprecated(self, recwarn):
InputPollOption.de_json({"text": self.text}, None)
assert len(recwarn) == 1
assert "`InputPollOption.de_json` is deprecated" in str(recwarn[0].message)
assert "The `media` field will not be included for deserialization" in str(
recwarn[0].message
)
assert recwarn[0].category is PTBDeprecationWarning
def test_to_dict(self, input_poll_option):
input_poll_option_dict = input_poll_option.to_dict()
@@ -343,11 +319,6 @@ class TestPollOptionWithoutRequest(PollOptionTestBase):
assert poll_option.parse_entities(MessageEntity.BOLD) == {entity: "test"}
assert poll_option.parse_entities() == {entity: "test", entity_2: "option"}
def test_persistent_id_required_workaround(self):
# tags: deprecated NEXT.VERSION, bot api 9.6
with pytest.raises(TypeError, match="`persistent_id` is a required"):
PollOption(self.text, self.voter_count)
def test_equality(self):
a = PollOption("text", 1, persistent_id="persistent_id")
b = PollOption("text", 1, persistent_id="persistent_id")
@@ -388,9 +359,9 @@ def poll_answer():
return PollAnswer(
PollAnswerTestBase.poll_id,
PollAnswerTestBase.option_ids,
PollAnswerTestBase.option_persistent_ids,
PollAnswerTestBase.user,
PollAnswerTestBase.voter_chat,
PollAnswerTestBase.option_persistent_ids,
)
@@ -430,19 +401,12 @@ class TestPollAnswerWithoutRequest(PollAnswerTestBase):
assert poll_answer_dict["voter_chat"] == poll_answer.voter_chat.to_dict()
assert poll_answer_dict["option_persistent_ids"] == list(poll_answer.option_persistent_ids)
def test_persistent_id_required_workaround(self):
# tags: deprecated NEXT.VERSION, bot api 9.6
with pytest.raises(TypeError, match="`option_persistent_ids` is a required"):
PollAnswer(poll_id=123, option_ids=[2], user=self.user, voter_chat=self.voter_chat)
def test_equality(self):
a = PollAnswer(123, [2], self.user, self.voter_chat, option_persistent_ids=["2"])
b = PollAnswer(123, [2], self.user, Chat(1, ""), option_persistent_ids=["2"])
c = PollAnswer(
123, [2], User(1, "first", False), self.voter_chat, option_persistent_ids=["2"]
)
d = PollAnswer(123, [1, 2], self.user, self.voter_chat, option_persistent_ids=["1", "2"])
e = PollAnswer(456, [2], self.user, self.voter_chat, option_persistent_ids=["2"])
a = PollAnswer(123, [2], ["2"], self.user, self.voter_chat)
b = PollAnswer(123, [2], ["2"], self.user, Chat(1, ""))
c = PollAnswer(123, [2], ["2"], User(1, "first", False), self.voter_chat)
d = PollAnswer(123, [1, 2], ["1", "2"], self.user, self.voter_chat)
e = PollAnswer(456, [2], ["2"], self.user, self.voter_chat)
f = PollOption("Text", 1, persistent_id="persistent_id")
assert a == b
@@ -663,58 +627,6 @@ class TestPollWithoutRequest(PollTestBase):
assert "`open_period` will be of type `datetime.timedelta`" in str(recwarn[0].message)
assert recwarn[0].category is PTBDeprecationWarning
def test_correct_option_id_deprecated(self, recwarn, poll):
poll.correct_option_id
assert len(recwarn) == 1
assert "The attribute `correct_option_id` is deprecated" in str(recwarn[0].message)
assert recwarn[0].category is PTBDeprecationWarning
poll = Poll(
PollTestBase.id_,
PollTestBase.question,
PollTestBase.options,
PollTestBase.total_voter_count,
PollTestBase.is_closed,
PollTestBase.is_anonymous,
PollTestBase.type,
PollTestBase.allows_multiple_answers,
correct_option_id=1,
allows_revoting=PollTestBase.allows_revoting,
members_only=PollTestBase.members_only,
)
assert poll.correct_option_ids == (1,)
def test_allows_revoting_required_workaround(self):
# tags: deprecated NEXT.VERSION, bot api 9.6
with pytest.raises(TypeError, match="`allows_revoting` is a required"):
Poll(
self.id_,
self.question,
self.options,
self.total_voter_count,
self.is_closed,
self.is_anonymous,
self.type,
self.allows_multiple_answers,
members_only=self.members_only,
)
def test_members_only_required_workaround(self):
# tags: deprecated NEXT.VERSION, bot api 10.0
with pytest.raises(TypeError, match="`members_only` is a required"):
Poll(
self.id_,
self.question,
self.options,
self.total_voter_count,
self.is_closed,
self.is_anonymous,
self.type,
self.allows_multiple_answers,
allows_revoting=self.allows_revoting,
)
def test_equality(self):
a = Poll(
123,
Generated
+82 -82
View File
@@ -500,62 +500,62 @@ toml = [
[[package]]
name = "cryptography"
version = "46.0.7"
version = "48.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9f/a9/db8f313fdcd85d767d4973515e1db101f9c71f95fced83233de224673757/cryptography-48.0.0.tar.gz", hash = "sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920", size = 832984, upload-time = "2026-05-04T22:59:38.133Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" },
{ url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" },
{ url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" },
{ url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" },
{ url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" },
{ url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" },
{ url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" },
{ url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" },
{ url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" },
{ url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" },
{ url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" },
{ url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" },
{ url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" },
{ url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" },
{ url = "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", size = 7119671, upload-time = "2026-04-08T01:56:44Z" },
{ url = "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", size = 4268551, upload-time = "2026-04-08T01:56:46.071Z" },
{ url = "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", size = 4408887, upload-time = "2026-04-08T01:56:47.718Z" },
{ url = "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", size = 4271354, upload-time = "2026-04-08T01:56:49.312Z" },
{ url = "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", size = 4905845, upload-time = "2026-04-08T01:56:50.916Z" },
{ url = "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", size = 4444641, upload-time = "2026-04-08T01:56:52.882Z" },
{ url = "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", size = 3967749, upload-time = "2026-04-08T01:56:54.597Z" },
{ url = "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", size = 4270942, upload-time = "2026-04-08T01:56:56.416Z" },
{ url = "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", size = 4871079, upload-time = "2026-04-08T01:56:58.31Z" },
{ url = "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", size = 4443999, upload-time = "2026-04-08T01:57:00.508Z" },
{ url = "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", size = 4399191, upload-time = "2026-04-08T01:57:02.654Z" },
{ url = "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", size = 4655782, upload-time = "2026-04-08T01:57:04.592Z" },
{ url = "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", size = 3002227, upload-time = "2026-04-08T01:57:06.91Z" },
{ url = "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", size = 3475332, upload-time = "2026-04-08T01:57:08.807Z" },
{ url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" },
{ url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" },
{ url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" },
{ url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" },
{ url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" },
{ url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" },
{ url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" },
{ url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" },
{ url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" },
{ url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" },
{ url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" },
{ url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" },
{ url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" },
{ url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" },
{ url = "https://files.pythonhosted.org/packages/63/0c/dca8abb64e7ca4f6b2978769f6fea5ad06686a190cec381f0a796fdcaaba/cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f", size = 3476879, upload-time = "2026-04-08T01:57:38.664Z" },
{ url = "https://files.pythonhosted.org/packages/3a/ea/075aac6a84b7c271578d81a2f9968acb6e273002408729f2ddff517fed4a/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15", size = 4219700, upload-time = "2026-04-08T01:57:40.625Z" },
{ url = "https://files.pythonhosted.org/packages/6c/7b/1c55db7242b5e5612b29fc7a630e91ee7a6e3c8e7bf5406d22e206875fbd/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455", size = 4385982, upload-time = "2026-04-08T01:57:42.725Z" },
{ url = "https://files.pythonhosted.org/packages/cb/da/9870eec4b69c63ef5925bf7d8342b7e13bc2ee3d47791461c4e49ca212f4/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65", size = 4219115, upload-time = "2026-04-08T01:57:44.939Z" },
{ url = "https://files.pythonhosted.org/packages/f4/72/05aa5832b82dd341969e9a734d1812a6aadb088d9eb6f0430fc337cc5a8f/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968", size = 4385479, upload-time = "2026-04-08T01:57:46.86Z" },
{ url = "https://files.pythonhosted.org/packages/20/2a/1b016902351a523aa2bd446b50a5bc1175d7a7d1cf90fe2ef904f9b84ebc/cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4", size = 3412829, upload-time = "2026-04-08T01:57:48.874Z" },
{ url = "https://files.pythonhosted.org/packages/df/3d/01f6dd9190170a5a241e0e98c2d04be3664a9e6f5b9b872cde63aff1c3dd/cryptography-48.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6", size = 8001587, upload-time = "2026-05-04T22:57:36.803Z" },
{ url = "https://files.pythonhosted.org/packages/b2/6e/e90527eef33f309beb811cf7c982c3aeffcce8e3edb178baa4ca3ae4a6fa/cryptography-48.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c", size = 4690433, upload-time = "2026-05-04T22:57:40.373Z" },
{ url = "https://files.pythonhosted.org/packages/90/04/673510ed51ddff56575f306cf1617d80411ee76831ccd3097599140efdfe/cryptography-48.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3", size = 4710620, upload-time = "2026-05-04T22:57:42.935Z" },
{ url = "https://files.pythonhosted.org/packages/14/d5/e9c4ef932c8d800490c34d8bd589d64a31d5890e27ec9e9ad532be893294/cryptography-48.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5", size = 4696283, upload-time = "2026-05-04T22:57:45.294Z" },
{ url = "https://files.pythonhosted.org/packages/0c/29/174b9dfb60b12d59ecfc6cfa04bc88c21b42a54f01b8aae09bb6e51e4c7f/cryptography-48.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c", size = 5296573, upload-time = "2026-05-04T22:57:47.933Z" },
{ url = "https://files.pythonhosted.org/packages/95/38/0d29a6fd7d0d1373f0c0c88a04ba20e359b257753ac497564cd660fc1d55/cryptography-48.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f", size = 4743677, upload-time = "2026-05-04T22:57:50.067Z" },
{ url = "https://files.pythonhosted.org/packages/30/be/eef653013d5c63b6a490529e0316f9ac14a37602965d4903efed1399f32b/cryptography-48.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25", size = 4330808, upload-time = "2026-05-04T22:57:52.301Z" },
{ url = "https://files.pythonhosted.org/packages/84/9e/500463e87abb7a0a0f9f256ec21123ecde0a7b5541a15e840ea54551fd81/cryptography-48.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602", size = 4695941, upload-time = "2026-05-04T22:57:54.603Z" },
{ url = "https://files.pythonhosted.org/packages/e3/dc/7303087450c2ec9e7fbb750e17c2abfbc658f23cbd0e54009509b7cc4091/cryptography-48.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c", size = 5252579, upload-time = "2026-05-04T22:57:57.207Z" },
{ url = "https://files.pythonhosted.org/packages/d0/c0/7101d3b7215edcdc90c45da544961fd8ed2d6448f77577460fa75a8443f7/cryptography-48.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5", size = 4743326, upload-time = "2026-05-04T22:57:59.535Z" },
{ url = "https://files.pythonhosted.org/packages/ac/d8/5b833bad13016f562ab9d063d68199a4bd121d18458e439515601d3357ec/cryptography-48.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321", size = 4826672, upload-time = "2026-05-04T22:58:01.996Z" },
{ url = "https://files.pythonhosted.org/packages/98/e1/7074eb8bf3c135558c73fc2bcf0f5633f912e6fb87e868a55c454080ef09/cryptography-48.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74", size = 4972574, upload-time = "2026-05-04T22:58:03.968Z" },
{ url = "https://files.pythonhosted.org/packages/04/70/e5a1b41d325f797f39427aa44ef8baf0be500065ab6d8e10369d850d4a4f/cryptography-48.0.0-cp311-abi3-win32.whl", hash = "sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4", size = 3294868, upload-time = "2026-05-04T22:58:06.467Z" },
{ url = "https://files.pythonhosted.org/packages/f4/ac/8ac51b4a5fc5932eb7ee5c517ba7dc8cd834f0048962b6b352f00f41ebf9/cryptography-48.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7", size = 3817107, upload-time = "2026-05-04T22:58:08.845Z" },
{ url = "https://files.pythonhosted.org/packages/6b/84/70e3feea9feea87fd7cbe77efb2712ae1e3e6edf10749dc6e95f4e60e455/cryptography-48.0.0-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec", size = 7986556, upload-time = "2026-05-04T22:58:11.172Z" },
{ url = "https://files.pythonhosted.org/packages/89/6e/18e07a618bb5442ba10cf4df16e99c071365528aa570dfcb8c02e25a303b/cryptography-48.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18", size = 4684776, upload-time = "2026-05-04T22:58:13.712Z" },
{ url = "https://files.pythonhosted.org/packages/be/6a/4ea3b4c6c6759794d5ee2103c304a5076dc4b19ae1f9fe47dba439e159e9/cryptography-48.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20", size = 4698121, upload-time = "2026-05-04T22:58:16.448Z" },
{ url = "https://files.pythonhosted.org/packages/2f/59/6ff6ad6cae03bb887da2a5860b2c9805f8dac969ef01ce563336c49bd1d1/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff", size = 4690042, upload-time = "2026-05-04T22:58:18.544Z" },
{ url = "https://files.pythonhosted.org/packages/ca/b4/fc334ed8cfd705aca282fe4d8f5ae64a8e0f74932e9feecb344610cf6e4d/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c", size = 5282526, upload-time = "2026-05-04T22:58:20.75Z" },
{ url = "https://files.pythonhosted.org/packages/11/08/9f8c5386cc4cd90d8255c7cdd0f5baf459a08502a09de30dc51f553d38dc/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db", size = 4733116, upload-time = "2026-05-04T22:58:23.627Z" },
{ url = "https://files.pythonhosted.org/packages/b8/77/99307d7574045699f8805aa500fa0fb83422d115b5400a064ddd306d7750/cryptography-48.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741", size = 4316030, upload-time = "2026-05-04T22:58:25.581Z" },
{ url = "https://files.pythonhosted.org/packages/fd/36/a608b98337af3cb2aff4818e406649d30572b7031918b04c87d979495348/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166", size = 4689640, upload-time = "2026-05-04T22:58:27.747Z" },
{ url = "https://files.pythonhosted.org/packages/dd/a6/825010a291b4438aecc1f568bc428189fc1175515223632477c07dc0a6df/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336", size = 5237657, upload-time = "2026-05-04T22:58:29.848Z" },
{ url = "https://files.pythonhosted.org/packages/b9/09/4e76a09b4caa29aad535ddc806f5d4c5d01885bd978bd984fbc6ca032cae/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057", size = 4732362, upload-time = "2026-05-04T22:58:32.009Z" },
{ url = "https://files.pythonhosted.org/packages/18/78/444fa04a77d0cb95f417dda20d450e13c56ba8e5220fc892a1658f44f882/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae", size = 4819580, upload-time = "2026-05-04T22:58:34.254Z" },
{ url = "https://files.pythonhosted.org/packages/38/85/ea67067c70a1fd4be2c63d35eeed82658023021affccc7b17705f8527dd2/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c", size = 4963283, upload-time = "2026-05-04T22:58:36.376Z" },
{ url = "https://files.pythonhosted.org/packages/75/54/cc6d0f3deac3e81c7f847e8a189a12b6cdd65059b43dad25d4316abd849a/cryptography-48.0.0-cp314-cp314t-win32.whl", hash = "sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f", size = 3270954, upload-time = "2026-05-04T22:58:38.791Z" },
{ url = "https://files.pythonhosted.org/packages/49/67/cc947e288c0758a4e5473d1dcb743037ab7785541265a969240b8885441a/cryptography-48.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12", size = 3797313, upload-time = "2026-05-04T22:58:40.746Z" },
{ url = "https://files.pythonhosted.org/packages/f2/63/61d4a4e1c6b6bab6ce1e213cd36a24c415d90e76d78c5eb8577c5541d2e8/cryptography-48.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86", size = 7983482, upload-time = "2026-05-04T22:58:43.769Z" },
{ url = "https://files.pythonhosted.org/packages/d5/ac/f5b5995b87770c693e2596559ffafe195b4033a57f14a82268a2842953f3/cryptography-48.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e", size = 4683266, upload-time = "2026-05-04T22:58:46.064Z" },
{ url = "https://files.pythonhosted.org/packages/ec/c6/8b14f67e18338fbc4adb76f66c001f5c3610b3e2d1837f268f47a347dbbb/cryptography-48.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f", size = 4696228, upload-time = "2026-05-04T22:58:48.22Z" },
{ url = "https://files.pythonhosted.org/packages/ea/73/f808fbae9514bd91b47875b003f13e284c8c6bdfd904b7944e803937eec1/cryptography-48.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7", size = 4689097, upload-time = "2026-05-04T22:58:50.9Z" },
{ url = "https://files.pythonhosted.org/packages/93/01/d86632d7d28db8ae83221995752eeb6639ffb374c2d22955648cf8d52797/cryptography-48.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832", size = 5283582, upload-time = "2026-05-04T22:58:53.017Z" },
{ url = "https://files.pythonhosted.org/packages/02/e1/50edc7a50334807cc4791fc4a0ce7468b4a1416d9138eab358bfc9a3d70b/cryptography-48.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c", size = 4730479, upload-time = "2026-05-04T22:58:55.611Z" },
{ url = "https://files.pythonhosted.org/packages/6f/af/99a582b1b1641ff5911ac559beb45097cf79efd4ead4657f578ef1af2d47/cryptography-48.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a", size = 4326481, upload-time = "2026-05-04T22:58:57.607Z" },
{ url = "https://files.pythonhosted.org/packages/90/ee/89aa26a06ef0a7d7611788ffd571a7c50e368cc6a4d5eef8b4884e866edb/cryptography-48.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a", size = 4688713, upload-time = "2026-05-04T22:59:00.077Z" },
{ url = "https://files.pythonhosted.org/packages/70/ba/bcb1b0bb7a33d4c7c0c4d4c7874b4a62ae4f56113a5f4baefa362dfb1f0f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a", size = 5238165, upload-time = "2026-05-04T22:59:02.317Z" },
{ url = "https://files.pythonhosted.org/packages/c9/70/ca4003b1ce5ca3dc3186ada51908c8a9b9ff7d5cab83cc0d43ee14ec144f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239", size = 4729947, upload-time = "2026-05-04T22:59:05.255Z" },
{ url = "https://files.pythonhosted.org/packages/44/a0/4ec7cf774207905aef1a8d11c3750d5a1db805eb380ee4e16df317870128/cryptography-48.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c", size = 4822059, upload-time = "2026-05-04T22:59:07.802Z" },
{ url = "https://files.pythonhosted.org/packages/1e/75/a2e55f99c16fcac7b5d6c1eb19ad8e00799854d6be5ca845f9259eae1681/cryptography-48.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4", size = 4960575, upload-time = "2026-05-04T22:59:09.851Z" },
{ url = "https://files.pythonhosted.org/packages/b8/23/6e6f32143ab5d8b36ca848a502c4bcd477ae75b9e1677e3530d669062578/cryptography-48.0.0-cp39-abi3-win32.whl", hash = "sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd", size = 3279117, upload-time = "2026-05-04T22:59:12.019Z" },
{ url = "https://files.pythonhosted.org/packages/9d/9a/0fea98a70cf1749d41d738836f6349d97945f7c89433a259a6c2642eefeb/cryptography-48.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8", size = 3792100, upload-time = "2026-05-04T22:59:14.884Z" },
{ url = "https://files.pythonhosted.org/packages/be/d2/024b5e06be9d44cb021fb0e1a03d34d63989cf56a0fe62f3dfbab695b9b4/cryptography-48.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:84cf79f0dc8b36ac5da873481716e87aef31fcfa0444f9e1d8b4b2cece142855", size = 3950391, upload-time = "2026-05-04T22:59:17.415Z" },
{ url = "https://files.pythonhosted.org/packages/bc/17/3861e17c56fa0fd37491a14a8673fdb77c57fc5693cafe745ea8b06dba75/cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:fdfef35d751d510fcef5252703621574364fec16418c4a1e5e1055248401054b", size = 4637126, upload-time = "2026-05-04T22:59:20.197Z" },
{ url = "https://files.pythonhosted.org/packages/f0/0a/7e226dbff530f21480727eb764973a7bff2b912f8e15cd4f129e71b56d1d/cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:0890f502ddf7d9c6426129c3f49f5c0a39278ed7cd6322c8755ffca6ee675a13", size = 4667270, upload-time = "2026-05-04T22:59:22.647Z" },
{ url = "https://files.pythonhosted.org/packages/3b/f2/5a72274ca9f1b2a8b44a662ee0bf1b435909deb473d6f97bcd035bcdbc71/cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:ecde28a596bead48b0cfd2a1b4416c3d43074c2d785e3a398d7ec1fc4d0f7fbb", size = 4636797, upload-time = "2026-05-04T22:59:24.912Z" },
{ url = "https://files.pythonhosted.org/packages/b4/e1/48cedb2fe63626e91ded1edad159e2a4fb8b6906c4425eb7749673077ce7/cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:4defde8685ae324a9eb9d818717e93b4638ef67070ac9bc15b8ca85f63048355", size = 4666800, upload-time = "2026-05-04T22:59:27.474Z" },
{ url = "https://files.pythonhosted.org/packages/a2/ca/7e8365deec19afb2b2c7be7c1c0aa8f99633b54e90c570999acda93260fc/cryptography-48.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:db63bf618e5dea46c07de12e900fe1cdd2541e6dc9dbae772a70b7d4d4765f6a", size = 3739536, upload-time = "2026-05-04T22:59:29.61Z" },
]
[[package]]
@@ -1651,7 +1651,7 @@ all = [
{ name = "pytest-cov" },
{ name = "pytest-xdist", specifier = "==3.8.0" },
{ name = "pytz" },
{ name = "ruff", specifier = "==0.15.15" },
{ name = "ruff", specifier = "==0.15.16" },
{ name = "sphinx", marker = "python_full_version >= '3.12'", specifier = "==9.1.0" },
{ name = "sphinx-build-compatibility", git = "https://github.com/readthedocs/sphinx-build-compatibility.git?rev=58aabc5f207c6c2421f23d3578adc0b14af57047" },
{ name = "sphinx-copybutton", specifier = "==0.5.2" },
@@ -1675,7 +1675,7 @@ linting = [
{ name = "mypy", specifier = "==1.20.2" },
{ name = "prek" },
{ name = "pylint", specifier = "==4.0.5" },
{ name = "ruff", specifier = "==0.15.15" },
{ name = "ruff", specifier = "==0.15.16" },
]
tests = [
{ name = "beautifulsoup4" },
@@ -1801,27 +1801,27 @@ wheels = [
[[package]]
name = "ruff"
version = "0.15.15"
version = "0.15.16"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/84/6f/a76f7d96e5c962f5b69cee865e49c15c1116897c01990faa8a57edb62e7f/ruff-0.15.15.tar.gz", hash = "sha256:b8dff018130b46d8e5bf0f926ef6b60cf871d6d5ae45fc9334e09632daa741d6", size = 4706985, upload-time = "2026-05-28T14:16:57.784Z" }
sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/5f7ec371001337d8fa61701c186ff8b613ecac1651848c5950f4c4d5f2e9/ruff-0.15.16.tar.gz", hash = "sha256:d05e78d38c78caf020b03789e25106c93017db5a0cb6e2819885018c61343b78", size = 4714267, upload-time = "2026-06-04T16:33:09.974Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/9d/3a45c05b8ab04b4705989de70a79008e27c8003296a0feaee9edc18dd7e9/ruff-0.15.15-py3-none-linux_armv6l.whl", hash = "sha256:cf93e5388f412e1b108b1f8b34a6e036b70fe8aff89393befad96fe48670311b", size = 10710652, upload-time = "2026-05-28T14:16:06.701Z" },
{ url = "https://files.pythonhosted.org/packages/05/66/da974431624bf3b49f6ee1f9543c02d929ff1cba78b0d5a79c38cf21f744/ruff-0.15.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac5a646d1f6a7dadd5d50842dae2c1f9862ac887ef5d1b1375e02def791fde6e", size = 11096615, upload-time = "2026-05-28T14:16:23.313Z" },
{ url = "https://files.pythonhosted.org/packages/8c/09/7443452e5d290230a712103f2fdceeef7184f3ec99a2bd01c8be78aaceb5/ruff-0.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:77d955a431430c66f72dd94e379ad38a16daea3d25094872ac4edf9e797be530", size = 10436683, upload-time = "2026-05-28T14:16:40.974Z" },
{ url = "https://files.pythonhosted.org/packages/53/01/d330c26a57fa4f3943a14424904027428315b700fe4d14a84bb123a649e5/ruff-0.15.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7614ee79c69788cf6cedd568069ade9cecc22a1ad20494efe8d0c9ebb4b622d4", size = 10769064, upload-time = "2026-05-28T14:16:28.905Z" },
{ url = "https://files.pythonhosted.org/packages/1d/85/cc8770f8bdff541b1da8392d1634141fe4a0e3f4ee596605959b7906c27f/ruff-0.15.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cdb1679e06a1f6b47bc384714ae96f6e2fb65ca441eb78c43d2ca554176ce1f", size = 10511987, upload-time = "2026-05-28T14:16:43.732Z" },
{ url = "https://files.pythonhosted.org/packages/7c/29/8c190c1472b63013583ba391f3342036e02010544c1270455ed8e519bdf3/ruff-0.15.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2728b93d7b23a603ea2c0ac6eb73d760bd38ec9de35f35fb41e18f7a3fee7622", size = 11275100, upload-time = "2026-05-28T14:16:55.244Z" },
{ url = "https://files.pythonhosted.org/packages/9f/6b/7e145ce2cc8e63d6834eca03d83a0e18d121def5c69f91b4cf4011ed4879/ruff-0.15.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be582fcc0db438902c7792b08d6ddf6c9b9e21addaa10092c2c741cfb09e5a45", size = 12176903, upload-time = "2026-05-28T14:16:14.368Z" },
{ url = "https://files.pythonhosted.org/packages/80/a3/d5974637f68e451f7fadf015cf3101d1cd7d8ba5027cffe0b9e3826ebe6b/ruff-0.15.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7aa77465b8ecaf1a27bea098d696f7fed5e1eccbd10b321b682d6de586ae5627", size = 11404550, upload-time = "2026-05-28T14:16:20.138Z" },
{ url = "https://files.pythonhosted.org/packages/fe/1c/e6e5e568f22be4fb05d6244234aba384c06b451252453b821e1a529263cf/ruff-0.15.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48decfa11d740de4889de623be1463308346312f2409a56e24aa280c86162dc4", size = 11382027, upload-time = "2026-05-28T14:16:46.615Z" },
{ url = "https://files.pythonhosted.org/packages/1d/01/170921b49fcd2e8858825593f91cf7146c3e40a5c3e6df763e4bb0484dde/ruff-0.15.15-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a5015088452ca0081387063649ec67f06d3d1d6b8b936a1f836b5e9657ecd48c", size = 11366041, upload-time = "2026-05-28T14:16:26.247Z" },
{ url = "https://files.pythonhosted.org/packages/87/54/a7bad711d7de93254e15e06a4c375b89a03d18de45d3e5dcc86a4472fb1a/ruff-0.15.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5294aab6356c81600fcdea3a62bb1b924dfd5e91767c12318d3f68f86af57cd", size = 10741795, upload-time = "2026-05-28T14:16:17.11Z" },
{ url = "https://files.pythonhosted.org/packages/c9/31/38c075963668f8b41c6914ee0f6f318727fbe30ab9145cb29e6df464c5fa/ruff-0.15.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db5bd4d802415cca656dc1616070b725952d6ae95eb5d4831e49fbd94a38f75f", size = 10511117, upload-time = "2026-05-28T14:16:31.767Z" },
{ url = "https://files.pythonhosted.org/packages/9d/96/6ff689e1f7e375d1d97075eca022f74c2bab59554a432fe4d2e6f091986a/ruff-0.15.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:587a6278ed42059191c1a466e490bd7930fb50bd2e255398bc29616c895a61cb", size = 10994867, upload-time = "2026-05-28T14:16:35.149Z" },
{ url = "https://files.pythonhosted.org/packages/c3/c2/5dce0ab9f92a8d534fa62b9bf9caca3eddb8c1a81b616f5e195ada4f0d6e/ruff-0.15.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:df0c1c084f5f4be9812f61518a45c440d3c30d69ce4bf6c5270e66d38338f02a", size = 11482101, upload-time = "2026-05-28T14:16:49.598Z" },
{ url = "https://files.pythonhosted.org/packages/b1/c0/1003b60edd697c649faf61f1a34094b1abb38fb3d1181e3f895781250a08/ruff-0.15.15-py3-none-win32.whl", hash = "sha256:29428ea79694afbe756d45fd59b36f22b6b020dc0443cf7de0173046236964b9", size = 10716774, upload-time = "2026-05-28T14:16:52.337Z" },
{ url = "https://files.pythonhosted.org/packages/02/a8/1269eddd6945a06c23f055ef7848886e37cf9d6a8bebb386a3115f01470c/ruff-0.15.15-py3-none-win_amd64.whl", hash = "sha256:8df0323902e15e24bc4bf246da830573d3cf3352bd0b9a164eab335d111ff4a4", size = 11868463, upload-time = "2026-05-28T14:16:11.333Z" },
{ url = "https://files.pythonhosted.org/packages/4e/b2/920464c907b191e37469d477a1aa8bc048b8f36c4c1610dfa4ab87b39e18/ruff-0.15.15-py3-none-win_arm64.whl", hash = "sha256:3c8ceca6792f38196b8f589bc92eccd03eef286602da92e5dc05cc42ef6441b7", size = 11138498, upload-time = "2026-05-28T14:16:38.425Z" },
{ url = "https://files.pythonhosted.org/packages/0c/42/53ef1c3953f157956db9bf7861e3bc50b9b887ce93300aa48cdba8336fe6/ruff-0.15.16-py3-none-linux_armv6l.whl", hash = "sha256:6ac3c0b3969cc6cf6b158c4e2f8f682acb58e7d700d8a44b65ecdc72d66ab0b2", size = 10709025, upload-time = "2026-06-04T16:32:51.935Z" },
{ url = "https://files.pythonhosted.org/packages/93/9a/a79159346f19134a956607754e57d8d128f7a4c00f4ad2f7514d224c172c/ruff-0.15.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:197c207ed75ffba54a0dec23db4aa939a27a3053073e085e0042433cbdc58e4a", size = 11063550, upload-time = "2026-06-04T16:32:42.24Z" },
{ url = "https://files.pythonhosted.org/packages/bc/72/3ce2ac000a5299ec238e01f51397b3b653c93b077d9b1bfe8715bb895f20/ruff-0.15.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a39fec45ab316cc23e7558f23fea4a70403ddb5648ea9a4a3854a16973d0071", size = 10421345, upload-time = "2026-06-04T16:32:37.251Z" },
{ url = "https://files.pythonhosted.org/packages/b0/c2/cc7fad3ec9169373f5b6a18f1917b91080feec40c3f9658334a1d28e2f03/ruff-0.15.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba93191d79003116b95128c9d306e045200fdbd0bccb782b110f3cd1d4abc5cf", size = 10757217, upload-time = "2026-06-04T16:32:54.722Z" },
{ url = "https://files.pythonhosted.org/packages/69/d2/3474009eaa0a65b31fa7152a2fad5e2f050c640ceb1e6b02ee6922e94c82/ruff-0.15.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6ee4b90520630120ef032aa5cc10db483852dff950e78b1d717e2993a61ac8d", size = 10507035, upload-time = "2026-06-04T16:33:05.343Z" },
{ url = "https://files.pythonhosted.org/packages/ca/81/b7ae6ccbd11f0c8dc3d5d67fc4be9b57ff57ca86ba56152021378e1277f2/ruff-0.15.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e4215bc938bc3c8215c1472c1aa437e310fee20cd427335fec9d7e609563628", size = 11255291, upload-time = "2026-06-04T16:32:49.49Z" },
{ url = "https://files.pythonhosted.org/packages/d9/e1/46e526f1a7cc90857ce6ddf25fbb77eb6568651ac38d71b033af07076dd5/ruff-0.15.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c8d26be963b090f10e29abc8b3e74a2a321f6fa34e02424e30b5af89350ecbb", size = 12124922, upload-time = "2026-06-04T16:33:07.821Z" },
{ url = "https://files.pythonhosted.org/packages/1a/da/5c791b088b596b24d0deb967fa28ae02ad751a140c0b9ea81c5ab915d6c0/ruff-0.15.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f198cf4123602a2280ed46c307bcbafe41758d6fee5b456b6b6058ca1514b3b4", size = 11332186, upload-time = "2026-06-04T16:33:02.971Z" },
{ url = "https://files.pythonhosted.org/packages/72/11/5da87abe20047c8962361473923ebb2f62b595250126aadfad8c20649c1e/ruff-0.15.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb27515fa6240fb586ae82b901a59e67d24acff86f2190b433dc542fe0435aeb", size = 11373541, upload-time = "2026-06-04T16:32:47.007Z" },
{ url = "https://files.pythonhosted.org/packages/fe/2a/8554754c23a854ae3fd6b507e36ad61ddb121e298c6d5d617dec94ed0f14/ruff-0.15.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a267c46ba1593fc26b8eecbea050b39d40c0b6bb7781ee11c90a02cd10032951", size = 11353014, upload-time = "2026-06-04T16:32:34.795Z" },
{ url = "https://files.pythonhosted.org/packages/62/25/62ea41529ec89f742ea3fed9cb1059c72877ec7cf9b9e99ac9cf3294d1d9/ruff-0.15.16-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:528c68f39a91498a8d50e91ff5985df3d105782bab49cc378e73ac26bff083e8", size = 10737467, upload-time = "2026-06-04T16:32:26.348Z" },
{ url = "https://files.pythonhosted.org/packages/90/17/334d3ad9de4d40f9dd58fdd09e35ce64553bb501e2f19a839e2fb6be14fc/ruff-0.15.16-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7ed55c58950df60589a9a7a5d2f8fa5f54ebd287163be805adfe6ee95a9de123", size = 10521910, upload-time = "2026-06-04T16:32:32.54Z" },
{ url = "https://files.pythonhosted.org/packages/4d/bd/3ac7c6ae77a885c1004b3dda2446ea401768d24f851c14b4ad4b24f6639c/ruff-0.15.16-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d482feaf51512b50f9790ceb417a56a61dd1e9d9bf967662b9ed27c01b34f53a", size = 10979190, upload-time = "2026-06-04T16:32:57.492Z" },
{ url = "https://files.pythonhosted.org/packages/33/d7/609546e6a413c3f216fbf2a50c928f97c80939154f6a0503114094a86191/ruff-0.15.16-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e15bc8c94513dae2a40cc9ef07c94fdd4ecc9e29dabebeebe170f952322c9e3", size = 11477014, upload-time = "2026-06-04T16:32:44.687Z" },
{ url = "https://files.pythonhosted.org/packages/74/0d/f2cd247ad32633a5c36e97141a2c21b11c6279f7957bc2ff360b1e08fddd/ruff-0.15.16-py3-none-win32.whl", hash = "sha256:580378f7bd4aa25f72e74aa54948a9622f142b1e509521dd10902e886681cc1e", size = 10735541, upload-time = "2026-06-04T16:32:30.145Z" },
{ url = "https://files.pythonhosted.org/packages/8b/9e/02e845ef151b1dee585e55c4739f8e1734ae1d9f1221dff65761c162208b/ruff-0.15.16-py3-none-win_amd64.whl", hash = "sha256:408256017284eddf98fff77b29aa4fb30f586042d535b2d9befc6512f400aaec", size = 11843403, upload-time = "2026-06-04T16:32:39.76Z" },
{ url = "https://files.pythonhosted.org/packages/15/19/016553f86f207450aebebc2b2b5088d086b901cc8186c02ac4284db3bd88/ruff-0.15.16-py3-none-win_arm64.whl", hash = "sha256:8cd61783afb39638a7133ef0d2dfb1e91277593962f81b5a8423eb0b888a6121", size = 11134555, upload-time = "2026-06-04T16:33:00.136Z" },
]
[[package]]
@@ -2166,19 +2166,19 @@ wheels = [
[[package]]
name = "tornado"
version = "6.5.5"
version = "6.5.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" }
sdist = { url = "https://files.pythonhosted.org/packages/50/57/6d7303a77ae439d9189108f76c0c4fd89ee5e2cc8387bffb55232565c4ed/tornado-6.5.6.tar.gz", hash = "sha256:9a365179fe8ff6b8766f602c0f67c185d778193e9bdd828b19f0b6ed7764177d", size = 518139, upload-time = "2026-05-27T15:35:54.646Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" },
{ url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" },
{ url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" },
{ url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" },
{ url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" },
{ url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" },
{ url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" },
{ url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" },
{ url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" },
{ url = "https://files.pythonhosted.org/packages/1b/0d/b4f481e18c5a51864e6d12b9a05ecf72919696680b747c958c3fc1f4fbae/tornado-6.5.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:65fcfaafb079435c2c19dc9e07c0f1cf0fa9051759ed0a7d0a3ba7ea7f64919c", size = 447737, upload-time = "2026-05-27T15:35:38.122Z" },
{ url = "https://files.pythonhosted.org/packages/9e/9c/5430c39fcab1144d35860f457b15e9c08b4bc7ac86764354204e983d6183/tornado-6.5.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:38bc01b4acacded2de63ae78023548e41ebe6fbed3ec05a796d7ae3ad893887e", size = 445899, upload-time = "2026-05-27T15:35:40.519Z" },
{ url = "https://files.pythonhosted.org/packages/8b/79/fa7e14a2f939c807a8d30619b4eb604eab219601b78792516ebe22d40cf9/tornado-6.5.6-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b942e6a137fda31ff54bf8e6e2c8d1c37f1f50583f3ed53fb840b53b9601d104", size = 448964, upload-time = "2026-05-27T15:35:42.106Z" },
{ url = "https://files.pythonhosted.org/packages/a7/71/bd67d5f5199f937dafe03a49a37989f60f600ff6fef34c79412a829d97bd/tornado-6.5.6-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8666946e70171b8c3f1fc9b7876fac492e84822c4c7f3746f4e8f8bc9ac92a79", size = 449935, upload-time = "2026-05-27T15:35:43.906Z" },
{ url = "https://files.pythonhosted.org/packages/cc/a4/c24388c9cf5b3c3a513b56a158af9f23092c9a2810d789e294310797df21/tornado-6.5.6-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1c34cfab7ad6d104f052f55de06d39bbafc5885cfeb4da688803308dbcfa90b7", size = 449767, upload-time = "2026-05-27T15:35:45.793Z" },
{ url = "https://files.pythonhosted.org/packages/a5/eb/6a07ad550c3f7b37244bd0becdf293ec3d3e961783d8b720a97df50de1b2/tornado-6.5.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:385f35e4e22fb52551dfcda4cdc8c30c61c2c001aef5ddad99cdfe116952efd3", size = 449174, upload-time = "2026-05-27T15:35:47.485Z" },
{ url = "https://files.pythonhosted.org/packages/bb/84/3469e098dccdb6763130e06aacd786bb4363fca7b590a55c101ddf34ed30/tornado-6.5.6-cp39-abi3-win32.whl", hash = "sha256:db475f1b67b2809b10bb16264829087724ca8d24fe4ed47f7b8675cae453ef86", size = 450230, upload-time = "2026-05-27T15:35:49.322Z" },
{ url = "https://files.pythonhosted.org/packages/d2/3c/273a04e0b9dd9016f1685cca0c1c8795a71ac88a34a8c889a0b443483226/tornado-6.5.6-cp39-abi3-win_amd64.whl", hash = "sha256:6739bf1e8eb09230f1280ddbd3236f0309db70f2c551a8dbc40f62babdf82f79", size = 450667, upload-time = "2026-05-27T15:35:51.194Z" },
{ url = "https://files.pythonhosted.org/packages/02/98/0cffe22a224f60c5fb1e3aa0b76f9da2e1ca78b0e9545e3d077c68ce60a7/tornado-6.5.6-cp39-abi3-win_arm64.whl", hash = "sha256:2543597b24a695d72338a9a77818362d72387c03ae173f1f169eadc5c91466ac", size = 449690, upload-time = "2026-05-27T15:35:52.902Z" },
]
[[package]]