From a391cad532184908c56e19e177bd29b2ef20d96c Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 5 May 2026 12:05:16 -0500 Subject: [PATCH 1/3] Force keyword-only args for `Duration` (prevent footgun) Spawning from https://github.com/element-hq/synapse/pull/19394#discussion_r3188418426 --- synapse/util/duration.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/synapse/util/duration.py b/synapse/util/duration.py index 135b9808520..1305b8cb317 100644 --- a/synapse/util/duration.py +++ b/synapse/util/duration.py @@ -32,6 +32,29 @@ class Duration(timedelta): ``` """ + # Using `__new__` because that's what `timedelta` uses + def __new__( + cls, + *, + days: float = 0, + seconds: float = 0, + microseconds: float = 0, + milliseconds: float = 0, + minutes: float = 0, + hours: float = 0, + weeks: float = 0, + ) -> "Duration": + return super().__new__( + cls, + days=days, + seconds=seconds, + microseconds=microseconds, + milliseconds=milliseconds, + minutes=minutes, + hours=hours, + weeks=weeks, + ) + def as_millis(self) -> int: """Returns the duration in milliseconds.""" return int(self / _ONE_MILLISECOND) From 8ca4c8010aa09dc3d39b05729b029500d1936440 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 5 May 2026 12:11:28 -0500 Subject: [PATCH 2/3] Better comments --- synapse/util/duration.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/synapse/util/duration.py b/synapse/util/duration.py index 1305b8cb317..a1abe944b53 100644 --- a/synapse/util/duration.py +++ b/synapse/util/duration.py @@ -32,9 +32,13 @@ class Duration(timedelta): ``` """ - # Using `__new__` because that's what `timedelta` uses + # Using `__new__` (instead of `__init__`) because that's what `timedelta` uses def __new__( cls, + # The whole goal of overriding `__new__` is to require keyword-only arguments. + # Without this, `Duration(5)` would create a duration represnting 5 *days* + # (timedelta's default), but callers almost certainly want to specify which unit + # like seconds or hours. *, days: float = 0, seconds: float = 0, From 371c160ff24b18d0b7a3a99086078da1330bd52d Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 5 May 2026 12:13:35 -0500 Subject: [PATCH 3/3] Add changelog --- changelog.d/19756.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/19756.misc diff --git a/changelog.d/19756.misc b/changelog.d/19756.misc new file mode 100644 index 00000000000..2450505b531 --- /dev/null +++ b/changelog.d/19756.misc @@ -0,0 +1 @@ +Force keyword-only args for `Duration` (prevent footgun) so people have to specify which time unit they want to us.