Skip to content

Commit

Permalink
Add custom filter.
Browse files Browse the repository at this point in the history
This filter allows to specify lambda to filter callback calls.
  • Loading branch information
denpamusic committed Oct 15, 2023
1 parent 3295ab6 commit 9405059
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
17 changes: 17 additions & 0 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,23 @@ It can be used with numeric values, dictionaries, tuples or lists.
# and last await.
ecomax.subscribe("outside_temp", delta(my_callback))
Custom
^^^^^^

.. autofunction:: pyplumio.filters.custom

This filter allows to specify filter function that will be called
every time the value is received from the controller.

A callback is awaited once this filter function returns true.

.. code-block:: python
from pyplumio.filter import delta
# Await the callback when temperature is higher that 10 degrees
# Celsius.
ecomax.subscribe("outside_temp", custom(my_callback, lambda x: x > 10))
Regulator Data
--------------
Expand Down
31 changes: 30 additions & 1 deletion pyplumio/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from abc import ABC, abstractmethod
import math
import time
from typing import Any, Final, SupportsFloat, overload
from typing import Any, Callable, Final, SupportsFloat, overload

from pyplumio.const import UNDEFINED
from pyplumio.helpers.parameter import Parameter
Expand Down Expand Up @@ -254,3 +254,32 @@ def aggregate(callback: EventCallbackType, seconds: float) -> _Aggregate:
over a specified time period.
"""
return _Aggregate(callback, seconds)


class _Custom(Filter):
"""Represents a custom filter.
Calls a callback with value, if user-defined filter function
that's called by this class with the value as an argument
returns true.
"""

def __init__(self, callback: EventCallbackType, filter_fn: Callable[[Any], bool]):
"""Initialize a new custom filter."""
super().__init__(callback)
self._filter_fn = filter_fn

async def __call__(self, new_value):
"""Set a new value for the callback."""
if self._filter_fn(new_value):
await self._callback(new_value)


def custom(callback: EventCallbackType, filter_fn: Callable[[Any], bool]) -> _Custom:
"""A custom filter.
A callback function will be called when user-defined filter
function, that's being called with the value as an argument,
returns true.
"""
return _Custom(callback, filter_fn)
18 changes: 17 additions & 1 deletion tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from pyplumio.filters import aggregate, debounce, delta, on_change, throttle
from pyplumio.filters import aggregate, custom, debounce, delta, on_change, throttle
from pyplumio.helpers.parameter import Parameter
from pyplumio.structures.alerts import Alert

Expand Down Expand Up @@ -184,3 +184,19 @@ async def test_aggregate(mock_time) -> None:
# Test with non-numeric value.
with pytest.raises(ValueError):
await wrapped_callback("banana")


async def test_custom() -> None:
"""Test custom filter."""
test_callback = AsyncMock()
wrapped_callback = custom(test_callback, lambda x: len(x) == 4)

await wrapped_callback([1, 2])
test_callback.assert_not_awaited()

await wrapped_callback([1, 2, 3, 4])
test_callback.assert_awaited_once_with([1, 2, 3, 4])
test_callback.reset_mock()

await wrapped_callback([])
test_callback.assert_not_awaited()

0 comments on commit 9405059

Please sign in to comment.