Skip to content

Commit

Permalink
Merge pull request #172 from mdeweerd/dev
Browse files Browse the repository at this point in the history
Update for zigpy >= 0.56.0, HA 2023.7.0 - integrate retryable
  • Loading branch information
mdeweerd committed Jul 6, 2023
2 parents 6499f64 + 3e2094b commit 11443fa
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 23 deletions.
16 changes: 1 addition & 15 deletions custom_components/zha_toolkit/neighbours.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,11 @@

import zigpy.zdo.types as zdo_t
from homeassistant.util.json import save_json
from zigpy.exceptions import ControllerException, DeliveryError
from zigpy.util import retryable
from zigpy.exceptions import DeliveryError

LOGGER = logging.getLogger(__name__)


@retryable(
(
DeliveryError,
ControllerException,
asyncio.CancelledError,
asyncio.TimeoutError,
),
tries=5,
)
def wrapper(cmd, *args, **kwargs):
return cmd(*args, **kwargs)


async def routes_and_neighbours(
app, listener, ieee, cmd, data, service, params, event_data
):
Expand Down
8 changes: 4 additions & 4 deletions custom_components/zha_toolkit/ota.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from pkg_resources import parse_version
from zigpy import __version__ as zigpy_version
from zigpy.exceptions import ControllerException, DeliveryError
from zigpy.util import retryable

from . import DEFAULT_OTAU
from . import utils as u
from .params import INTERNAL_PARAMS as p

LOGGER = logging.getLogger(__name__)
Expand All @@ -21,7 +21,7 @@
SONOFF_LIST_URL = "https://zigbee-ota.sonoff.tech/releases/upgrade.json"


@retryable(
@u.retryable(
(
DeliveryError,
ControllerException,
Expand All @@ -30,7 +30,7 @@
),
tries=3,
)
async def wrapper(cmd, *args, **kwargs):
async def retry_wrapper(cmd, *args, **kwargs):
return await cmd(*args, **kwargs)


Expand Down Expand Up @@ -232,7 +232,7 @@ async def ota_notify(
ret = await cluster.image_notify(0, 100)
else:
cmd_args = [0, 100]
ret = await wrapper(
ret = await retry_wrapper(
cluster.client_command,
0, # cmd_id
*cmd_args,
Expand Down
5 changes: 2 additions & 3 deletions custom_components/zha_toolkit/scan_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

from zigpy import types as t
from zigpy.exceptions import ControllerException, DeliveryError
from zigpy.util import retryable
from zigpy.zcl import foundation

from . import utils as u
Expand All @@ -15,7 +14,7 @@
LOGGER = logging.getLogger(__name__)


@retryable(
@u.retryable(
(
DeliveryError,
ControllerException,
Expand All @@ -30,7 +29,7 @@ async def read_attr(cluster, attrs, manufacturer=None):
)


@retryable(
@u.retryable(
(DeliveryError, asyncio.CancelledError, asyncio.TimeoutError), tries=3
)
async def wrapper(cmd, *args, **kwargs):
Expand Down
59 changes: 58 additions & 1 deletion custom_components/zha_toolkit/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from __future__ import annotations

import asyncio
import functools
import json
import logging
import os
import re
import typing
from enum import Enum
from typing import Any

import packaging
import packaging.version
Expand All @@ -15,7 +17,6 @@
from zigpy import __version__ as zigpy_version
from zigpy import types as t
from zigpy.exceptions import ControllerException, DeliveryError
from zigpy.util import retryable
from zigpy.zcl import foundation as f

from .params import INTERNAL_PARAMS as p
Expand Down Expand Up @@ -834,6 +835,62 @@ def extractParams( # noqa: C901
return params


#
# Copied retry and retryable from zigpy < 0.56.0
# where "tries" and "delay" were removed
# from the wrapper function and hence propagated to the decorated function.
#
async def retry(
func: typing.Callable[[], typing.Awaitable[typing.Any]],
retry_exceptions: typing.Iterable[Any], # typing.Iterable[BaseException],
tries: int = 3,
delay: int | float = 0.1,
) -> typing.Any:
"""Retry a function in case of exception
Only exceptions in `retry_exceptions` will be retried.
"""
while True:
LOGGER.debug("Tries remaining: %s", tries)
try:
return await func()
except retry_exceptions: # type:ignore[misc]
if tries <= 1:
raise
tries -= 1
await asyncio.sleep(delay)


def retryable(
retry_exceptions: typing.Iterable[Any], # typing.Iterable[BaseException]
tries: int = 1,
delay: float = 0.1,
) -> typing.Callable:
"""Return a decorator which makes a function able to be retried
This adds "tries" and "delay" keyword arguments to the function. Only
exceptions in `retry_exceptions` will be retried.
"""

def decorator(func: typing.Callable) -> typing.Callable:
nonlocal tries, delay

@functools.wraps(func)
def wrapper(*args, tries=tries, delay=delay, **kwargs):
if tries <= 1:
return func(*args, **kwargs)
return retry(
functools.partial(func, *args, **kwargs),
retry_exceptions,
tries=tries,
delay=delay,
)

return wrapper

return decorator


# zigpy wrappers

# The zigpy library does not offer retryable on read_attributes.
Expand Down

0 comments on commit 11443fa

Please sign in to comment.