Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Usetimedelta to represent time periods in classes#4750

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Bibo-Joshi merged 33 commits intomasterfromfeature/4575-timedelta-classes
Jun 29, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
33 commits
Select commitHold shift + click to select a range
40d354a
Setup helper functions and a common test fixture.
aelkheirApr 8, 2025
5cd6507
Accept timedeltas in params of `ChatFullInfo`.
aelkheirApr 8, 2025
a3b340b
Add chango fragment for PR #4750
aelkheirApr 9, 2025
d60b9fe
Refactor `test_chatfullinfo.py` a bit.
aelkheirApr 9, 2025
d4d62ce
Oops, so many white spaces.
aelkheirApr 9, 2025
3084d3b
Finish up `ChatFullInfo` plus some helper tweaks.
aelkheirApr 11, 2025
8d48756
Modify ``docs/substitutions/global.rst``.
aelkheirApr 11, 2025
8ef4ca9
Accept timedeltas in ``duration`` param of media classes.
aelkheirApr 12, 2025
28af9f7
Undeprecate passing `ints` to classes' arguments.
aelkheirMay 15, 2025
319dd6c
Accept timedeltas in params of `InlineQueryResult.*` classes.
aelkheirMay 16, 2025
d8dbe15
Accept timedeltas in other time period params.
aelkheirMay 17, 2025
caa831b
Modify test_official to handle time periods as timedelta automatically.
aelkheirMay 17, 2025
881a9f6
Accept timedeltas in Bot.get_updates.timeout.
aelkheirMay 17, 2025
466e0b0
Elaborate chango fragment for PR.
aelkheirMay 17, 2025
216b90b
Merge remote-tracking branch 'upstream/master' into feature/4575-time…
aelkheirMay 20, 2025
fb9a709
Update ``timeout`` type annotation in Application, Updater methods.
aelkheirMay 20, 2025
4e9f5fa
Accept timedelta in RetryAfter.
aelkheirMay 23, 2025
a4d4d12
Include attribute name in warning message.
aelkheirMay 23, 2025
3194848
review: refactor `_utils/datetime.get_timedelta_value`.
aelkheirMay 23, 2025
de83ac6
Remove temporarily time period parser introduced in #4769.
aelkheirMay 23, 2025
10e716a
review: address comments
aelkheirMay 24, 2025
b20f9f9
Fix precommit and update `test_request.py`.
aelkheirMay 24, 2025
719e9b3
Fix a test in `test_updater.py` that hangs.
aelkheirMay 24, 2025
cd0fd0e
Merge remote-tracking branch 'upstream/master' into feature/4575-time…
aelkheirMay 26, 2025
574b09d
Move `to_dict` logic to `_telegramobject.py`.
aelkheirMay 26, 2025
2a4ed74
Merge remote-tracking branch 'upstream/master' into feature/4575-time…
aelkheirMay 28, 2025
eb34ae3
Add a test for `get_timedelta_value`.
aelkheirMay 28, 2025
7d93eb5
Fix precommit.
aelkheirJun 1, 2025
aba92df
review: address comments.
aelkheirJun 9, 2025
11ac715
review: update handling of deprecation logic in telegramobject.
aelkheirJun 9, 2025
e9a63c2
fix typo in docstring of `TO._is_deprecated_attr`
aelkheirJun 9, 2025
0ef3041
review: some other points.
aelkheirJun 16, 2025
5aabf59
Mock business float period properties.
aelkheirJun 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletionschanges/unreleased/4750.jJBu7iAgZa96hdqcpHK96W.toml
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
features = "Use `timedelta` to represent time periods in class arguments and attributes"
deprecations = """In this release, we're migrating attributes of Telegram objects that represent durations/time periods from having :obj:`int` type to Python's native :class:`datetime.timedelta`. This change is opt-in for now to allow for a smooth transition phase. It will become opt-out in future releases.

Set ``PTB_TIMEDELTA=true`` or ``PTB_TIMEDELTA=1`` as an environment variable to make these attributes return :obj:`datetime.timedelta` objects instead of integers. Support for :obj:`int` values is deprecated and will be removed in a future major version.

Affected Attributes:
- :attr:`telegram.ChatFullInfo.slow_mode_delay` and :attr:`telegram.ChatFullInfo.message_auto_delete_time`
- :attr:`telegram.Animation.duration`
- :attr:`telegram.Audio.duration`
- :attr:`telegram.Video.duration` and :attr:`telegram.Video.start_timestamp`
- :attr:`telegram.VideoNote.duration`
- :attr:`telegram.Voice.duration`
- :attr:`telegram.PaidMediaPreview.duration`
- :attr:`telegram.VideoChatEnded.duration`
- :attr:`telegram.InputMediaVideo.duration`
- :attr:`telegram.InputMediaAnimation.duration`
- :attr:`telegram.InputMediaAudio.duration`
- :attr:`telegram.InputPaidMediaVideo.duration`
- :attr:`telegram.InlineQueryResultGif.gif_duration`
- :attr:`telegram.InlineQueryResultMpeg4Gif.mpeg4_duration`
- :attr:`telegram.InlineQueryResultVideo.video_duration`
- :attr:`telegram.InlineQueryResultAudio.audio_duration`
- :attr:`telegram.InlineQueryResultVoice.voice_duration`
- :attr:`telegram.InlineQueryResultLocation.live_period`
- :attr:`telegram.Poll.open_period`
- :attr:`telegram.Location.live_period`
- :attr:`telegram.MessageAutoDeleteTimerChanged.message_auto_delete_time`
- :attr:`telegram.ChatInviteLink.subscription_period`
- :attr:`telegram.InputLocationMessageContent.live_period`
- :attr:`telegram.error.RetryAfter.retry_after`
"""
internal = "Modify `test_official` to handle time periods as timedelta automatically."
[[pull_requests]]
uid = "4750"
author_uid = "aelkheir"
closes_threads = ["4575"]
2 changes: 2 additions & 0 deletionsdocs/substitutions/global.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,3 +101,5 @@
.. |org-verify| replace:: `on behalf of the organization <https://telegram.org/verify#third-party-verification>`__

