diff --git a/redbot/__main__.py b/redbot/__main__.py index eb3a6af0c..a15b9d2a6 100644 --- a/redbot/__main__.py +++ b/redbot/__main__.py @@ -1,7 +1,5 @@ #!/usr/bin/env python -# Discord Version check - import asyncio import functools import getpass @@ -20,7 +18,7 @@ from typing import NoReturn import discord -# Set the event loop policies here so any subsequent `get_event_loop()` +# Set the event loop policies here so any subsequent `new_event_loop()` # calls, in particular those as a result of the following imports, # return the correct loop object. from redbot import _update_event_loop_policy, __version__ @@ -298,7 +296,8 @@ def handle_edit(cli_flags: Namespace): """ This one exists to not log all the things like it's a full run of the bot. """ - loop = asyncio.get_event_loop() + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) data_manager.load_basic_configuration(cli_flags.instance_name) red = Red(cli_flags=cli_flags, description="Red V3", dm_help=None, fetch_offline_members=True) try: @@ -310,6 +309,7 @@ def handle_edit(cli_flags: Namespace): print("Aborted!") finally: loop.run_until_complete(asyncio.sleep(1)) + asyncio.set_event_loop(None) loop.stop() loop.close() sys.exit(0) @@ -460,7 +460,8 @@ def main(): handle_edit(cli_flags) return try: - loop = asyncio.get_event_loop() + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) if cli_flags.no_instance: print( @@ -524,6 +525,7 @@ def main(): # results in a resource warning instead log.info("Please wait, cleaning up a bit more") loop.run_until_complete(asyncio.sleep(2)) + asyncio.set_event_loop(None) loop.stop() loop.close() exit_code = red._shutdown_mode if red is not None else 1 diff --git a/redbot/cogs/downloader/downloader.py b/redbot/cogs/downloader/downloader.py index ed48f8cfd..162a748af 100644 --- a/redbot/cogs/downloader/downloader.py +++ b/redbot/cogs/downloader/downloader.py @@ -462,7 +462,7 @@ class Downloader(commands.Cog): if not deps: await ctx.send_help() return - repo = Repo("", "", "", "", Path.cwd(), loop=ctx.bot.loop) + repo = Repo("", "", "", "", Path.cwd()) async with ctx.typing(): success = await repo.install_raw_requirements(deps, self.LIB_PATH) diff --git a/redbot/cogs/downloader/repo_manager.py b/redbot/cogs/downloader/repo_manager.py index fe786ef98..f05a4b94e 100644 --- a/redbot/cogs/downloader/repo_manager.py +++ b/redbot/cogs/downloader/repo_manager.py @@ -135,7 +135,6 @@ class Repo(RepoJSONMixin): commit: str, folder_path: Path, available_modules: Tuple[Installable, ...] = (), - loop: Optional[asyncio.AbstractEventLoop] = None, ): self.url = url self.branch = branch @@ -154,8 +153,6 @@ class Repo(RepoJSONMixin): self._repo_lock = asyncio.Lock() - self._loop = loop if loop is not None else asyncio.get_event_loop() - @property def clean_url(self) -> str: """Sanitized repo URL (with removed HTTP Basic Auth)""" @@ -529,7 +526,7 @@ class Repo(RepoJSONMixin): env["LANGUAGE"] = "C" kwargs["env"] = env async with self._repo_lock: - p: CompletedProcess = await self._loop.run_in_executor( + p: CompletedProcess = await asyncio.get_running_loop().run_in_executor( self._executor, functools.partial(sp_run, *args, stdout=PIPE, stderr=PIPE, **kwargs), ) diff --git a/redbot/core/utils/__init__.py b/redbot/core/utils/__init__.py index dfdab23b0..0da1213df 100644 --- a/redbot/core/utils/__init__.py +++ b/redbot/core/utils/__init__.py @@ -1,4 +1,5 @@ import asyncio +import warnings from asyncio import AbstractEventLoop, as_completed, Semaphore from asyncio.futures import isfuture from itertools import chain @@ -177,14 +178,20 @@ def bounded_gather_iter( TypeError When invalid parameters are passed """ - if loop is None: - loop = asyncio.get_event_loop() + if loop is not None: + warnings.warn( + "Explicitly passing the loop will not work in Red 3.4+ and is currently ignored." + "Call this from the related event loop.", + DeprecationWarning, + ) + + loop = asyncio.get_running_loop() if semaphore is None: if not isinstance(limit, int) or limit <= 0: raise TypeError("limit must be an int > 0") - semaphore = Semaphore(limit, loop=loop) + semaphore = Semaphore(limit) pending = [] @@ -195,7 +202,7 @@ def bounded_gather_iter( cof = _sem_wrapper(semaphore, cof) pending.append(cof) - return as_completed(pending, loop=loop) + return as_completed(pending) def bounded_gather( @@ -228,15 +235,21 @@ def bounded_gather( TypeError When invalid parameters are passed """ - if loop is None: - loop = asyncio.get_event_loop() + if loop is not None: + warnings.warn( + "Explicitly passing the loop will not work in Red 3.4+ and is currently ignored." + "Call this from the related event loop.", + DeprecationWarning, + ) + + loop = asyncio.get_running_loop() if semaphore is None: if not isinstance(limit, int) or limit <= 0: raise TypeError("limit must be an int > 0") - semaphore = Semaphore(limit, loop=loop) + semaphore = Semaphore(limit) tasks = (_sem_wrapper(semaphore, task) for task in coros_or_futures) - return asyncio.gather(*tasks, loop=loop, return_exceptions=return_exceptions) + return asyncio.gather(*tasks, return_exceptions=return_exceptions) diff --git a/redbot/core/utils/menus.py b/redbot/core/utils/menus.py index 6305b19ff..f4e9cf364 100644 --- a/redbot/core/utils/menus.py +++ b/redbot/core/utils/menus.py @@ -5,6 +5,7 @@ import asyncio import contextlib import functools +import warnings from typing import Union, Iterable, Optional import discord @@ -200,7 +201,9 @@ def start_adding_reactions( await message.add_reaction(emoji) if loop is None: - loop = asyncio.get_event_loop() + loop = asyncio.get_running_loop() + else: + warnings.warn("Explicitly passing the loop will not work in Red 3.4+", DeprecationWarning) return loop.create_task(task()) diff --git a/redbot/pytest/downloader.py b/redbot/pytest/downloader.py index 0ac043791..dbeb2e6f6 100644 --- a/redbot/pytest/downloader.py +++ b/redbot/pytest/downloader.py @@ -76,7 +76,6 @@ def bot_repo(event_loop): commit="", url="https://empty.com/something.git", folder_path=cwd, - loop=event_loop, ) @@ -163,14 +162,7 @@ def _init_test_repo(destination: Path): async def _session_git_repo(tmp_path_factory, event_loop): # we will import repo only once once per session and duplicate the repo folder repo_path = tmp_path_factory.mktemp("session_git_repo") - repo = Repo( - name="redbot-testrepo", - url="", - branch="master", - commit="", - folder_path=repo_path, - loop=event_loop, - ) + repo = Repo(name="redbot-testrepo", url="", branch="master", commit="", folder_path=repo_path) git_dirparams = _init_test_repo(repo_path) fast_import = sp.Popen((*git_dirparams, "fast-import", "--quiet"), stdin=sp.PIPE) with TEST_REPO_EXPORT_PTH.open(mode="rb") as f: @@ -193,7 +185,6 @@ async def git_repo(_session_git_repo, tmp_path, event_loop): branch=_session_git_repo.branch, commit=_session_git_repo.commit, folder_path=repo_path, - loop=event_loop, ) return repo @@ -208,7 +199,6 @@ async def cloned_git_repo(_session_git_repo, tmp_path, event_loop): branch=_session_git_repo.branch, commit=_session_git_repo.commit, folder_path=repo_path, - loop=event_loop, ) sp.run(("git", "clone", str(_session_git_repo.folder_path), str(repo_path)), check=True) return repo @@ -224,7 +214,6 @@ async def git_repo_with_remote(git_repo, tmp_path, event_loop): branch=git_repo.branch, commit=git_repo.commit, folder_path=repo_path, - loop=event_loop, ) sp.run(("git", "clone", str(git_repo.folder_path), str(repo_path)), check=True) return repo diff --git a/redbot/setup.py b/redbot/setup.py index 2be440acc..5ed245a5e 100644 --- a/redbot/setup.py +++ b/redbot/setup.py @@ -371,8 +371,7 @@ def delete( remove_datapath: Optional[bool], ): """Removes an instance.""" - loop = asyncio.get_event_loop() - loop.run_until_complete( + asyncio.run( remove_instance( instance, interactive, delete_data, _create_backup, drop_db, remove_datapath ) @@ -391,14 +390,12 @@ def convert(instance, backend): default_dirs = deepcopy(data_manager.basic_config_default) default_dirs["DATA_PATH"] = str(Path(instance_data[instance]["DATA_PATH"])) - loop = asyncio.get_event_loop() - if current_backend == BackendType.MONGOV1: raise RuntimeError("Please see the 3.2 release notes for upgrading a bot using mongo.") elif current_backend == BackendType.POSTGRES: # TODO: GH-3115 raise RuntimeError("Converting away from postgres isn't currently supported") else: - new_storage_details = loop.run_until_complete(do_migration(current_backend, target)) + new_storage_details = asyncio.run(do_migration(current_backend, target)) if new_storage_details is not None: default_dirs["STORAGE_TYPE"] = target.value @@ -422,8 +419,7 @@ def convert(instance, backend): ) def backup(instance: str, destination_folder: Union[str, Path]) -> None: """Backup instance's data.""" - loop = asyncio.get_event_loop() - loop.run_until_complete(create_backup(instance, Path(destination_folder))) + asyncio.run(create_backup(instance, Path(destination_folder))) def run_cli(): diff --git a/tests/conftest.py b/tests/conftest.py index cb420c900..32038d835 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,8 +12,10 @@ _update_event_loop_policy() @pytest.fixture(scope="session") def event_loop(request): """Create an instance of the default event loop for entire session.""" - loop = asyncio.get_event_loop_policy().new_event_loop() + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) yield loop + asyncio.set_event_loop(None) loop.close()