diff --git a/changelog/1600.bugfix.rst b/changelog/1600.bugfix.rst new file mode 100644 index 0000000000..9c8503f4fa --- /dev/null +++ b/changelog/1600.bugfix.rst @@ -0,0 +1 @@ +|tasks| Retain original ``**kwargs`` of a :class:`~ext.tasks.Loop` for copying the loop, which helps avoid having to re-implement :meth:`Loop.clone ` in custom subclasses. diff --git a/disnake/ext/tasks/__init__.py b/disnake/ext/tasks/__init__.py index c917ddd95d..c92d2fa67b 100644 --- a/disnake/ext/tasks/__init__.py +++ b/disnake/ext/tasks/__init__.py @@ -72,6 +72,19 @@ class Loop(Generic[LF]): The main interface to create this is through :func:`loop`. """ + # (args, kwargs), used for cloning the loop later + __original_args__: tuple[tuple[Any, ...], dict[str, Any]] + + def __new__(cls, *args: Any, **kwargs: Any) -> Self: + self = super().__new__(cls) + # These are captured in __new__ (rather than __init__), such that we run + # before any subclass __init__'s and snapshot the original set of arguments. + # (n.b. while custom *args aren't supported in `Loop`, we capture *args here + # nonetheless, in case a subclass __init__ wraps the callback; using self.coro + # instead of the original arg for cloning would wrap it a second time) + self.__original_args__ = (args, kwargs) + return self + def __init__( self, coro: LF, @@ -200,20 +213,14 @@ def __get__(self, obj: T, objtype: type[T]) -> Self: return clone def clone(self) -> Self: - instance = type(self)( - self.coro, - seconds=self._seconds, - hours=self._hours, - minutes=self._minutes, - time=self._time, - count=self.count, - reconnect=self.reconnect, - loop=self.loop, - ) + args, kwargs = self.__original_args__ + instance = type(self)(*args, **kwargs) + instance._before_loop = self._before_loop instance._after_loop = self._after_loop instance._error = self._error instance._injected = self._injected + return instance @property diff --git a/tests/ext/tasks/test_loops.py b/tests/ext/tasks/test_loops.py index 73890d7f0c..10dfd03c08 100644 --- a/tests/ext/tasks/test_loops.py +++ b/tests/ext/tasks/test_loops.py @@ -41,18 +41,6 @@ def __init__(self, coro: LF, time_tup: tuple[float, float, float]) -> None: s, m, h = time_tup super().__init__(coro, seconds=s, minutes=m, hours=h) - def clone(self): - instance = type(self)(self.coro, (self._seconds, self._minutes, self._hours)) - instance._time = self._time - instance.count = self.count - instance.reconnect = self.reconnect - instance.loop = self.loop - instance._before_loop = self._before_loop - instance._after_loop = self._after_loop - instance._error = self._error - instance._injected = self._injected - return instance - async def callback() -> None: pass