.. |time-period-input| replace:: :class:`datetime.timedelta` objects are accepted in addition to plain :obj:`int` values.

.. |time-period-int-deprecated| replace:: In a future major version this attribute will be of type :obj:`datetime.timedelta`. You can opt-in early by setting `PTB_TIMEDELTA=true` or ``PTB_TIMEDELTA=1`` as an environment variable.
5 changes: 4 additions & 1 deletionexamples/rawapibot.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
"""
import asyncio
import contextlib
import datetime as dtm
import logging
from typing import NoReturn

Expand DownExpand Up@@ -47,7 +48,9 @@ async def main() -> NoReturn:
async def echo(bot: Bot, update_id: int) -> int:
"""Echo the message the user sent."""
# Request updates after the last update_id
updates = await bot.get_updates(offset=update_id, timeout=10, allowed_updates=Update.ALL_TYPES)
updates = await bot.get_updates(
offset=update_id, timeout=dtm.timedelta(seconds=10), allowed_updates=Update.ALL_TYPES
)
for update in updates:
next_update_id = update.update_id + 1

Expand Down
19 changes: 14 additions & 5 deletionssrc/telegram/_bot.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4519,7 +4519,7 @@ async def get_updates(
self,
offset: Optional[int] = None,
limit: Optional[int] = None,
timeout: Optional[int] = None,
timeout: Optional[TimePeriod] = None,
allowed_updates: Optional[Sequence[str]] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
Expand DownExpand Up@@ -4554,9 +4554,12 @@ async def get_updates(
between :tg-const:`telegram.constants.PollingLimit.MIN_LIMIT`-
:tg-const:`telegram.constants.PollingLimit.MAX_LIMIT` are accepted.
Defaults to ``100``.
timeout (:obj:`int`, optional): Timeout in seconds for long polling. Defaults to ``0``,
i.e. usual short polling. Should be positive, short polling should be used for
testing purposes only.
timeout (:obj:`int` | :class:`datetime.timedelta`, optional): Timeout in seconds for
long polling. Defaults to ``0``, i.e. usual short polling. Should be positive,
short polling should be used for testing purposes only.

.. versionchanged:: NEXT.VERSION
|time-period-input|
allowed_updates (Sequence[:obj:`str`]), optional): A sequence the types of
updates you want your bot to receive. For example, specify ["message",
"edited_channel_post", "callback_query"] to only receive updates of these types.
Expand DownExpand Up@@ -4591,6 +4594,12 @@ async def get_updates(
else:
arg_read_timeout = self._request[0].read_timeout or 0

read_timeout = (
(arg_read_timeout + timeout.total_seconds())
if isinstance(timeout, dtm.timedelta)
else (arg_read_timeout + timeout if timeout else arg_read_timeout)
)

# Ideally we'd use an aggressive read timeout for the polling. However,
# * Short polling should return within 2 seconds.
# * Long polling poses a different problem: the connection might have been dropped while
Expand All@@ -4601,7 +4610,7 @@ async def get_updates(
await self._post(
"getUpdates",
data,
read_timeout=arg_read_timeout + timeout if timeout else arg_read_timeout,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
Expand Down
69 changes: 50 additions & 19 deletionssrc/telegram/_chatfullinfo.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,7 @@
"""This module contains an object that represents a Telegram ChatFullInfo."""
import datetime as dtm
from collections.abc import Sequence
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Optional, Union

from telegram._birthdate import Birthdate
from telegram._chat import Chat, _ChatBase
Expand All@@ -29,9 +29,18 @@
from telegram._files.chatphoto import ChatPhoto
from telegram._gifts import AcceptedGiftTypes
from telegram._reaction import ReactionType
from telegram._utils.argumentparsing import de_json_optional, de_list_optional, parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
from telegram._utils.argumentparsing import (
de_json_optional,
de_list_optional,
parse_sequence_arg,
to_timedelta,
)
from telegram._utils.datetime import (
extract_tzinfo_from_defaults,
from_timestamp,
get_timedelta_value,
)
from telegram._utils.types import JSONDict, TimePeriod
from telegram._utils.warnings import warn
from telegram._utils.warnings_transition import (
build_deprecation_warning_message,
Expand DownExpand Up@@ -166,17 +175,23 @@ class ChatFullInfo(_ChatBase):
(by sending date).
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
for groups and supergroups.
slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between
consecutive messages sent by each unprivileged user.
slow_mode_delay (:obj:`int` | :class:`datetime.timedelta`, optional): For supergroups,
the minimum allowed delay between consecutive messages sent by each unprivileged user.

.. versionchanged:: NEXT.VERSION
|time-period-input|
unrestrict_boost_count (:obj:`int`, optional): For supergroups, the minimum number of
boosts that a non-administrator user needs to add in order to ignore slow mode and chat
permissions.

.. versionadded:: 21.0
message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to
the chat will be automatically deleted; in seconds.
message_auto_delete_time (:obj:`int` | :class:`datetime.timedelta`, optional): The time
after which all messages sent tothe chat will be automatically deleted; in seconds.

.. versionadded:: 13.4

.. versionchanged:: NEXT.VERSION
|time-period-input|
has_aggressive_anti_spam_enabled (:obj:`bool`, optional): :obj:`True`, if aggressive
anti-spam checks are enabled in the supergroup. The field is only available to chat
administrators.
Expand DownExpand Up@@ -331,17 +346,23 @@ class ChatFullInfo(_ChatBase):
(by sending date).
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
for groups and supergroups.
slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between
consecutive messages sent by each unprivileged user.
slow_mode_delay (:obj:`int` | :class:`datetime.timedelta`): Optional. For supergroups,
the minimum allowed delay between consecutive messages sent by each unprivileged user.

.. deprecated:: NEXT.VERSION
|time-period-int-deprecated|
unrestrict_boost_count (:obj:`int`): Optional. For supergroups, the minimum number of
boosts that a non-administrator user needs to add in order to ignore slow mode and chat
permissions.

.. versionadded:: 21.0
message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to
the chat will be automatically deleted; in seconds.
message_auto_delete_time (:obj:`int` | :class:`datetime.timedelta`): Optional. The time
after which all messages sent tothe chat will be automatically deleted; in seconds.

.. versionadded:: 13.4

.. deprecated:: NEXT.VERSION
|time-period-int-deprecated|
has_aggressive_anti_spam_enabled (:obj:`bool`): Optional. :obj:`True`, if aggressive
anti-spam checks are enabled in the supergroup. The field is only available to chat
administrators.
Expand DownExpand Up@@ -383,6 +404,8 @@ class ChatFullInfo(_ChatBase):

__slots__ = (
"_can_send_gift",
"_message_auto_delete_time",
"_slow_mode_delay",
"accent_color_id",
"accepted_gift_types",
"active_usernames",
Expand DownExpand Up@@ -411,14 +434,12 @@ class ChatFullInfo(_ChatBase):
"linked_chat_id",
"location",
"max_reaction_count",
"message_auto_delete_time",
"permissions",
"personal_chat",
"photo",
"pinned_message",
"profile_accent_color_id",
"profile_background_custom_emoji_id",
"slow_mode_delay",
"sticker_set_name",
"unrestrict_boost_count",
)
Expand DownExpand Up@@ -456,9 +477,9 @@ def __init__(
invite_link: Optional[str] = None,
pinned_message: Optional["Message"] = None,
permissions: Optional[ChatPermissions] = None,
slow_mode_delay: Optional[int] = None,
slow_mode_delay: Optional[TimePeriod] = None,
unrestrict_boost_count: Optional[int] = None,
message_auto_delete_time: Optional[int] = None,
message_auto_delete_time: Optional[TimePeriod] = None,
has_aggressive_anti_spam_enabled: Optional[bool] = None,
has_hidden_members: Optional[bool] = None,
has_protected_content: Optional[bool] = None,
Expand DownExpand Up@@ -513,9 +534,9 @@ def __init__(
self.invite_link: Optional[str] = invite_link
self.pinned_message: Optional[Message] = pinned_message
self.permissions: Optional[ChatPermissions] = permissions
self.slow_mode_delay: Optional[int] = slow_mode_delay
self.message_auto_delete_time: Optional[int] = (
int(message_auto_delete_time) if message_auto_delete_time is not None else None
self._slow_mode_delay: Optional[dtm.timedelta] =to_timedelta(slow_mode_delay)
self._message_auto_delete_time: Optional[dtm.timedelta] =to_timedelta(
message_auto_delete_time
)
self.has_protected_content: Optional[bool] = has_protected_content
self.has_visible_history: Optional[bool] = has_visible_history
Expand DownExpand Up@@ -576,6 +597,16 @@ def can_send_gift(self) -> Optional[bool]:
)
return self._can_send_gift

@property
def slow_mode_delay(self) -> Optional[Union[int, dtm.timedelta]]:
return get_timedelta_value(self._slow_mode_delay, attribute="slow_mode_delay")

@property
def message_auto_delete_time(self) -> Optional[Union[int, dtm.timedelta]]:
return get_timedelta_value(
self._message_auto_delete_time, attribute="message_auto_delete_time"
)

@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatFullInfo":
"""See :meth:`telegram.TelegramObject.de_json`."""
Expand Down
36 changes: 25 additions & 11 deletionssrc/telegram/_chatinvitelink.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,13 +18,17 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents an invite link for a chat."""
import datetime as dtm
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Optional, Union

