Skip to content
Draft
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
30 changes: 0 additions & 30 deletions .github/workflows/matchers/flake8.json

This file was deleted.

54 changes: 7 additions & 47 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,46 +1,13 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.16.9
hooks:
- id: pyupgrade
args: [--py311-plus]

- repo: https://github.com/PyCQA/autoflake
rev: v2.2.1
hooks:
- id: autoflake

- repo: https://github.com/psf/black
rev: 23.9.1
hooks:
- id: black
args:
- --quiet
- --safe

- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
additional_dependencies:
- flake8-docstrings==1.7.0
- pydocstyle==6.3.0
- Flake8-pyproject==1.2.3
- flake8-bugbear==23.9.16
- flake8-comprehensions==3.14.0
- flake8_2020==1.8.1
- mccabe==0.7.0
- pycodestyle==2.11.0
- pyflakes==3.1.0
- flake8-async==22.11.14

- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort
- id: ruff-check
args: ["--fix", "--exit-non-zero-on-fix"]
- id: ruff-format

- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
rev: v2.4.3
hooks:
- id: codespell
args:
Expand All @@ -49,15 +16,8 @@ repos:
- --quiet-level=2

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.6.0
rev: v2.3.1
hooks:
- id: mypy
additional_dependencies:
- zigpy

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.291
hooks:
- id: ruff
args:
- --fix
49 changes: 33 additions & 16 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,43 @@ testing = [
[tool.setuptools-git-versioning]
enabled = true

[tool.isort]
profile = "black"
# will group `import x` and `from x import` of the same module.
force_sort_within_sections = true
known_first_party = ["zigpy_xbee", "tests"]
forced_separate = "tests"
combine_as_imports = true
[tool.ruff]
target-version = "py311"
line-length = 88

[tool.ruff.lint]
select = [
"ASYNC", # flake8-async
"B", # flake8-bugbear
"C", # complexity
"D", # pydocstyle
"E", # pycodestyle
"F", # pyflakes/autoflake
"I", # isort
"SIM", # flake8-simplify
"UP", # pyupgrade
"W", # pycodestyle
"YTT", # flake8-2020
]
ignore = [
"D202", # No blank lines allowed after function docstring
]

[tool.ruff.lint.mccabe]
max-complexity = 25

[tool.ruff.lint.pydocstyle]
convention = "pep257"

[tool.ruff.lint.isort]
force-sort-within-sections = true
known-first-party = ["zigpy_xbee", "tests"]
forced-separate = ["tests"]
combine-as-imports = true

[tool.mypy]
ignore_errors = true

[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"

[tool.flake8]
exclude = [".venv", ".git", ".tox", "docs", "venv", "bin", "lib", "deps", "build"]
# To work with Black
max-line-length = 88
# W503: Line break occurred before a binary operator
# E203: Whitespace before ':'
# D202 No blank lines allowed after function docstring
ignore = ["W503", "E203", "D202"]
6 changes: 1 addition & 5 deletions requirements_test.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Test dependencies.

isort
black
flake8
codecov
colorlog
codespell
Expand All @@ -15,5 +12,4 @@ pytest-timeout
pytest-asyncio>=0.17
pytest>=7.1.3
zigpy>=2.0.0
ruff>=0.0.291
Flake8-pyproject
ruff==0.16.9
16 changes: 7 additions & 9 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ async def test_connect_initial_timeout_failure():
api._at_command = mock.AsyncMock(side_effect=asyncio.TimeoutError)
api.init_api_mode = mock.AsyncMock(return_value=False)

with mock.patch("zigpy_xbee.uart.connect") as mock_connect:
with pytest.raises(zigpy.exceptions.APIException):
await api.connect()
with (
mock.patch("zigpy_xbee.uart.connect") as mock_connect,
pytest.raises(zigpy.exceptions.APIException),
):
await api.connect()

assert mock_connect.return_value.disconnect.mock_calls == [mock.call()]

Expand Down Expand Up @@ -565,9 +567,7 @@ async def test_api_mode_at_commands(api):
assert res is True

async def mock_at_cmd(cmd):
if cmd == "ATWR\r":
return False
return True
return cmd != "ATWR\r"

api.command_mode_at_cmd = mock_at_cmd
res = await api.api_mode_at_commands(57600)
Expand All @@ -590,9 +590,7 @@ async def test_init_api_mode(api, monkeypatch):
assert api.enter_at_command_mode.call_count == 10

async def enter_at_mode():
if api._uart.baudrate == 9600:
return True
return False
return api._uart.baudrate == 9600

api._uart.baudrate = 57600
api.enter_at_command_mode = mock.MagicMock(side_effect=enter_at_mode)
Expand Down
10 changes: 5 additions & 5 deletions tests/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def _at_command_mock(cmd, *args):
"SL": 0x04030201,
"ZS": zs,
"VR": 0x1234,
}.get(cmd, None)
}.get(cmd)

