Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up asyncio deprecations #675

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cloudbot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from cloudbot.hook import Action
from cloudbot.plugin import PluginManager
from cloudbot.reloader import ConfigReloader, PluginReloader
from cloudbot.util import async_util, database, formatting
from cloudbot.util import database, formatting
from cloudbot.util.mapping import KeyFoldDict

logger = logging.getLogger("cloudbot")
Expand Down Expand Up @@ -108,7 +108,7 @@ def __init__(
self.running = True
self.clients: Dict[str, Type[Client]] = {}
# future which will be called when the bot stopsIf you
self.stopped_future = async_util.create_future(self.loop)
self.stopped_future = self.loop.create_future()

# stores each bot server connection
self.connections = KeyFoldDict()
Expand Down
3 changes: 1 addition & 2 deletions cloudbot/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from typing import Any, Dict

from cloudbot.permissions import PermissionManager
from cloudbot.util import async_util

logger = logging.getLogger("cloudbot")

Expand Down Expand Up @@ -66,7 +65,7 @@ def __init__(self, bot, _type, name, nick, *, channels=None, config=None):

self._active = False

self.cancelled_future = async_util.create_future(self.loop)
self.cancelled_future = self.loop.create_future()

def describe_server(self):
raise NotImplementedError
Expand Down
10 changes: 5 additions & 5 deletions cloudbot/clients/irc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from cloudbot.client import Client, ClientConnectError, client
from cloudbot.event import Event, EventType, IrcOutEvent
from cloudbot.util import async_util, colors
from cloudbot.util import colors

logger = logging.getLogger("cloudbot")

Expand Down Expand Up @@ -391,7 +391,7 @@ def _send(self, line, log=True):
"""
Sends a raw IRC line unchecked. Doesn't do connected check, and is *not* threadsafe
"""
async_util.wrap_future(
asyncio.ensure_future(
self._protocol.send(line, log=log), loop=self.loop
)

Expand Down Expand Up @@ -423,7 +423,7 @@ def __init__(self, conn):
self._transport = None

# Future that waits until we are connected
self._connected_future = async_util.create_future(self.loop)
self._connected_future = self.loop.create_future()

def connection_made(self, transport):
self._transport = transport
Expand All @@ -438,7 +438,7 @@ def connection_lost(self, exc):
if exc:
logger.error("[%s] Connection lost: %s", self.conn.name, exc)

async_util.wrap_future(self.conn.auto_reconnect(), loop=self.loop)
asyncio.ensure_future(self.conn.auto_reconnect(), loop=self.loop)

def close(self):
self._connecting = False
Expand Down Expand Up @@ -522,7 +522,7 @@ def data_received(self, data):
)
else:
# handle the message, async
async_util.wrap_future(self.bot.process(event), loop=self.loop)
asyncio.ensure_future(self.bot.process(event), loop=self.loop)

def parse_line(self, line: str) -> Event:
message = Message.parse(line)
Expand Down
8 changes: 4 additions & 4 deletions cloudbot/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
SieveHook,
hook_name_to_plugin,
)
from cloudbot.util import HOOK_ATTR, LOADED_ATTR, async_util, database
from cloudbot.util import HOOK_ATTR, LOADED_ATTR, database
from cloudbot.util.func_utils import call_with_args

logger = logging.getLogger("cloudbot")
Expand Down Expand Up @@ -310,7 +310,7 @@ async def load_plugin(self, path):
self._log_hook(on_cap_ack_hook)

for periodic_hook in plugin.hooks["periodic"]:
task = async_util.wrap_future(self._start_periodic(periodic_hook))
task = asyncio.ensure_future(self._start_periodic(periodic_hook))
plugin.tasks.append(task)
self._log_hook(periodic_hook)

Expand Down Expand Up @@ -566,7 +566,7 @@ async def internal_launch(self, hook, event):
else:
coro = self._execute_hook_sync(hook, event)

task = async_util.wrap_future(coro)
task = asyncio.ensure_future(coro)
hook.plugin.tasks.append(task)
try:
out = await task
Expand Down Expand Up @@ -621,7 +621,7 @@ async def _sieve(self, sieve, event, hook):
coro = sieve.function(self.bot, event, hook)