from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import de_json_optional
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict
from telegram._utils.argumentparsing import de_json_optional, to_timedelta
from telegram._utils.datetime import (
extract_tzinfo_from_defaults,
from_timestamp,
get_timedelta_value,
)
from telegram._utils.types import JSONDict, TimePeriod

if TYPE_CHECKING:
from telegram import Bot
Expand DownExpand Up@@ -70,10 +74,13 @@ class ChatInviteLink(TelegramObject):
created using this link.

.. versionadded:: 13.8
subscription_period (:obj:`int`, optional): The number of seconds the subscription will be
active for before the next payment.
subscription_period (:obj:`int` | :class:`datetime.timedelta`, optional): The number of
seconds the subscription will beactive for before the next payment.

.. versionadded:: 21.5

.. versionchanged:: NEXT.VERSION
|time-period-input|
subscription_price (:obj:`int`, optional): The amount of Telegram Stars a user must pay
initially and after each subsequent subscription period to be a member of the chat
using the link.
Expand DownExpand Up@@ -107,10 +114,13 @@ class ChatInviteLink(TelegramObject):
created using this link.

.. versionadded:: 13.8
subscription_period (:obj:`int`): Optional. The number of seconds the subscription will be
active for before the next payment.
subscription_period (:obj:`int` | :class:`datetime.timedelta`): Optional. The number of
seconds the subscription will beactive for before the next payment.