def init_api_mode_mock():
nonlocal api_mode
Expand Down Expand Up @@ -492,7 +492,7 @@ async def test_permit_with_link_key(app):
app._api._command = mock.AsyncMock(return_value=xbee_t.TXStatus.SUCCESS)
app._api._at_command = mock.AsyncMock(return_value="OK")
node = t.EUI64(b"\x01\x02\x03\x04\x05\x06\x07\x08")
link_key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
link_key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
time_s = 500
await app.permit_with_link_key(node=node, link_key=link_key, time_s=time_s)
app._api._at_command.assert_called_once_with("KT", time_s)
Expand Down Expand Up @@ -735,7 +735,7 @@ async def test_move_network_to_channel(app):

async def test_energy_scan(app):
"""Test channel energy scan."""
rssi = b"\x0A\x0F\x14\x19\x1E\x23\x28\x2D\x32\x37\x3C\x41\x46\x4B\x50\x55"
rssi = b"\x0a\x0f\x14\x19\x1e\x23\x28\x2d\x32\x37\x3c\x41\x46\x4b\x50\x55"
app._api._at_command = mock.AsyncMock(spec=XBee._at_command, return_value=rssi)
time_s = 3
count = 3
Expand Down Expand Up @@ -774,7 +774,7 @@ async def test_energy_scan_legacy_module(app):
channels=list(range(11, 27)), duration_exp=time_s, count=count
)
app._api._at_command.assert_called_once_with("ED", bytes([time_s]))
assert energy == {c: 0 for c in range(11, 27)}
assert energy == dict.fromkeys(range(11, 27), 0)