result, error = None, None
task = async_util.wrap_future(coro)
task = asyncio.ensure_future(coro)
sieve.plugin.tasks.append(task)
try:
result = await task
Expand Down
29 changes: 0 additions & 29 deletions cloudbot/util/async_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,10 @@
"""

import asyncio
from asyncio import AbstractEventLoop
from asyncio.tasks import Task
from functools import partial
from typing import List, Optional, cast

from cloudbot.util.func_utils import call_with_args

try:
_asyncio_get_tasks = getattr(asyncio, "all_tasks")
except AttributeError:
_asyncio_get_tasks = getattr(Task, "all_tasks")


def wrap_future(fut, *, loop=None):
"""
Wraps asyncio.ensure_future()
:param fut: The awaitable, future, or coroutine to wrap
:param loop: The loop to run in
:return: The wrapped future
"""
return asyncio.ensure_future(fut, loop=loop)


async def run_func(loop, func, *args, **kwargs):
part = partial(func, *args, **kwargs)
Expand Down Expand Up @@ -56,14 +38,3 @@ def run_coroutine_threadsafe(coro, loop):
raise TypeError("A coroutine object is required")

asyncio.run_coroutine_threadsafe(coro, loop)


def create_future(loop):
return loop.create_future()


def get_all_tasks(loop: Optional[AbstractEventLoop] = None) -> List[Task]:
"""
Get a list of all tasks for the current loop
"""
return cast(List[Task], _asyncio_get_tasks(loop))
2 changes: 1 addition & 1 deletion plugins/core/cap.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async def handle_available_caps(conn, caplist, event, irc_paramlist, bot):
]
results = await asyncio.gather(*tasks)
if any(ok and (res or res is None) for ok, res in results):
cap_queue[name_cf] = async_util.create_future(conn.loop)
cap_queue[name_cf] = conn.loop.create_future()
conn.cmd("CAP", "REQ", name)

if irc_paramlist[2] != "*":
Expand Down
5 changes: 2 additions & 3 deletions plugins/core/sasl.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import logging

from cloudbot import hook
from cloudbot.util import async_util

logger = logging.getLogger("cloudbot")

Expand All @@ -18,14 +17,14 @@ async def sasl_ack(conn):
sasl_auth = conn.config.get("sasl")
if sasl_auth and sasl_auth.get("enabled", True):
sasl_mech = sasl_auth.get("mechanism", "PLAIN").upper()
auth_fut = async_util.create_future(conn.loop)
auth_fut = conn.loop.create_future()
conn.memory["sasl_auth_future"] = auth_fut
conn.cmd("AUTHENTICATE", sasl_mech)
cmd, arg = await auth_fut
if cmd == "908":
logger.warning("[%s|sasl] SASL mechanism not supported", conn.name)
elif cmd == "AUTHENTICATE" and arg[0] == "+":
num_fut = async_util.create_future(conn.loop)
num_fut = conn.loop.create_future()
conn.memory["sasl_numeric_future"] = num_fut
if sasl_mech == "PLAIN":
auth_str = "{user}\0{user}\0{passwd}".format(
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mypy == 1.9.0
pre-commit == 3.3.3
pylint == 3.1.0
pytest == 8.1.1
pytest-asyncio == 0.20.3
pytest-asyncio == 0.23.5.post1
pytest-cov == 4.1.0
pytest-random-order == 1.1.1
responses == 0.25.0
Expand Down
33 changes: 16 additions & 17 deletions tests/core_tests/irc_client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from cloudbot.client import ClientConnectError
from cloudbot.clients import irc
from cloudbot.event import Event, EventType
from cloudbot.util import async_util
from tests.util.async_mock import AsyncMock

if TYPE_CHECKING:
Expand Down Expand Up @@ -53,7 +52,7 @@ def test_send_closed(event_loop):
class TestLineParsing:
@staticmethod
def wait_tasks(conn, cancel=False):
tasks = async_util.get_all_tasks(conn.loop)
tasks = asyncio.all_tasks(conn.loop)
if cancel:
for task in tasks:
task.cancel()
Expand Down Expand Up @@ -440,8 +439,8 @@ def test_parse_pm_privmsg(self, caplog_bot, event_loop):


class TestConnect:
async def make_client(self, event_loop) -> irc.IrcClient:
bot = MagicMock(loop=event_loop, config={})
async def make_client(self) -> irc.IrcClient:
bot = MagicMock(loop=asyncio.get_running_loop(), config={})
conn_config = {
"connection": {
"server": "host.invalid",
Expand All @@ -457,8 +456,8 @@ async def make_client(self, event_loop) -> irc.IrcClient:
return client

@pytest.mark.asyncio()
async def test_exc(self, caplog_bot, event_loop):
client = await self.make_client(event_loop)
async def test_exc(self, caplog_bot):
client = await self.make_client()
runs = 0

# noinspection PyUnusedLocal
Expand Down Expand Up @@ -520,8 +519,8 @@ async def connect(timeout):
assert client.bot.mock_calls == []

@pytest.mark.asyncio()
async def test_timeout_exc(self, caplog_bot, event_loop):
client = await self.make_client(event_loop)
async def test_timeout_exc(self, caplog_bot):
client = await self.make_client()
runs = 0

# noinspection PyUnusedLocal
Expand Down Expand Up @@ -578,8 +577,8 @@ async def connect(timeout):
assert client.bot.mock_calls == []

@pytest.mark.asyncio()
async def test_other_exc(self, caplog_bot, event_loop):
client = await self.make_client(event_loop)
async def test_other_exc(self, caplog_bot):
client = await self.make_client()

client.connect = AsyncMock() # type: ignore
client.connect.side_effect = Exception("foo")
Expand All @@ -605,8 +604,8 @@ async def test_other_exc(self, caplog_bot, event_loop):
assert client.bot.mock_calls == []

@pytest.mark.asyncio()
async def test_one_connect(self, caplog_bot, event_loop):
client = await self.make_client(event_loop)
async def test_one_connect(self, caplog_bot):
client = await self.make_client()

async def _connect(timeout=5):
await asyncio.sleep(timeout)
Expand Down Expand Up @@ -636,8 +635,8 @@ async def _connect(timeout=5):
assert client.bot.mock_calls == []

@pytest.mark.asyncio()
async def test_create_socket(self, caplog_bot, event_loop):
client = await self.make_client(event_loop)
async def test_create_socket(self, caplog_bot):
client = await self.make_client()
client.loop.create_connection = mock = MagicMock()
fut: "Future[Tuple[None, None]]" = asyncio.Future(loop=client.loop)
fut.set_result((None, None))
Expand Down Expand Up @@ -668,14 +667,14 @@ async def test_create_socket(self, caplog_bot, event_loop):

class TestSend:
@pytest.mark.asyncio()
async def test_send_sieve_error(self, caplog_bot, event_loop):
conn = make_mock_conn(event_loop=event_loop)
async def test_send_sieve_error(self, caplog_bot):
conn = make_mock_conn(event_loop=asyncio.get_running_loop())
proto = irc._IrcProtocol(conn)
proto.connection_made(MagicMock())
sieve = object()
proto.bot.plugin_manager.out_sieves = [sieve]
proto.bot.plugin_manager.internal_launch = launch = MagicMock()
fut = async_util.create_future(proto.loop)
fut = proto.loop.create_future()
fut.set_result((False, None))
launch.return_value = fut

Expand Down
22 changes: 10 additions & 12 deletions tests/core_tests/reloader_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

class TestConfigReload:
@pytest.mark.asyncio()
async def test_reload(self, mock_bot_factory, tmp_path, event_loop) -> None:
async def test_reload(self, mock_bot_factory, tmp_path) -> None:
config_file = tmp_path / "config.json"
config_file.touch()
bot = mock_bot_factory(loop=event_loop)
bot = mock_bot_factory()
reloader = ConfigReloader(bot)
bot.running = True
with patch.object(
Expand All @@ -25,12 +25,10 @@ async def test_reload(self, mock_bot_factory, tmp_path, event_loop) -> None:
assert mocked.mock_calls == [call()]

@pytest.mark.asyncio()
async def test_reload_not_running(
self, mock_bot_factory, tmp_path, event_loop
):
async def test_reload_not_running(self, mock_bot_factory, tmp_path):
config_file = tmp_path / "config.json"
config_file.touch()
bot = mock_bot_factory(loop=event_loop)
bot = mock_bot_factory()
reloader = ConfigReloader(bot)
bot.running = False
with patch.object(
Expand All @@ -45,12 +43,12 @@ async def test_reload_not_running(

class TestPluginReload:
@pytest.mark.asyncio()
async def test_reload(self, mock_bot_factory, tmp_path, event_loop):
async def test_reload(self, mock_bot_factory, tmp_path):
plugin_dir = tmp_path / "plugins"
plugin_dir.mkdir()
plugin_file = plugin_dir / "plugin.py"
plugin_file.touch()
bot = mock_bot_factory(loop=event_loop)
bot = mock_bot_factory()
reloader = PluginReloader(bot)
with patch.object(
reloader, "_reload", new_callable=AsyncMock
Expand All @@ -62,11 +60,11 @@ async def test_reload(self, mock_bot_factory, tmp_path, event_loop):
assert mocked.mock_calls == [call(Path(str(plugin_file)))]

@pytest.mark.asyncio()
async def test_reload_no_path(self, mock_bot_factory, tmp_path, event_loop):
async def test_reload_no_path(self, mock_bot_factory, tmp_path):
plugin_dir = tmp_path / "plugins"
plugin_dir.mkdir()
plugin_file = plugin_dir / "plugin.py"
bot = mock_bot_factory(loop=event_loop)
bot = mock_bot_factory()
reloader = PluginReloader(bot)
with patch.object(
reloader, "_reload", new_callable=AsyncMock
Expand All @@ -78,12 +76,12 @@ async def test_reload_no_path(self, mock_bot_factory, tmp_path, event_loop):
assert mocked.mock_calls == []

@pytest.mark.asyncio()
async def test_unload(self, mock_bot_factory, tmp_path, event_loop):
async def test_unload(self, mock_bot_factory, tmp_path):
plugin_dir = tmp_path / "plugins"
plugin_dir.mkdir()
plugin_file = plugin_dir / "plugin.py"
plugin_file.touch()
bot = mock_bot_factory(loop=event_loop)
bot = mock_bot_factory()
reloader = PluginReloader(bot)
with patch.object(
reloader, "_unload", new_callable=AsyncMock
Expand Down
Loading