.. versionadded:: 21.5

.. deprecated:: NEXT.VERSION
|time-period-int-deprecated|
subscription_price (:obj:`int`): Optional. The amount of Telegram Stars a user must pay
initially and after each subsequent subscription period to be a member of the chat
using the link.
Expand All@@ -120,6 +130,7 @@ class ChatInviteLink(TelegramObject):
"""

__slots__ = (
"_subscription_period",
"creates_join_request",
"creator",
"expire_date",
Expand All@@ -129,7 +140,6 @@ class ChatInviteLink(TelegramObject):
"member_limit",
"name",
"pending_join_request_count",
"subscription_period",
"subscription_price",
)

Expand All@@ -144,7 +154,7 @@ def __init__(
member_limit: Optional[int] = None,
name: Optional[str] = None,
pending_join_request_count: Optional[int] = None,
subscription_period: Optional[int] = None,
subscription_period: Optional[TimePeriod] = None,
subscription_price: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
Expand All@@ -164,7 +174,7 @@ def __init__(
self.pending_join_request_count: Optional[int] = (
int(pending_join_request_count) if pending_join_request_count is not None else None
)
self.subscription_period: Optional[int] = subscription_period
self._subscription_period: Optional[dtm.timedelta] =to_timedelta(subscription_period)
self.subscription_price: Optional[int] = subscription_price

self._id_attrs = (
Expand All@@ -177,6 +187,10 @@ def __init__(

self._freeze()

@property
def subscription_period(self) -> Optional[Union[int, dtm.timedelta]]:
return get_timedelta_value(self._subscription_period, attribute="subscription_period")

@classmethod
def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "ChatInviteLink":
"""See :meth:`telegram.TelegramObject.de_json`."""
Expand Down
15 changes: 3 additions & 12 deletionssrc/telegram/_files/_inputstorycontent.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@
fromtelegram._files.inputfileimportInputFile
fromtelegram._telegramobjectimportTelegramObject
fromtelegram._utilsimportenum
fromtelegram._utils.argumentparsingimportto_timedelta
fromtelegram._utils.filesimportparse_file_input
fromtelegram._utils.typesimportFileInput,JSONDict

Expand DownExpand Up@@ -158,18 +159,8 @@ def __init__(

withself._unfrozen():
self.video:Union[str,InputFile]=self._parse_file_input(video)
self.duration:Optional[dtm.timedelta]=self._parse_period_arg(duration)
self.cover_frame_timestamp:Optional[dtm.timedelta]=self._parse_period_arg(
self.duration:Optional[dtm.timedelta]=to_timedelta(duration)
self.cover_frame_timestamp:Optional[dtm.timedelta]=to_timedelta(
cover_frame_timestamp
)
self.is_animation:Optional[bool]=is_animation

# This helper is temporarly here until we can use `argumentparsing.parse_period_arg`
# from https://github.com/python-telegram-bot/python-telegram-bot/pull/4750
@staticmethod
def_parse_period_arg(arg:Optional[Union[float,dtm.timedelta]])->Optional[dtm.timedelta]:
ifargisNone:
returnNone
ifisinstance(arg,dtm.timedelta):
returnarg
returndtm.timedelta(seconds=arg)
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp