Skip to content

Commit 81cff21

Browse files
authored
Merge pull request #124 from puddly/puddly/rc
0.15.0 Release
2 parents 1a5a0af + 654e5ff commit 81cff21

12 files changed

+245
-241
lines changed

.pre-commit-config.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
repos:
22
- repo: https://github.com/psf/black
3-
rev: 19.10b0
3+
rev: 22.3.0
44
hooks:
55
- id: black
66
args:
77
- --safe
88
- --quiet
99
- repo: https://gitlab.com/pycqa/flake8
10-
rev: 3.7.9
10+
rev: 4.0.1
1111
hooks:
1212
- id: flake8
13-
- repo: https://github.com/pre-commit/mirrors-isort
14-
rev: v4.3.21
13+
- repo: https://github.com/PyCQA/isort
14+
rev: 5.10.1
1515
hooks:
1616
- id: isort
1717
- repo: https://github.com/pre-commit/pre-commit-hooks
18-
rev: v2.4.0
18+
rev: v4.1.0
1919
hooks:
2020
- id: no-commit-to-branch
2121
args:

setup.cfg

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ force_grid_wrap=0
2020
use_parentheses=True
2121
line_length=88
2222
indent = " "
23-
# by default isort don't check module indexes
24-
not_skip = __init__.py
2523
# will group `import x` and `from x import` of the same module.
2624
force_sort_within_sections = true
27-
sections = FUTURE,STDLIB,INBETWEENS,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
25+
sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
2826
default_section = THIRDPARTY
2927
known_first_party = zigpy_xbee,tests
3028
forced_separate = tests
3129
combine_as_imports = true
30+
31+
[tool:pytest]
32+
asyncio_mode = auto

setup.py

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
11
"""Setup module for zigpy-xbee"""
22

3-
import os
3+
import pathlib
44

55
from setuptools import find_packages, setup
66

77
import zigpy_xbee
88

9-
this_directory = os.path.join(os.path.abspath(os.path.dirname(__file__)))
10-
with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f:
11-
long_description = f.read()
12-
139
setup(
1410
name="zigpy-xbee",
1511
version=zigpy_xbee.__version__,
1612
description="A library which communicates with XBee radios for zigpy",
17-
long_description=long_description,
13+
long_description=(pathlib.Path(__file__).parent / "README.md").read_text(),
1814
long_description_content_type="text/markdown",
1915
url="http://github.com/zigpy/zigpy-xbee",
2016
author="Russell Cloran",
2117
author_email="[email protected]",
2218
license="GPL-3.0",
2319
packages=find_packages(exclude=["*.tests"]),
24-
install_requires=["pyserial-asyncio", "zigpy>= 0.23.0"],
25-
tests_require=["pytest"],
20+
install_requires=["pyserial-asyncio", "zigpy>=0.47.0"],
21+
tests_require=["pytest", "asynctest", "pytest-asyncio"],
2622
)

tests/__init__.py

Whitespace-only changes.

