mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-06-06 11:57:17 +00:00
[tasks] Create different Loop objects for different instances
Fixes #2294
This commit is contained in:
parent
11211d48eb
commit
d5211fb327
@ -405,6 +405,21 @@ class Loop:
|
|||||||
self.hours = hours
|
self.hours = hours
|
||||||
self.minutes = minutes
|
self.minutes = minutes
|
||||||
|
|
||||||
|
class _LoopFactory:
|
||||||
|
def __init__(self, func, **kwargs):
|
||||||
|
self.func = func
|
||||||
|
self.name = func.__name__
|
||||||
|
self.kwargs = kwargs
|
||||||
|
|
||||||
|
def __get__(self, obj, objtype):
|
||||||
|
if obj is None:
|
||||||
|
return self
|
||||||
|
|
||||||
|
loop = Loop(self.func, **self.kwargs)
|
||||||
|
loop._injected = obj
|
||||||
|
setattr(obj, self.name, loop)
|
||||||
|
return loop
|
||||||
|
|
||||||
def loop(*, seconds=0, minutes=0, hours=0, count=None, reconnect=True, loop=None):
|
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
|
"""A decorator that schedules a task in the background for you with
|
||||||
optional reconnect logic. The decorator returns a :class:`Loop`.
|
optional reconnect logic. The decorator returns a :class:`Loop`.
|
||||||
@ -436,6 +451,33 @@ def loop(*, seconds=0, minutes=0, hours=0, count=None, reconnect=True, loop=None
|
|||||||
The function was not a coroutine.
|
The function was not a coroutine.
|
||||||
"""
|
"""
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
return Loop(func, seconds=seconds, minutes=minutes, hours=hours,
|
defined_within_class = False
|
||||||
count=count, reconnect=reconnect, loop=loop)
|
frames = inspect.stack()
|
||||||
|
# Essentially, to detect whether we're using this decorator a class
|
||||||
|
# context we're walking the stack to see whether it's top level or
|
||||||
|
# within a class level. This code is pretty finicky and hacky but
|
||||||
|
# it's better than the alternative that requires maintaining a list
|
||||||
|
# of IDs. This code does however break if someone assigns a loop
|
||||||
|
# decorator using different ways, such as a dynamically created
|
||||||
|
# class or calling the decorator directly. However such uses should
|
||||||
|
# be niche and thus don't really impede functionality for 99.99% of users
|
||||||
|
for frame in frames[1:]:
|
||||||
|
if frame[3] == '<module>':
|
||||||
|
break
|
||||||
|
if '__module__' in frame[0].f_code.co_names:
|
||||||
|
defined_within_class = True
|
||||||
|
break
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'seconds': seconds,
|
||||||
|
'minutes': minutes,
|
||||||
|
'hours': hours,
|
||||||
|
'count': count,
|
||||||
|
'reconnect': reconnect,
|
||||||
|
'loop': loop
|
||||||
|
}
|
||||||
|
|
||||||
|
if defined_within_class:
|
||||||
|
return _LoopFactory(func, **kwargs)
|
||||||
|
return Loop(func, **kwargs)
|
||||||
return decorator
|
return decorator
|
||||||
|
Loading…
x
Reference in New Issue
Block a user