diff options
| author | 2021-09-26 12:23:37 -0700 | |
|---|---|---|
| committer | 2021-09-26 12:23:37 -0700 | |
| commit | e98719a5fc4026bf01a8a3a762707bc4f888243c (patch) | |
| tree | 1bfa2fc72ec8b29a3cafa7865b5d7d8b63165b8f | |
| parent | Merge pull request #1846 from python-discord/suppress-notfound-messages-on-de... (diff) | |
| parent | Merge branch 'main' into scheduling-create_task-init (diff) | |
Merge pull request #1825 from Numerlor/scheduling-create_task-init
Use scheduling create_task util to create tasks
29 files changed, 85 insertions, 55 deletions
| diff --git a/bot/async_stats.py b/bot/async_stats.py index 58a80f528..2af832e5b 100644 --- a/bot/async_stats.py +++ b/bot/async_stats.py @@ -3,6 +3,8 @@ import socket  from statsd.client.base import StatsClientBase +from bot.utils import scheduling +  class AsyncStatsClient(StatsClientBase):      """An async transport method for statsd communication.""" @@ -32,7 +34,7 @@ class AsyncStatsClient(StatsClientBase):      def _send(self, data: str) -> None:          """Start an async task to send data to statsd.""" -        self._loop.create_task(self._async_send(data)) +        scheduling.create_task(self._async_send(data), event_loop=self._loop)      async def _async_send(self, data: str) -> None:          """Send data to the statsd server using the async transport.""" diff --git a/bot/decorators.py b/bot/decorators.py index f65ec4103..ee210be26 100644 --- a/bot/decorators.py +++ b/bot/decorators.py @@ -10,7 +10,7 @@ from discord.ext import commands  from discord.ext.commands import Cog, Context  from bot.constants import Channels, DEBUG_MODE, RedirectOutput -from bot.utils import function +from bot.utils import function, scheduling  from bot.utils.checks import ContextCheckFailure, in_whitelist_check  from bot.utils.function import command_wraps @@ -154,7 +154,7 @@ def redirect_output(              if ping_user:                  await ctx.send(f"Here's the output of your command, {ctx.author.mention}") -            asyncio.create_task(func(self, ctx, *args, **kwargs)) +            scheduling.create_task(func(self, ctx, *args, **kwargs))              message = await old_channel.send(                  f"Hey, {ctx.author.mention}, you can find the output of your command here: " diff --git a/bot/exts/backend/branding/_cog.py b/bot/exts/backend/branding/_cog.py index 0ba146635..ab0a761ff 100644 --- a/bot/exts/backend/branding/_cog.py +++ b/bot/exts/backend/branding/_cog.py @@ -17,6 +17,7 @@ from bot.bot import Bot  from bot.constants import Branding as BrandingConfig, Channels, Colours, Guild, MODERATION_ROLES  from bot.decorators import mock_in_debug  from bot.exts.backend.branding._repository import BrandingRepository, Event, RemoteObject +from bot.utils import scheduling  log = logging.getLogger(__name__) @@ -126,7 +127,7 @@ class Branding(commands.Cog):          self.bot = bot          self.repository = BrandingRepository(bot) -        self.bot.loop.create_task(self.maybe_start_daemon())  # Start depending on cache. +        scheduling.create_task(self.maybe_start_daemon(), event_loop=self.bot.loop)  # Start depending on cache.      # region: Internal logic & state management diff --git a/bot/exts/backend/config_verifier.py b/bot/exts/backend/config_verifier.py index d72c6c22e..c24cb324f 100644 --- a/bot/exts/backend/config_verifier.py +++ b/bot/exts/backend/config_verifier.py @@ -4,7 +4,7 @@ from discord.ext.commands import Cog  from bot import constants  from bot.bot import Bot - +from bot.utils import scheduling  log = logging.getLogger(__name__) @@ -14,7 +14,7 @@ class ConfigVerifier(Cog):      def __init__(self, bot: Bot):          self.bot = bot -        self.channel_verify_task = self.bot.loop.create_task(self.verify_channels()) +        self.channel_verify_task = scheduling.create_task(self.verify_channels(), event_loop=self.bot.loop)      async def verify_channels(self) -> None:          """ diff --git a/bot/exts/backend/logging.py b/bot/exts/backend/logging.py index 823f14ea4..8f1b8026f 100644 --- a/bot/exts/backend/logging.py +++ b/bot/exts/backend/logging.py @@ -5,7 +5,7 @@ from discord.ext.commands import Cog  from bot.bot import Bot  from bot.constants import Channels, DEBUG_MODE - +from bot.utils import scheduling  log = logging.getLogger(__name__) @@ -16,7 +16,7 @@ class Logging(Cog):      def __init__(self, bot: Bot):          self.bot = bot -        self.bot.loop.create_task(self.startup_greeting()) +        scheduling.create_task(self.startup_greeting(), event_loop=self.bot.loop)      async def startup_greeting(self) -> None:          """Announce our presence to the configured devlog channel.""" diff --git a/bot/exts/backend/sync/_cog.py b/bot/exts/backend/sync/_cog.py index 48d2b6f02..f88dcf538 100644 --- a/bot/exts/backend/sync/_cog.py +++ b/bot/exts/backend/sync/_cog.py @@ -9,6 +9,7 @@ from bot import constants  from bot.api import ResponseCodeError  from bot.bot import Bot  from bot.exts.backend.sync import _syncers +from bot.utils import scheduling  log = logging.getLogger(__name__) @@ -18,7 +19,7 @@ class Sync(Cog):      def __init__(self, bot: Bot) -> None:          self.bot = bot -        self.bot.loop.create_task(self.sync_guild()) +        scheduling.create_task(self.sync_guild(), event_loop=self.bot.loop)      async def sync_guild(self) -> None:          """Syncs the roles/users of the guild with the database.""" diff --git a/bot/exts/filters/antispam.py b/bot/exts/filters/antispam.py index 72103c9fb..fe79a5d62 100644 --- a/bot/exts/filters/antispam.py +++ b/bot/exts/filters/antispam.py @@ -129,7 +129,11 @@ class AntiSpam(Cog):          self.max_interval = max_interval_config['interval']          self.cache = MessageCache(AntiSpamConfig.cache_size, newest_first=True) -        self.bot.loop.create_task(self.alert_on_validation_error(), name="AntiSpam.alert_on_validation_error") +        scheduling.create_task( +            self.alert_on_validation_error(), +            name="AntiSpam.alert_on_validation_error", +            event_loop=self.bot.loop, +        )      @property      def mod_log(self) -> ModLog: diff --git a/bot/exts/filters/filter_lists.py b/bot/exts/filters/filter_lists.py index 232c1e48b..a06437f3d 100644 --- a/bot/exts/filters/filter_lists.py +++ b/bot/exts/filters/filter_lists.py @@ -9,6 +9,7 @@ from bot.api import ResponseCodeError  from bot.bot import Bot  from bot.converters import ValidDiscordServerInvite, ValidFilterListType  from bot.pagination import LinePaginator +from bot.utils import scheduling  log = logging.getLogger(__name__) @@ -27,7 +28,7 @@ class FilterLists(Cog):      def __init__(self, bot: Bot) -> None:          self.bot = bot -        self.bot.loop.create_task(self._amend_docstrings()) +        scheduling.create_task(self._amend_docstrings(), event_loop=self.bot.loop)      async def _amend_docstrings(self) -> None:          """Add the valid FilterList types to the docstrings, so they'll appear in !help invocations.""" diff --git a/bot/exts/filters/filtering.py b/bot/exts/filters/filtering.py index 7e698880f..64f3b82af 100644 --- a/bot/exts/filters/filtering.py +++ b/bot/exts/filters/filtering.py @@ -21,9 +21,9 @@ from bot.constants import (  )  from bot.exts.events.code_jams._channels import CATEGORY_NAME as JAM_CATEGORY_NAME  from bot.exts.moderation.modlog import ModLog +from bot.utils import scheduling  from bot.utils.messages import format_user  from bot.utils.regex import INVITE_RE -from bot.utils.scheduling import Scheduler  log = logging.getLogger(__name__) @@ -64,7 +64,7 @@ class Filtering(Cog):      def __init__(self, bot: Bot):          self.bot = bot -        self.scheduler = Scheduler(self.__class__.__name__) +        self.scheduler = scheduling.Scheduler(self.__class__.__name__)          self.name_lock = asyncio.Lock()          staff_mistake_str = "If you believe this was a mistake, please let staff know!" @@ -133,7 +133,7 @@ class Filtering(Cog):              },          } -        self.bot.loop.create_task(self.reschedule_offensive_msg_deletion()) +        scheduling.create_task(self.reschedule_offensive_msg_deletion(), event_loop=self.bot.loop)      def cog_unload(self) -> None:          """Cancel scheduled tasks.""" diff --git a/bot/exts/fun/duck_pond.py b/bot/exts/fun/duck_pond.py index 7f7e4585c..8ced6922c 100644 --- a/bot/exts/fun/duck_pond.py +++ b/bot/exts/fun/duck_pond.py @@ -9,6 +9,7 @@ from discord.ext.commands import Cog, Context, command  from bot import constants  from bot.bot import Bot  from bot.converters import MemberOrUser +from bot.utils import scheduling  from bot.utils.checks import has_any_role  from bot.utils.messages import count_unique_users_reaction, send_attachments  from bot.utils.webhooks import send_webhook @@ -24,7 +25,7 @@ class DuckPond(Cog):          self.webhook_id = constants.Webhooks.duck_pond          self.webhook = None          self.ducked_messages = [] -        self.bot.loop.create_task(self.fetch_webhook()) +        scheduling.create_task(self.fetch_webhook(), event_loop=self.bot.loop)          self.relay_lock = None      async def fetch_webhook(self) -> None: diff --git a/bot/exts/fun/off_topic_names.py b/bot/exts/fun/off_topic_names.py index 845b8175c..2f56aa5ba 100644 --- a/bot/exts/fun/off_topic_names.py +++ b/bot/exts/fun/off_topic_names.py @@ -11,6 +11,7 @@ from bot.bot import Bot  from bot.constants import Channels, MODERATION_ROLES  from bot.converters import OffTopicName  from bot.pagination import LinePaginator +from bot.utils import scheduling  CHANNELS = (Channels.off_topic_0, Channels.off_topic_1, Channels.off_topic_2)  log = logging.getLogger(__name__) @@ -50,7 +51,7 @@ class OffTopicNames(Cog):          self.bot = bot          self.updater_task = None -        self.bot.loop.create_task(self.init_offtopic_updater()) +        scheduling.create_task(self.init_offtopic_updater(), event_loop=self.bot.loop)      def cog_unload(self) -> None:          """Cancel any running updater tasks on cog unload.""" @@ -62,7 +63,7 @@ class OffTopicNames(Cog):          await self.bot.wait_until_guild_available()          if self.updater_task is None:              coro = update_names(self.bot) -            self.updater_task = self.bot.loop.create_task(coro) +            self.updater_task = scheduling.create_task(coro, event_loop=self.bot.loop)      @group(name='otname', aliases=('otnames', 'otn'), invoke_without_command=True)      @has_any_role(*MODERATION_ROLES) diff --git a/bot/exts/help_channels/_cog.py b/bot/exts/help_channels/_cog.py index cfc9cf477..8612f9866 100644 --- a/bot/exts/help_channels/_cog.py +++ b/bot/exts/help_channels/_cog.py @@ -82,7 +82,7 @@ class HelpChannels(commands.Cog):          # Asyncio stuff          self.queue_tasks: t.List[asyncio.Task] = [] -        self.init_task = self.bot.loop.create_task(self.init_cog()) +        self.init_task = scheduling.create_task(self.init_cog(), event_loop=self.bot.loop)      def cog_unload(self) -> None:          """Cancel the init task and scheduled tasks when the cog unloads.""" @@ -507,7 +507,7 @@ class HelpChannels(commands.Cog):          """Wait for a dormant channel to become available in the queue and return it."""          log.trace("Waiting for a dormant channel.") -        task = asyncio.create_task(self.channel_queue.get()) +        task = scheduling.create_task(self.channel_queue.get())          self.queue_tasks.append(task)          channel = await task diff --git a/bot/exts/info/codeblock/_cog.py b/bot/exts/info/codeblock/_cog.py index 9a0705d2b..f63a459ff 100644 --- a/bot/exts/info/codeblock/_cog.py +++ b/bot/exts/info/codeblock/_cog.py @@ -11,7 +11,7 @@ from bot.bot import Bot  from bot.exts.filters.token_remover import TokenRemover  from bot.exts.filters.webhook_remover import WEBHOOK_URL_RE  from bot.exts.info.codeblock._instructions import get_instructions -from bot.utils import has_lines +from bot.utils import has_lines, scheduling  from bot.utils.channel import is_help_channel  from bot.utils.messages import wait_for_deletion @@ -114,7 +114,7 @@ class CodeBlockCog(Cog, name="Code Block"):          bot_message = await message.channel.send(f"Hey {message.author.mention}!", embed=embed)          self.codeblock_message_ids[message.id] = bot_message.id -        self.bot.loop.create_task(wait_for_deletion(bot_message, (message.author.id,))) +        scheduling.create_task(wait_for_deletion(bot_message, (message.author.id,)), event_loop=self.bot.loop)          # Increase amount of codeblock correction in stats          self.bot.stats.incr("codeblock_corrections") diff --git a/bot/exts/info/doc/_batch_parser.py b/bot/exts/info/doc/_batch_parser.py index 369bb462c..51ee29b68 100644 --- a/bot/exts/info/doc/_batch_parser.py +++ b/bot/exts/info/doc/_batch_parser.py @@ -24,9 +24,10 @@ class StaleInventoryNotifier:      """Handle sending notifications about stale inventories through `DocItem`s to dev log."""      def __init__(self): -        self._init_task = bot.instance.loop.create_task( +        self._init_task = scheduling.create_task(              self._init_channel(), -            name="StaleInventoryNotifier channel init" +            name="StaleInventoryNotifier channel init", +            event_loop=bot.instance.loop,          )          self._warned_urls = set() diff --git a/bot/exts/info/doc/_cog.py b/bot/exts/info/doc/_cog.py index a2119a53d..1624c50f6 100644 --- a/bot/exts/info/doc/_cog.py +++ b/bot/exts/info/doc/_cog.py @@ -17,6 +17,7 @@ from bot.bot import Bot  from bot.constants import MODERATION_ROLES, RedirectOutput  from bot.converters import Inventory, PackageName, ValidURL, allowed_strings  from bot.pagination import LinePaginator +from bot.utils import scheduling  from bot.utils.lock import SharedEvent, lock  from bot.utils.messages import send_denial, wait_for_deletion  from bot.utils.scheduling import Scheduler @@ -75,9 +76,10 @@ class DocCog(commands.Cog):          self.refresh_event.set()          self.symbol_get_event = SharedEvent() -        self.init_refresh_task = self.bot.loop.create_task( +        self.init_refresh_task = scheduling.create_task(              self.init_refresh_inventory(), -            name="Doc inventory init" +            name="Doc inventory init", +            event_loop=self.bot.loop,          )      @lock(NAMESPACE, COMMAND_LOCK_SINGLETON, raise_error=True) @@ -456,4 +458,4 @@ class DocCog(commands.Cog):          """Clear scheduled inventories, queued symbols and cleanup task on cog unload."""          self.inventory_scheduler.cancel_all()          self.init_refresh_task.cancel() -        asyncio.create_task(self.item_fetcher.clear(), name="DocCog.item_fetcher unload clear") +        scheduling.create_task(self.item_fetcher.clear(), name="DocCog.item_fetcher unload clear") diff --git a/bot/exts/info/pep.py b/bot/exts/info/pep.py index b11b34db0..bbd112911 100644 --- a/bot/exts/info/pep.py +++ b/bot/exts/info/pep.py @@ -9,6 +9,7 @@ from discord.ext.commands import Cog, Context, command  from bot.bot import Bot  from bot.constants import Keys +from bot.utils import scheduling  from bot.utils.caching import AsyncCache  log = logging.getLogger(__name__) @@ -32,7 +33,7 @@ class PythonEnhancementProposals(Cog):          self.peps: Dict[int, str] = {}          # To avoid situations where we don't have last datetime, set this to now.          self.last_refreshed_peps: datetime = datetime.now() -        self.bot.loop.create_task(self.refresh_peps_urls()) +        scheduling.create_task(self.refresh_peps_urls(), event_loop=self.bot.loop)      async def refresh_peps_urls(self) -> None:          """Refresh PEP URLs listing in every 3 hours.""" diff --git a/bot/exts/info/python_news.py b/bot/exts/info/python_news.py index 63eb4ac17..58dcd3a02 100644 --- a/bot/exts/info/python_news.py +++ b/bot/exts/info/python_news.py @@ -11,6 +11,7 @@ from discord.ext.tasks import loop  from bot import constants  from bot.bot import Bot +from bot.utils import scheduling  from bot.utils.webhooks import send_webhook  PEPS_RSS_URL = "https://www.python.org/dev/peps/peps.rss/" @@ -33,8 +34,8 @@ class PythonNews(Cog):          self.webhook_names = {}          self.webhook: t.Optional[discord.Webhook] = None -        self.bot.loop.create_task(self.get_webhook_names()) -        self.bot.loop.create_task(self.get_webhook_and_channel()) +        scheduling.create_task(self.get_webhook_names(), event_loop=self.bot.loop) +        scheduling.create_task(self.get_webhook_and_channel(), event_loop=self.bot.loop)      async def start_tasks(self) -> None:          """Start the tasks for fetching new PEPs and mailing list messages.""" diff --git a/bot/exts/moderation/defcon.py b/bot/exts/moderation/defcon.py index 6ac077b93..ac813d6ba 100644 --- a/bot/exts/moderation/defcon.py +++ b/bot/exts/moderation/defcon.py @@ -1,4 +1,3 @@ -import asyncio  import logging  import traceback  from collections import namedtuple @@ -17,6 +16,7 @@ from bot.bot import Bot  from bot.constants import Channels, Colours, Emojis, Event, Icons, MODERATION_ROLES, Roles  from bot.converters import DurationDelta, Expiry  from bot.exts.moderation.modlog import ModLog +from bot.utils import scheduling  from bot.utils.messages import format_user  from bot.utils.scheduling import Scheduler  from bot.utils.time import ( @@ -69,7 +69,7 @@ class Defcon(Cog):          self.scheduler = Scheduler(self.__class__.__name__) -        self.bot.loop.create_task(self._sync_settings()) +        scheduling.create_task(self._sync_settings(), event_loop=self.bot.loop)      @property      def mod_log(self) -> ModLog: @@ -205,7 +205,7 @@ class Defcon(Cog):          new_topic = f"{BASE_CHANNEL_TOPIC}\n(Threshold: {humanize_delta(self.threshold) if self.threshold else '-'})"          self.mod_log.ignore(Event.guild_channel_update, Channels.defcon) -        asyncio.create_task(self.channel.edit(topic=new_topic)) +        scheduling.create_task(self.channel.edit(topic=new_topic))      @defcon_settings.atomic_transaction      async def _update_threshold(self, author: User, threshold: relativedelta, expiry: Optional[Expiry] = None) -> None: diff --git a/bot/exts/moderation/incidents.py b/bot/exts/moderation/incidents.py index 561e0251e..a3d90e3fe 100644 --- a/bot/exts/moderation/incidents.py +++ b/bot/exts/moderation/incidents.py @@ -9,6 +9,7 @@ from discord.ext.commands import Cog  from bot.bot import Bot  from bot.constants import Channels, Colours, Emojis, Guild, Webhooks +from bot.utils import scheduling  from bot.utils.messages import sub_clyde  log = logging.getLogger(__name__) @@ -190,7 +191,7 @@ class Incidents(Cog):          self.bot = bot          self.event_lock = asyncio.Lock() -        self.crawl_task = self.bot.loop.create_task(self.crawl_incidents()) +        self.crawl_task = scheduling.create_task(self.crawl_incidents(), event_loop=self.bot.loop)      async def crawl_incidents(self) -> None:          """ @@ -275,7 +276,7 @@ class Incidents(Cog):              return payload.message_id == incident.id          coroutine = self.bot.wait_for(event="raw_message_delete", check=check, timeout=timeout) -        return self.bot.loop.create_task(coroutine) +        return scheduling.create_task(coroutine, event_loop=self.bot.loop)      async def process_event(self, reaction: str, incident: discord.Message, member: discord.Member) -> None:          """ diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py index 6ba4e74e9..8e844822d 100644 --- a/bot/exts/moderation/infraction/_scheduler.py +++ b/bot/exts/moderation/infraction/_scheduler.py @@ -29,7 +29,7 @@ class InfractionScheduler:          self.bot = bot          self.scheduler = scheduling.Scheduler(self.__class__.__name__) -        self.bot.loop.create_task(self.reschedule_infractions(supported_infractions)) +        scheduling.create_task(self.reschedule_infractions(supported_infractions), event_loop=self.bot.loop)      def cog_unload(self) -> None:          """Cancel scheduled tasks.""" diff --git a/bot/exts/moderation/metabase.py b/bot/exts/moderation/metabase.py index 9eeeec074..6eadd4bad 100644 --- a/bot/exts/moderation/metabase.py +++ b/bot/exts/moderation/metabase.py @@ -14,7 +14,7 @@ from discord.ext.commands import Cog, Context, group, has_any_role  from bot.bot import Bot  from bot.constants import Metabase as MetabaseConfig, Roles  from bot.converters import allowed_strings -from bot.utils import send_to_paste_service +from bot.utils import scheduling, send_to_paste_service  from bot.utils.channel import is_mod_channel  from bot.utils.scheduling import Scheduler @@ -40,7 +40,7 @@ class Metabase(Cog):          self.exports: Dict[int, List[Dict]] = {}  # Saves the output of each question, so internal eval can access it -        self.init_task = self.bot.loop.create_task(self.init_cog()) +        self.init_task = scheduling.create_task(self.init_cog(), event_loop=self.bot.loop)      async def cog_command_error(self, ctx: Context, error: Exception) -> None:          """Handle ClientResponseError errors locally to invalidate token if needed.""" diff --git a/bot/exts/moderation/modpings.py b/bot/exts/moderation/modpings.py index 80c9f0c38..d775cdedf 100644 --- a/bot/exts/moderation/modpings.py +++ b/bot/exts/moderation/modpings.py @@ -9,6 +9,7 @@ from discord.ext.commands import Cog, Context, group, has_any_role  from bot.bot import Bot  from bot.constants import Colours, Emojis, Guild, Icons, MODERATION_ROLES, Roles  from bot.converters import Expiry +from bot.utils import scheduling  from bot.utils.scheduling import Scheduler  log = logging.getLogger(__name__) @@ -29,7 +30,11 @@ class ModPings(Cog):          self.guild = None          self.moderators_role = None -        self.reschedule_task = self.bot.loop.create_task(self.reschedule_roles(), name="mod-pings-reschedule") +        self.reschedule_task = scheduling.create_task( +            self.reschedule_roles(), +            name="mod-pings-reschedule", +            event_loop=self.bot.loop, +        )      async def reschedule_roles(self) -> None:          """Reschedule moderators role re-apply times.""" diff --git a/bot/exts/moderation/silence.py b/bot/exts/moderation/silence.py index 95e2792c3..2ee6496df 100644 --- a/bot/exts/moderation/silence.py +++ b/bot/exts/moderation/silence.py @@ -13,6 +13,7 @@ from discord.ext.commands import Context  from bot import constants  from bot.bot import Bot  from bot.converters import HushDurationConverter +from bot.utils import scheduling  from bot.utils.lock import LockedResourceError, lock, lock_arg  from bot.utils.scheduling import Scheduler @@ -104,7 +105,7 @@ class Silence(commands.Cog):          self.bot = bot          self.scheduler = Scheduler(self.__class__.__name__) -        self._init_task = self.bot.loop.create_task(self._async_init()) +        self._init_task = scheduling.create_task(self._async_init(), event_loop=self.bot.loop)      async def _async_init(self) -> None:          """Set instance attributes once the guild is available and reschedule unsilences.""" diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py index 01d2614b0..b5bd62a71 100644 --- a/bot/exts/moderation/stream.py +++ b/bot/exts/moderation/stream.py @@ -15,7 +15,7 @@ from bot.constants import (  )  from bot.converters import Expiry  from bot.pagination import LinePaginator -from bot.utils.scheduling import Scheduler +from bot.utils import scheduling  from bot.utils.time import discord_timestamp, format_infraction_with_duration  log = logging.getLogger(__name__) @@ -30,8 +30,8 @@ class Stream(commands.Cog):      def __init__(self, bot: Bot):          self.bot = bot -        self.scheduler = Scheduler(self.__class__.__name__) -        self.reload_task = self.bot.loop.create_task(self._reload_tasks_from_redis()) +        self.scheduler = scheduling.Scheduler(self.__class__.__name__) +        self.reload_task = scheduling.create_task(self._reload_tasks_from_redis(), event_loop=self.bot.loop)      def cog_unload(self) -> None:          """Cancel all scheduled tasks.""" diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index 146426569..a42e1f518 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -18,7 +18,7 @@ from bot.exts.filters.token_remover import TokenRemover  from bot.exts.filters.webhook_remover import WEBHOOK_URL_RE  from bot.exts.moderation.modlog import ModLog  from bot.pagination import LinePaginator -from bot.utils import CogABCMeta, messages +from bot.utils import CogABCMeta, messages, scheduling  from bot.utils.time import get_time_delta  log = logging.getLogger(__name__) @@ -69,7 +69,7 @@ class WatchChannel(metaclass=CogABCMeta):          self.message_history = MessageHistory()          self.disable_header = disable_header -        self._start = self.bot.loop.create_task(self.start_watchchannel()) +        self._start = scheduling.create_task(self.start_watchchannel(), event_loop=self.bot.loop)      @property      def modlog(self) -> ModLog: @@ -169,7 +169,7 @@ class WatchChannel(metaclass=CogABCMeta):          """Queues up messages sent by watched users."""          if msg.author.id in self.watched_users:              if not self.consuming_messages: -                self._consume_task = self.bot.loop.create_task(self.consume_messages()) +                self._consume_task = scheduling.create_task(self.consume_messages(), event_loop=self.bot.loop)              self.log.trace(f"Received message: {msg.content} ({len(msg.attachments)} attachments)")              self.message_queue[msg.author.id][msg.channel.id].append(msg) @@ -199,7 +199,10 @@ class WatchChannel(metaclass=CogABCMeta):          if self.message_queue:              self.log.trace("Channel queue not empty: Continuing consuming queues") -            self._consume_task = self.bot.loop.create_task(self.consume_messages(delay_consumption=False)) +            self._consume_task = scheduling.create_task( +                self.consume_messages(delay_consumption=False), +                event_loop=self.bot.loop, +            )          else:              self.log.trace("Done consuming messages.") diff --git a/bot/exts/utils/reminders.py b/bot/exts/utils/reminders.py index 41b6cac5c..1030357fd 100644 --- a/bot/exts/utils/reminders.py +++ b/bot/exts/utils/reminders.py @@ -1,4 +1,3 @@ -import asyncio  import logging  import random  import textwrap @@ -17,6 +16,7 @@ from bot.constants import (  )  from bot.converters import Duration, UnambiguousUser  from bot.pagination import LinePaginator +from bot.utils import scheduling  from bot.utils.checks import has_any_role_check, has_no_roles_check  from bot.utils.lock import lock_arg  from bot.utils.messages import send_denial @@ -40,7 +40,7 @@ class Reminders(Cog):          self.bot = bot          self.scheduler = Scheduler(self.__class__.__name__) -        self.bot.loop.create_task(self.reschedule_reminders()) +        scheduling.create_task(self.reschedule_reminders(), event_loop=self.bot.loop)      def cog_unload(self) -> None:          """Cancel scheduled tasks.""" @@ -80,7 +80,7 @@ class Reminders(Cog):                  f"Reminder {reminder['id']} invalid: "                  f"User {reminder['author']}={user}, Channel {reminder['channel_id']}={channel}."              ) -            asyncio.create_task(self.bot.api_client.delete(f"bot/reminders/{reminder['id']}")) +            scheduling.create_task(self.bot.api_client.delete(f"bot/reminders/{reminder['id']}"))          return is_valid, user, channel diff --git a/bot/exts/utils/snekbox.py b/bot/exts/utils/snekbox.py index b1f1ba6a8..5fb10a25b 100644 --- a/bot/exts/utils/snekbox.py +++ b/bot/exts/utils/snekbox.py @@ -14,7 +14,7 @@ from discord.ext.commands import Cog, Context, command, guild_only  from bot.bot import Bot  from bot.constants import Categories, Channels, Roles, URLs  from bot.decorators import redirect_output -from bot.utils import send_to_paste_service +from bot.utils import scheduling, send_to_paste_service  from bot.utils.messages import wait_for_deletion  log = logging.getLogger(__name__) @@ -219,7 +219,7 @@ class Snekbox(Cog):                  response = await ctx.send("Attempt to circumvent filter detected. Moderator team has been alerted.")              else:                  response = await ctx.send(msg) -            self.bot.loop.create_task(wait_for_deletion(response, (ctx.author.id,))) +            scheduling.create_task(wait_for_deletion(response, (ctx.author.id,)), event_loop=self.bot.loop)              log.info(f"{ctx.author}'s job had a return code of {results['returncode']}")          return response diff --git a/tests/bot/exts/backend/sync/test_cog.py b/tests/bot/exts/backend/sync/test_cog.py index 22a07313e..fdd0ab74a 100644 --- a/tests/bot/exts/backend/sync/test_cog.py +++ b/tests/bot/exts/backend/sync/test_cog.py @@ -60,13 +60,13 @@ class SyncCogTestCase(unittest.IsolatedAsyncioTestCase):  class SyncCogTests(SyncCogTestCase):      """Tests for the Sync cog.""" +    @mock.patch("bot.utils.scheduling.create_task")      @mock.patch.object(Sync, "sync_guild", new_callable=mock.MagicMock) -    def test_sync_cog_init(self, sync_guild): +    def test_sync_cog_init(self, sync_guild, create_task):          """Should instantiate syncers and run a sync for the guild."""          # Reset because a Sync cog was already instantiated in setUp.          self.RoleSyncer.reset_mock()          self.UserSyncer.reset_mock() -        self.bot.loop.create_task = mock.MagicMock()          mock_sync_guild_coro = mock.MagicMock()          sync_guild.return_value = mock_sync_guild_coro @@ -74,7 +74,8 @@ class SyncCogTests(SyncCogTestCase):          Sync(self.bot)          sync_guild.assert_called_once_with() -        self.bot.loop.create_task.assert_called_once_with(mock_sync_guild_coro) +        create_task.assert_called_once() +        self.assertEqual(create_task.call_args.args[0], mock_sync_guild_coro)      async def test_sync_cog_sync_guild(self):          """Roles and users should be synced only if a guild is successfully retrieved.""" diff --git a/tests/helpers.py b/tests/helpers.py index 3978076ed..47f06f292 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -278,7 +278,10 @@ def _get_mock_loop() -> unittest.mock.Mock:      # Since calling `create_task` on our MockBot does not actually schedule the coroutine object      # as a task in the asyncio loop, this `side_effect` calls `close()` on the coroutine object      # to prevent "has not been awaited"-warnings. -    loop.create_task.side_effect = lambda coroutine: coroutine.close() +    def mock_create_task(coroutine, **kwargs): +        coroutine.close() +        return unittest.mock.Mock() +    loop.create_task.side_effect = mock_create_task      return loop | 