tests/async_mock.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Mock utilities that are async aware."""
2+
import sys
3+
4+
if sys.version_info[:2] < (3, 8):
5+
from asynctest.mock import * # noqa
6+
7+
AsyncMock = CoroutineMock # noqa: F405
8+
else:
9+
from unittest.mock import * # noqa

tests/test_api.py

+17-50
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import asyncio
22
import logging
33

4-
from asynctest import CoroutineMock, mock
54
import pytest
65
import serial
76
import zigpy.exceptions
@@ -10,6 +9,8 @@
109
import zigpy_xbee.config
1110
from zigpy_xbee.zigbee.application import ControllerApplication
1211

12+
import tests.async_mock as mock
13+
1314
DEVICE_CONFIG = zigpy_xbee.config.SCHEMA_DEVICE(
1415
{zigpy_xbee.config.CONF_DEVICE_PATH: "/dev/null"}
1516
)
@@ -22,10 +23,9 @@ def api():
2223
return api
2324

2425

25-
@pytest.mark.asyncio
2626
async def test_connect(monkeypatch):
2727
api = xbee_api.XBee(DEVICE_CONFIG)
28-
monkeypatch.setattr(uart, "connect", CoroutineMock())
28+
monkeypatch.setattr(uart, "connect", mock.AsyncMock())
2929
await api.connect()
3030

3131

@@ -52,7 +52,6 @@ def test_commands():
5252
assert reply is None or isinstance(reply, int)
5353

5454

55-
@pytest.mark.asyncio
5655
async def test_command(api):
5756
def mock_api_frame(name, *args):
5857
c = xbee_api.COMMAND_REQUESTS[name]
@@ -90,7 +89,6 @@ def mock_api_frame(name, *args):
9089
api._uart.send.reset_mock()
9190

9291

93-
@pytest.mark.asyncio
9492
async def test_command_not_connected(api):
9593
api._uart = None
9694

@@ -135,20 +133,17 @@ def mock_command(name, *args):
135133
api._command.reset_mock()
136134

137135

138-
@pytest.mark.asyncio
139136
async def test_at_command(api, monkeypatch):
140137
await _test_at_or_queued_at_command(api, api._at_command, monkeypatch)
141138

142139

143-
@pytest.mark.asyncio
144140
async def test_at_command_no_response(api, monkeypatch):
145141
with pytest.raises(asyncio.TimeoutError):
146142
await _test_at_or_queued_at_command(
147143
api, api._at_command, monkeypatch, do_reply=False
148144
)
149145

150146

151-
@pytest.mark.asyncio
152147
async def test_queued_at_command(api, monkeypatch):
153148
await _test_at_or_queued_at_command(api, api._queued_at, monkeypatch)
154149

@@ -191,12 +186,10 @@ def mock_command(name, *args):
191186
api._command.reset_mock()
192187

193188

194-
@pytest.mark.asyncio
195189
async def test_remote_at_cmd(api, monkeypatch):
196190
await _test_remote_at_command(api, monkeypatch)
197191

198192

199-
@pytest.mark.asyncio
200193
async def test_remote_at_cmd_no_rsp(api, monkeypatch):
201194
monkeypatch.setattr(xbee_api, "REMOTE_AT_COMMAND_TIMEOUT", 0.1)
202195
with pytest.raises(asyncio.TimeoutError):
@@ -417,7 +410,6 @@ def test_handle_tx_status_duplicate(api):
417410
assert send_fut.set_exception.call_count == 0
418411

419412

420-
@pytest.mark.asyncio
421413
async def test_command_mode_at_cmd(api):
422414
command = "+++"
423415

@@ -430,7 +422,6 @@ def cmd_mode_send(cmd):
430422
assert result
431423

432424

433-
@pytest.mark.asyncio
434425
async def test_command_mode_at_cmd_timeout(api):
435426
command = "+++"
436427

@@ -462,21 +453,15 @@ def test_handle_command_mode_rsp(api):
462453
assert api._cmd_mode_future.result() == data
463454

464455

465-
@pytest.mark.asyncio
466456
async def test_enter_at_command_mode(api):
467-
api.command_mode_at_cmd = mock.MagicMock(
468-
side_effect=asyncio.coroutine(lambda x: mock.sentinel.at_response)
469-
)
457+
api.command_mode_at_cmd = mock.AsyncMock(return_value=mock.sentinel.at_response)
470458

471459
res = await api.enter_at_command_mode()
472460
assert res == mock.sentinel.at_response
473461

474462

475-
@pytest.mark.asyncio
476463
async def test_api_mode_at_commands(api):
477-
api.command_mode_at_cmd = mock.MagicMock(
478-
side_effect=asyncio.coroutine(lambda x: mock.sentinel.api_mode)
479-
)
464+
api.command_mode_at_cmd = mock.AsyncMock(return_value=mock.sentinel.api_mode)
480465

481466
res = await api.api_mode_at_commands(57600)
482467
assert res is True
@@ -491,20 +476,15 @@ async def mock_at_cmd(cmd):
491476
assert res is None
492477

493478

494-
@pytest.mark.asyncio
495479
async def test_init_api_mode(api, monkeypatch):
496480
monkeypatch.setattr(api._uart, "baudrate", 57600)
497-
api.enter_at_command_mode = mock.MagicMock(
498-
side_effect=asyncio.coroutine(mock.MagicMock(return_value=True))
499-
)
481+
api.enter_at_command_mode = mock.AsyncMock(return_value=True)
500482

501483
res = await api.init_api_mode()
502484
assert res is None
503485
assert api.enter_at_command_mode.call_count == 1
504486

505-
api.enter_at_command_mode = mock.MagicMock(
506-
side_effect=asyncio.coroutine(mock.MagicMock(return_value=False))
507-
)
487+
api.enter_at_command_mode = mock.AsyncMock(return_value=False)
508488

509489
res = await api.init_api_mode()
510490
assert res is False
@@ -517,9 +497,7 @@ async def enter_at_mode():
517497

518498
api._uart.baudrate = 57600
519499
api.enter_at_command_mode = mock.MagicMock(side_effect=enter_at_mode)
520-
api.api_mode_at_commands = mock.MagicMock(
521-
side_effect=asyncio.coroutine(mock.MagicMock(return_value=True))
522-
)
500+
api.api_mode_at_commands = mock.AsyncMock(return_value=True)
523501

524502
res = await api.init_api_mode()
525503
assert res is True
@@ -542,21 +520,16 @@ def test_handle_many_to_one_rri(api):
542520
api._handle_many_to_one_rri(ieee, nwk, 0)
543521

544522

545-
@pytest.mark.asyncio
546523
async def test_reconnect_multiple_disconnects(monkeypatch, caplog):
547524
api = xbee_api.XBee(DEVICE_CONFIG)
548-
connect_mock = CoroutineMock()
549-
connect_mock.return_value = asyncio.Future()
550-
connect_mock.return_value.set_result(True)
525+
connect_mock = mock.AsyncMock(return_value=True)
551526
monkeypatch.setattr(uart, "connect", connect_mock)
552527

553528
await api.connect()
554529

555530
caplog.set_level(logging.DEBUG)
556-
connected = asyncio.Future()
557-
connected.set_result(mock.sentinel.uart_reconnect)
558531
connect_mock.reset_mock()
559-
connect_mock.side_effect = [asyncio.Future(), connected]
532+
connect_mock.side_effect = [OSError, mock.sentinel.uart_reconnect]
560533
api.connection_lost("connection lost")
561534
await asyncio.sleep(0.3)
562535
api.connection_lost("connection lost 2")
@@ -567,21 +540,20 @@ async def test_reconnect_multiple_disconnects(monkeypatch, caplog):
567540
assert connect_mock.call_count == 2
568541

569542

570-
@pytest.mark.asyncio
571543
async def test_reconnect_multiple_attempts(monkeypatch, caplog):
572544
api = xbee_api.XBee(DEVICE_CONFIG)
573-
connect_mock = CoroutineMock()
574-
connect_mock.return_value = asyncio.Future()
575-
connect_mock.return_value.set_result(True)
545+
connect_mock = mock.AsyncMock(return_value=True)
576546
monkeypatch.setattr(uart, "connect", connect_mock)
577547

578548
await api.connect()
579549

580550
caplog.set_level(logging.DEBUG)
581-
connected = asyncio.Future()
582-
connected.set_result(mock.sentinel.uart_reconnect)
583551
connect_mock.reset_mock()
584-
connect_mock.side_effect = [asyncio.TimeoutError, OSError, connected]
552+
connect_mock.side_effect = [
553+
asyncio.TimeoutError,
554+
OSError,
555+
mock.sentinel.uart_reconnect,
556+
]
585557

586558
with mock.patch("asyncio.sleep"):
587559
api.connection_lost("connection lost")
@@ -591,8 +563,7 @@ async def test_reconnect_multiple_attempts(monkeypatch, caplog):
591563
assert connect_mock.call_count == 3
592564

593565

594-
@pytest.mark.asyncio
595-
@mock.patch.object(xbee_api.XBee, "_at_command", new_callable=CoroutineMock)
566+
@mock.patch.object(xbee_api.XBee, "_at_command", new_callable=mock.AsyncMock)
596567
@mock.patch.object(uart, "connect")
597568
async def test_probe_success(mock_connect, mock_at_cmd):
598569
"""Test device probing."""
@@ -606,7 +577,6 @@ async def test_probe_success(mock_connect, mock_at_cmd):
606577
assert mock_connect.return_value.close.call_count == 1
607578

608579

609-
@pytest.mark.asyncio
610580
@mock.patch.object(xbee_api.XBee, "init_api_mode", return_value=True)
611581
@mock.patch.object(xbee_api.XBee, "_at_command", side_effect=asyncio.TimeoutError)
612582
@mock.patch.object(uart, "connect")
@@ -623,7 +593,6 @@ async def test_probe_success_api_mode(mock_connect, mock_at_cmd, mock_api_mode):
623593
assert mock_connect.return_value.close.call_count == 1
624594

625595

626-
@pytest.mark.asyncio
627596
@mock.patch.object(xbee_api.XBee, "init_api_mode")
628597
@mock.patch.object(xbee_api.XBee, "_at_command", side_effect=asyncio.TimeoutError)
629598
@mock.patch.object(uart, "connect")
@@ -648,7 +617,6 @@ async def test_probe_fail(mock_connect, mock_at_cmd, mock_api_mode, exception):
648617
assert mock_connect.return_value.close.call_count == 1
649618

650619

651-
@pytest.mark.asyncio
652620
@mock.patch.object(xbee_api.XBee, "init_api_mode", return_value=False)
653621
@mock.patch.object(xbee_api.XBee, "_at_command", side_effect=asyncio.TimeoutError)
654622
@mock.patch.object(uart, "connect")
@@ -668,7 +636,6 @@ async def test_probe_fail_api_mode(mock_connect, mock_at_cmd, mock_api_mode):
668636
assert mock_connect.return_value.close.call_count == 1
669637

670638

671-
@pytest.mark.asyncio
672639
@mock.patch.object(xbee_api.XBee, "connect")
673640
async def test_xbee_new(conn_mck):
674641
"""Test new class method."""

0 commit comments

Comments
 (0)