Skip to content

Commit

Permalink
Upgrade pytest-asyncio
Browse files Browse the repository at this point in the history
  • Loading branch information
puddly committed Oct 27, 2024
1 parent 18ea1ca commit 377e029
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 82 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ timeout = 20
log_format = "%(asctime)s.%(msecs)03d %(levelname)s %(message)s"
log_date_format = "%Y-%m-%d %H:%M:%S"
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"

[tool.flake8]
exclude = ".venv,.git,.tox,docs,venv,bin,lib,deps,build"
Expand Down
12 changes: 6 additions & 6 deletions tests/api/test_listeners.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
from zigpy_znp.api import OneShotResponseListener, CallbackResponseListener


async def test_resolve(event_loop, mocker):
async def test_resolve(mocker):
callback = mocker.Mock()
callback_listener = CallbackResponseListener(
[c.SYS.Ping.Rsp(partial=True)], callback
)

future = event_loop.create_future()
future = asyncio.get_running_loop().create_future()
one_shot_listener = OneShotResponseListener([c.SYS.Ping.Rsp(partial=True)], future)

match = c.SYS.Ping.Rsp(Capabilities=t.MTCapabilities.SYS)
Expand Down Expand Up @@ -42,9 +42,9 @@ async def test_resolve(event_loop, mocker):
assert one_shot_listener.cancel()


async def test_cancel(event_loop):
async def test_cancel():
# Cancelling a one-shot listener prevents it from being fired
future = event_loop.create_future()
future = asyncio.get_running_loop().create_future()
one_shot_listener = OneShotResponseListener([c.SYS.Ping.Rsp(partial=True)], future)
one_shot_listener.cancel()

Expand All @@ -55,13 +55,13 @@ async def test_cancel(event_loop):
await future


async def test_multi_cancel(event_loop, mocker):
async def test_multi_cancel(mocker):
callback = mocker.Mock()
callback_listener = CallbackResponseListener(
[c.SYS.Ping.Rsp(partial=True)], callback
)

future = event_loop.create_future()
future = asyncio.get_running_loop().create_future()
one_shot_listener = OneShotResponseListener([c.SYS.Ping.Rsp(partial=True)], future)

match = c.SYS.Ping.Rsp(Capabilities=t.MTCapabilities.SYS)
Expand Down
24 changes: 12 additions & 12 deletions tests/api/test_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from zigpy_znp.exceptions import CommandNotRecognized, InvalidCommandResponse


async def test_callback_rsp(connected_znp, event_loop):
async def test_callback_rsp(connected_znp):
znp, znp_server = connected_znp

def send_responses():
Expand All @@ -20,7 +20,7 @@ def send_responses():
c.AF.DataConfirm.Callback(Endpoint=56, TSN=1, Status=t.Status.SUCCESS)
)

event_loop.call_soon(send_responses)
asyncio.get_running_loop().call_soon(send_responses)

# The UART sometimes replies with a SRSP and an AREQ faster than
# we can register callbacks for both. This method is a workaround.
Expand Down Expand Up @@ -150,7 +150,7 @@ async def replier(req):
assert len(znp._unhandled_command.mock_calls) == 0


async def test_callback_rsp_cleanup_concurrent(connected_znp, event_loop, mocker):
async def test_callback_rsp_cleanup_concurrent(connected_znp, mocker):
znp, znp_server = connected_znp

mocker.spy(znp, "_unhandled_command")
Expand All @@ -163,7 +163,7 @@ def send_responses():
znp_server.send(c.SYS.OSALTimerExpired.Callback(Id=0xAB))
znp_server.send(c.SYS.OSALTimerExpired.Callback(Id=0xCD))

event_loop.call_soon(send_responses)
asyncio.get_running_loop().call_soon(send_responses)

callback_rsp = await znp.request_callback_rsp(
request=c.UTIL.TimeAlive.Req(),
Expand All @@ -183,7 +183,7 @@ def send_responses():
]


async def test_znp_request_kwargs(connected_znp, event_loop):
async def test_znp_request_kwargs(connected_znp):
znp, znp_server = connected_znp

# Invalid format
Expand All @@ -196,7 +196,7 @@ async def test_znp_request_kwargs(connected_znp, event_loop):

# Valid format, valid name
ping_rsp = c.SYS.Ping.Rsp(Capabilities=t.MTCapabilities.SYS)
event_loop.call_soon(znp_server.send, ping_rsp)
asyncio.get_running_loop().call_soon(znp_server.send, ping_rsp)
assert (
await znp.request(c.SYS.Ping.Req(), RspCapabilities=t.MTCapabilities.SYS)
) == ping_rsp
Expand Down Expand Up @@ -227,7 +227,7 @@ async def test_znp_request_kwargs(connected_znp, event_loop):
)


