Repository: Rapptz/discord.py
Pull request: [tasks] Add way to change interval at run-time
### Summary

This pull request fixes #2158 by creating a `create_interval` method for a Loop, allowing the interval to be changed at run-time

### Checklist

<!-- Put an x inside [ ] to check it -->

- [x] If code changes were made then they have been tested.
    - [x] I have updated the documentation to reflect the changes.
- [x] This PR fixes an issue.
- [x] This PR adds something new (e.g. new method or parameters).
- [ ] This PR is a breaking change (e.g. methods or parameters removed/renamed)
- [ ] This PR is **not** a code change (e.g. documentation, README, ...)


Problem statement:
[tasks] Run-time changing of the sleep interval
### The Problem

No way to change the sleep interval at run-time.

### The Ideal Solution

Something like `task.change_interval(seconds=20.0)`. 

It should apply on the next loop. If someone wants to do it right away regardless of the current loop they can cancel it, change the interval, then start it again.

### The Current Solution

None

Hints from issue discussion:

Commit message: [tasks] Alter Loop.__init__ to use the new change_interval method

Patch to review:
diff --git a/discord/ext/tasks/__init__.py b/discord/ext/tasks/__init__.py
index 543086446ccd..5c93dfbe8140 100644
--- a/discord/ext/tasks/__init__.py
+++ b/discord/ext/tasks/__init__.py
@@ -18,9 +18,6 @@ class Loop:
     """
     def __init__(self, coro, seconds, hours, minutes, count, reconnect, loop):
         self.coro = coro
-        self.seconds = seconds
-        self.hours = hours
-        self.minutes = minutes
         self.reconnect = reconnect
         self.loop = loop or asyncio.get_event_loop()
         self.count = count
@@ -47,13 +44,7 @@ def __init__(self, coro, seconds, hours, minutes, count, reconnect, loop):
         if self.count is not None and self.count <= 0:
             raise ValueError('count must be greater than 0 or None.')
 
-        self._sleep = sleep = self.seconds + (self.minutes * 60.0) + (self.hours * 3600.0)
-        if sleep >= MAX_ASYNCIO_SECONDS:
-            fmt = 'Total number of seconds exceeds asyncio imposed limit of {0} seconds.'
-            raise ValueError(fmt.format(MAX_ASYNCIO_SECONDS))
-
-        if sleep < 0:
-            raise ValueError('Total number of seconds cannot be less than zero.')
+        self.change_interval(seconds=seconds, minutes=minutes, hours=hours)
 
         if not inspect.iscoroutinefunction(self.coro):
             raise TypeError('Expected coroutine function, not {0.__name__!r}.'.format(type(self.coro)))
@@ -317,6 +308,43 @@ def after_loop(self, coro):
         self._after_loop = coro
         return coro
 
+    def change_interval(self, *, seconds=0, minutes=0, hours=0):
+        """Changes the interval for the sleep time, which can be called at run-time.
+
+        .. note::
+
+            This only applies on the next loop. If it is desirable for the change of interval
+            to be applied right away, the loop can be cancelled, then the interval can be 
+            changed and the loop can be restarted after that.
+
+        Parameters
+        ------------
+        seconds: :class:`float`
+            The number of seconds between every iteration.
+        minutes: :class:`float`
+            The number of minutes between every iteration.
+        hours: :class:`float`
+            The number of hours between every iteration.
+
+        Raises
+        -------
+        ValueError
+            An invalid value was given.
+        """
+
+        sleep = seconds + (minutes * 60.0) + (hours * 3600.0)
+        if sleep >= MAX_ASYNCIO_SECONDS:
+            fmt = 'Total number of seconds exceeds asyncio imposed limit of {0} seconds.'
+            raise ValueError(fmt.format(MAX_ASYNCIO_SECONDS))
+
+        if sleep < 0:
+            raise ValueError('Total number of seconds cannot be less than zero.')
+
+        self._sleep = sleep
+        self.seconds = seconds
+        self.hours = hours
+        self.minutes = minutes
+
 def loop(*, seconds=0, minutes=0, hours=0, count=None, reconnect=True, loop=None):
     """A decorator that schedules a task in the background for you with
     optional reconnect logic.


Code review comments:
diff_hunk: @@ -317,6 +308,43 @@ def after_loop(self, coro):
         self._after_loop = coro
         return coro
 
+    def change_interval(self, *, seconds=0, minutes=0, hours=0):
+        """Changes the interval for the sleep time, which can be called at run-time.
+
+        .. note::
+
+            This only applies on the next loop. If it is desirable for the change of interval
+            to be applied right away, the loop can be cancelled, then the interval can be 
+            changed and the loop can be restarted after that.
path: discord/ext/tasks/__init__.py
text: @user1:
```suggestion
```

diff_hunk: @@ -317,6 +308,43 @@ def after_loop(self, coro):
         self._after_loop = coro
         return coro
 
+    def change_interval(self, *, seconds=0, minutes=0, hours=0):
+        """Changes the interval for the sleep time, which can be called at run-time.
+
+        .. note::
+
+            This only applies on the next loop. If it is desirable for the change of interval
path: discord/ext/tasks/__init__.py
text: @user1:
```suggestion
            This only applies on the next loop iteration. If it is desirable for the change of interval
```