def test_neighbors_updated(app, device):
Expand Down Expand Up @@ -819,7 +819,7 @@ def test_neighbors_updated(app, device):
# Let's also include an unknown device
zdo_t.Neighbor(
extended_pan_id=pan_id,
ieee=t.EUI64(b"\x00\x0F\x0E\x0D\x0C\x0B\x0A\x09"),
ieee=t.EUI64(b"\x00\x0f\x0e\x0d\x0c\x0b\x0a\x09"),
nwk=t.NWK(0x9999),
device_type=0x2,
rx_on_when_idle=0x0,
Expand Down
4 changes: 2 additions & 2 deletions tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_bytes_serialize():
def test_bytes_deserialize():
"""Test Bytes.deserialize()."""
data, rest = xbee_t.Bytes.deserialize(0x89AB.to_bytes(3, "big"))
assert data == b"\x00\x89\xAB"
assert data == b"\x00\x89\xab"
assert rest == b""


Expand Down Expand Up @@ -76,7 +76,7 @@ def test_nwk():

def test_eui64():
"""Test EUI64 class."""
extra = b"\xBE\xEF"
extra = b"\xbe\xef"
data = b"01234567"

result, rest = xbee_t.EUI64.deserialize(data + extra)
Expand Down
25 changes: 13 additions & 12 deletions tests/test_uart.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def gw():

def test_baudrate(gw):
"""Test setting baudrate."""
gw.baudrate
gw._transport.serial.baudrate = 57600
assert gw.baudrate == 57600
gw.baudrate = 19200
assert gw._transport.serial.baudrate == 19200

Expand Down Expand Up @@ -62,7 +63,7 @@ def test_command_mode_rsp(gw):

def test_command_mode_send(gw):
"""Test command mode request."""
data = b"ATAP2\x0D"
data = b"ATAP2\x0d"
gw.command_mode_send(data)
gw._transport.write.assert_called_once_with(data)

Expand Down Expand Up @@ -105,7 +106,7 @@ def test_data_received_incomplete_frame(gw):

def test_data_received_at_response_non_cmd_mode(gw):
"""Test command mode response while not in command mode."""
data = b"OK\x0D"
data = b"OK\x0d"
gw.frame_received = mock.MagicMock()
gw.command_mode_rsp = mock.MagicMock()

Expand All @@ -115,7 +116,7 @@ def test_data_received_at_response_non_cmd_mode(gw):

def test_data_received_at_response_in_cmd_mode(gw):
"""Test command mode response in command mode."""
data = b"OK\x0D"
data = b"OK\x0d"
gw.frame_received = mock.MagicMock()
gw.command_mode_rsp = mock.MagicMock()

Expand All @@ -131,23 +132,23 @@ def test_data_received_at_response_in_cmd_mode(gw):

def test_extract(gw):
"""Test handling extra chaining data."""
gw._buffer = b"\x7E\x00\x02\x23\x7D\x31\xCBextra"
gw._buffer = b"\x7e\x00\x02\x23\x7d\x31\xcbextra"
frame = gw._extract_frame()
assert frame == b"\x23\x11"
assert gw._buffer == b"extra"


def test_extract_wrong_checksum(gw):
"""Test API frame with wrong checksum and extra data."""
gw._buffer = b"\x7E\x00\x02\x23\x7D\x31\xCEextra"
gw._buffer = b"\x7e\x00\x02\x23\x7d\x31\xceextra"
frame = gw._extract_frame()
assert frame is None
assert gw._buffer == b"extra"


def test_extract_checksum_none(gw):
"""Test API frame with no checksum."""
data = b"\x7E\x00\x02\x23\x7D\x31"
data = b"\x7e\x00\x02\x23\x7d\x31"
gw._buffer = data
gw._checksum = lambda x: None
frame = gw._extract_frame()
Expand All @@ -157,7 +158,7 @@ def test_extract_checksum_none(gw):

def test_extract_frame_len_none(gw):
"""Test API frame with no length."""
data = b"\x7E"
data = b"\x7e"
gw._buffer = data
frame = gw._extract_frame()
assert frame is None
Expand All @@ -166,7 +167,7 @@ def test_extract_frame_len_none(gw):

def test_extract_frame_no_start(gw):
"""Test API frame without frame ID."""
data = b"\x00\x02\x23\x7D\x31"
data = b"\x00\x02\x23\x7d\x31"
gw._buffer = data
frame = gw._extract_frame()
assert frame is None
Expand All @@ -184,7 +185,7 @@ def test_frame_received(gw):
def test_send(gw):
"""Test data send."""
gw.send(b"\x23\x11")
data = b"\x7E\x00\x02\x23\x7D\x31\xCB"
data = b"\x7e\x00\x02\x23\x7d\x31\xcb"
gw._transport.write.assert_called_once_with(data)


Expand All @@ -193,7 +194,7 @@ def test_escape(gw):
data = b"".join(
[
a.to_bytes(1, "big") + b.to_bytes(1, "big")
for a, b in zip(gw.RESERVED, b"\x22\x33\x44\x55")
for a, b in zip(gw.RESERVED, b"\x22\x33\x44\x55", strict=True)
]
)
escaped = gw._escape(data)
Expand All @@ -210,7 +211,7 @@ def test_unescape(gw):
chk = b"".join(
[
a.to_bytes(1, "big") + b.to_bytes(1, "big")
for a, b in zip(gw.RESERVED, b"\x22\x33\x44\x55")
for a, b in zip(gw.RESERVED, b"\x22\x33\x44\x55", strict=True)
]
)
unescaped, rest = gw._get_unescaped(escaped + extra, 8)
Expand Down
4 changes: 3 additions & 1 deletion zigpy_xbee/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,9 @@
await self._at_command("AP", 2)
except TimeoutError:
if not await self.init_api_mode():
raise APIException("Failed to configure XBee for API mode")
raise APIException(
"Failed to configure XBee for API mode"
) from None
except Exception:
await self.disconnect()
raise
Expand All @@ -320,7 +322,7 @@
def connection_lost(self, exc: Exception) -> None:
"""Lost serial connection."""
if self._app is not None:
self._app.connection_lost(exc)

Check warning on line 325 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 325 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 325 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 325 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 325 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 325 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 325 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 325 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

async def disconnect(self):
"""Close the connection."""
Expand Down Expand Up @@ -507,7 +509,7 @@
async def command_mode_at_cmd(self, command):
"""Send AT command in command mode."""
self._cmd_mode_future = asyncio.Future()
self._uart.command_mode_send(command.encode("ascii"))

Check warning on line 512 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 512 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 512 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 512 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 512 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 512 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 512 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 512 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

try:
res = await asyncio.wait_for(self._cmd_mode_future, timeout=2)
Expand All @@ -534,7 +536,7 @@
LOGGER.debug("No response to %s cmd", cmd)
return None
LOGGER.debug("Successfully sent %s cmd", cmd)
self._uart.reset_command_mode()

Check warning on line 539 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 539 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 539 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 539 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 539 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 539 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 539 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 539 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited
return True

async def init_api_mode(self):
Expand Down
Loading
Loading