async def test_znp_request_not_recognized(connected_znp, event_loop):
async def test_znp_request_not_recognized(connected_znp):
znp, _ = connected_znp

# An error is raise when a bad request is sent
Expand All @@ -237,11 +237,11 @@ async def test_znp_request_not_recognized(connected_znp, event_loop):
)

with pytest.raises(CommandNotRecognized):
event_loop.call_soon(znp.frame_received, unknown_rsp.to_frame())
asyncio.get_running_loop().call_soon(znp.frame_received, unknown_rsp.to_frame())
await znp.request(request)


async def test_znp_request_wrong_params(connected_znp, event_loop):
async def test_znp_request_wrong_params(connected_znp):
znp, _ = connected_znp

# You cannot specify response kwargs for responses with no response
Expand All @@ -250,14 +250,14 @@ async def test_znp_request_wrong_params(connected_znp, event_loop):

# An error is raised when a response with bad params is received
with pytest.raises(InvalidCommandResponse):
event_loop.call_soon(
asyncio.get_running_loop().call_soon(
znp.frame_received,
c.SYS.Ping.Rsp(Capabilities=t.MTCapabilities.SYS).to_frame(),
)
await znp.request(c.SYS.Ping.Req(), RspCapabilities=t.MTCapabilities.APP)


async def test_znp_sreq_srsp(connected_znp, event_loop):
async def test_znp_sreq_srsp(connected_znp):
znp, _ = connected_znp

# Each SREQ must have a corresponding SRSP, so this will fail
Expand All @@ -267,7 +267,7 @@ async def test_znp_sreq_srsp(connected_znp, event_loop):

# This will work
ping_rsp = c.SYS.Ping.Rsp(Capabilities=t.MTCapabilities.SYS)
event_loop.call_soon(znp.frame_received, ping_rsp.to_frame())
asyncio.get_running_loop().call_soon(znp.frame_received, ping_rsp.to_frame())

await znp.request(c.SYS.Ping.Req())

Expand Down
6 changes: 3 additions & 3 deletions tests/api/test_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ async def test_wait_responses_empty(connected_znp):
await znp.wait_for_responses([])


async def test_response_callback_simple(connected_znp, event_loop, mocker):
async def test_response_callback_simple(connected_znp, mocker):
znp, _ = connected_znp

sync_callback = mocker.Mock()
Expand All @@ -207,7 +207,7 @@ async def test_response_callback_simple(connected_znp, event_loop, mocker):
sync_callback.assert_called_once_with(good_response)


async def test_response_callbacks(connected_znp, event_loop, mocker):
async def test_response_callbacks(connected_znp, mocker):
znp, _ = connected_znp

sync_callback = mocker.Mock()
Expand Down Expand Up @@ -270,7 +270,7 @@ async def async_callback(response):
assert len(async_callback_responses) == 3


async def test_wait_for_responses(connected_znp, event_loop):
async def test_wait_for_responses(connected_znp):
znp, _ = connected_znp

response1 = c.SYS.Ping.Rsp(Capabilities=t.MTCapabilities.SYS)
Expand Down
10 changes: 4 additions & 6 deletions tests/application/test_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ async def test_mrequest(device, make_application, mocker):


@pytest.mark.parametrize("device", [FormedLaunchpadCC26X2R1])
async def test_mrequest_doesnt_block(device, make_application, event_loop):
async def test_mrequest_doesnt_block(device, make_application):
app, znp_server = make_application(server_cls=device)

znp_server.reply_once_to(
Expand All @@ -226,7 +226,7 @@ async def test_mrequest_doesnt_block(device, make_application, event_loop):
Status=t.Status.SUCCESS, Endpoint=1, TSN=2
)

request_sent = event_loop.create_future()
request_sent = asyncio.get_running_loop().create_future()
request_sent.add_done_callback(lambda _: znp_server.send(data_confirm_rsp))

await app.startup(auto_form=False)
Expand Down Expand Up @@ -398,9 +398,7 @@ async def test_nonstandard_profile(device, make_application):


@pytest.mark.parametrize("device", FORMED_DEVICES)
async def test_request_cancellation_shielding(
device, make_application, mocker, event_loop
):
async def test_request_cancellation_shielding(device, make_application, mocker):
app, znp_server = make_application(server_cls=device)

await app.startup(auto_form=False)
Expand All @@ -412,7 +410,7 @@ async def test_request_cancellation_shielding(

device = app.add_initialized_device(ieee=t.EUI64(range(8)), nwk=0xABCD)

delayed_reply_sent = event_loop.create_future()
delayed_reply_sent = asyncio.get_running_loop().create_future()

def delayed_reply(req):
async def inner():
Expand Down
50 changes: 4 additions & 46 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import gc
import sys
import json
import typing
import asyncio
import inspect
import logging
Expand Down Expand Up @@ -46,46 +43,6 @@ def pytest_collection_modifyitems(session, config, items):
item.add_marker(pytest.mark.filterwarnings("error::RuntimeWarning"))


@pytest.hookimpl(trylast=True)
def pytest_fixture_post_finalizer(fixturedef, request) -> None:
"""Called after fixture teardown"""
if fixturedef.argname != "event_loop":
return

policy = asyncio.get_event_loop_policy()
try:
loop = policy.get_event_loop()
except RuntimeError:
loop = None
if loop is not None:
# Cleanup code based on the implementation of asyncio.run()
try:
if not loop.is_closed():
asyncio.runners._cancel_all_tasks(loop) # type: ignore[attr-defined]
loop.run_until_complete(loop.shutdown_asyncgens())
if sys.version_info >= (3, 9):
loop.run_until_complete(loop.shutdown_default_executor())
finally:
loop.close()
new_loop = policy.new_event_loop() # Replace existing event loop
# Ensure subsequent calls to get_event_loop() succeed
policy.set_event_loop(new_loop)


@pytest.fixture
def event_loop(
request: pytest.FixtureRequest,
) -> typing.Iterator[asyncio.AbstractEventLoop]:
"""Create an instance of the default event loop for each test case."""
yield asyncio.get_event_loop_policy().new_event_loop()
# Call the garbage collector to trigger ResourceWarning's as soon
# as possible (these are triggered in various __del__ methods).
# Without this, resources opened in one test can fail other tests
# when the warning is generated.
gc.collect()
# Event loop cleanup handled by pytest_fixture_post_finalizer


class ForwardingSerialTransport:
"""
Serial transport that hooks directly into a protocol
Expand Down Expand Up @@ -237,10 +194,11 @@ async def inner(server_cls):


@pytest.fixture
def connected_znp(event_loop, make_connected_znp):
znp, znp_server = event_loop.run_until_complete(make_connected_znp(BaseServerZNP))
async def connected_znp(make_connected_znp):
znp, znp_server = await make_connected_znp(BaseServerZNP)
yield znp, znp_server
znp.close()
await znp.disconnect()
await znp_server.disconnect()


def simple_deepcopy(d):
Expand Down
20 changes: 11 additions & 9 deletions tests/test_uart.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import asyncio

import pytest
from serial_asyncio import SerialTransport

Expand All @@ -19,25 +21,25 @@ def connected_uart(mocker):


@pytest.fixture
def dummy_serial_conn(event_loop, mocker):
async def dummy_serial_conn(mocker):
device = "/dev/ttyACM0"

serial_interface = mocker.Mock()
serial_interface.name = device

def create_serial_conn(loop, protocol_factory, url, *args, **kwargs):
fut = event_loop.create_future()
fut = loop.create_future()
assert url == device

protocol = protocol_factory()

# Our event loop doesn't really do anything
event_loop.add_writer = lambda *args, **kwargs: None
event_loop.add_reader = lambda *args, **kwargs: None
event_loop.remove_writer = lambda *args, **kwargs: None
event_loop.remove_reader = lambda *args, **kwargs: None
loop.add_writer = lambda *args, **kwargs: None
loop.add_reader = lambda *args, **kwargs: None
loop.remove_writer = lambda *args, **kwargs: None
loop.remove_reader = lambda *args, **kwargs: None

transport = SerialTransport(event_loop, protocol, serial_interface)
transport = SerialTransport(loop, protocol, serial_interface)

protocol.connection_made(transport)

Expand Down Expand Up @@ -221,11 +223,11 @@ def test_uart_frame_received_error(connected_uart, mocker):
assert znp.frame_received.call_count == 3


async def test_connection_lost(dummy_serial_conn, mocker, event_loop):
async def test_connection_lost(dummy_serial_conn, mocker):
device, _ = dummy_serial_conn

znp = mocker.Mock()
conn_lost_fut = event_loop.create_future()
conn_lost_fut = asyncio.get_running_loop().create_future()
znp.connection_lost = conn_lost_fut.set_result

protocol = await znp_uart.connect(
Expand Down

0 comments on commit 377e029

Please sign in to comment.