async def test_str() -> None: assert "foo~=^f" == str(filter.BinaryFilter({"~=": ("foo", "^f")})) assert "-foo=1" == str(filter.BinaryFilter({"-": {"=": ("foo", 1)}})) assert "foo" == str(filter.BinaryFilter({"=": ("foo", True)})) assert "-bar" == str(filter.BinaryFilter({"=": ("bar", False)})) with pytest.raises(filter.InvalidOperator): str(filter.BinaryFilter({">=": ("bar", False)}))
async def test_contains() -> None: f = filter.BinaryFilter({"=": ("foo", 1)}) assert await f(FakePR({"foo": [1, 2]})) assert not await f(FakePR({"foo": [2, 3]})) assert await f(FakePR({"foo": (1, 2)})) f = filter.BinaryFilter({">": ("foo", 2)}) assert not await f(FakePR({"foo": [1, 2]})) assert await f(FakePR({"foo": [2, 3]}))
async def test_and() -> None: f = filter.BinaryFilter({"and": ({"=": ("foo", 1)}, {"=": ("bar", 1)})}) assert await f(FakePR({"bar": 1, "foo": 1})) assert not await f(FakePR({"bar": 2, "foo": 2})) assert not await f(FakePR({"bar": 2, "foo": 1})) assert not await f(FakePR({"bar": 1, "foo": 2})) with pytest.raises(filter.ParseError): filter.BinaryFilter({"or": {"foo": "whar"}})
async def test_regexp() -> None: f = filter.BinaryFilter({"~=": ("foo", "^f")}) assert await f(FakePR({"foo": "foobar"})) assert await f(FakePR({"foo": "foobaz"})) assert not await f(FakePR({"foo": "x"})) assert not await f(FakePR({"foo": None})) f = filter.BinaryFilter({"~=": ("foo", "^$")}) assert await f(FakePR({"foo": ""})) assert not await f(FakePR({"foo": "x"}))
async def test_set_value_expanders() -> None: f = filter.BinaryFilter( {"=": ("foo", "@bar")}, ) f.value_expanders["foo"] = lambda x: [x.replace("@", "foo")] assert await f(FakePR({"foo": "foobar"})) assert not await f(FakePR({"foo": "x"}))
async def test_chain() -> None: f1 = {"=": ("bar", 1)} f2 = {"=": ("foo", 1)} f = filter.BinaryFilter({"and": (f1, f2)}) assert await f(FakePR({"bar": 1, "foo": 1})) assert not await f(FakePR({"bar": 2, "foo": 2})) assert not await f(FakePR({"bar": 2, "foo": 1})) assert not await f(FakePR({"bar": 1, "foo": 2}))
async def test_partial_datetime_binary( klass: typing.Type[date.PartialDatetime], ) -> None: f = filter.BinaryFilter({"<=": ("foo", klass(5))}) assert await f(FakePR({"foo": klass(2)})) assert await f(FakePR({"foo": klass(5)})) assert not await f(FakePR({"foo": klass(7)})) f = filter.BinaryFilter({"=": ("foo", klass(5))}) assert await f(FakePR({"foo": klass(5)})) assert not await f(FakePR({"foo": klass(7)})) f = filter.BinaryFilter({">": ("foo", klass(5))}) assert await f(FakePR({"foo": klass(7)})) assert not await f(FakePR({"foo": klass(2)})) assert not await f(FakePR({"foo": klass(5)}))
async def test_optimized_len() -> None: f = filter.BinaryFilter({"=": ("#foo", 3)}) assert await f(FakePR({"foo": "bar"})) with pytest.raises(filter.InvalidOperator): await f(FakePR({"foo": 2})) assert not await f(FakePR({"foo": "a"})) assert await f(FakePR({"#foo": 3, "foo": "a"})) assert not await f(FakePR({"#foo": 2, "foo": "abc"}))
async def test_len() -> None: f = filter.BinaryFilter({"=": ("#foo", 3)}) assert await f(FakePR({"foo": "bar"})) with pytest.raises(filter.InvalidOperator): await f(FakePR({"foo": 2})) assert not await f(FakePR({"foo": "a"})) assert not await f(FakePR({"foo": "abcedf"})) assert await f(FakePR({"foo": [10, 20, 30]})) assert not await f(FakePR({"foo": [10, 20]})) assert not await f(FakePR({"foo": [10, 20, 40, 50]})) f = filter.BinaryFilter({">": ("#foo", 3)}) assert await f(FakePR({"foo": "barz"})) with pytest.raises(filter.InvalidOperator): await f(FakePR({"foo": 2})) assert not await f(FakePR({"foo": "a"})) assert await f(FakePR({"foo": "abcedf"})) assert await f(FakePR({"foo": [10, "abc", 20, 30]})) assert not await f(FakePR({"foo": [10, 20]})) assert not await f(FakePR({"foo": []}))
def update(self, condition_raw: typing.Union[str, FakeTreeT]) -> None: self.condition = condition_raw try: if isinstance(condition_raw, str): condition = parser.parse(condition_raw) else: condition = condition_raw self.partial_filter = filter.BinaryFilter( typing.cast(filter.TreeT, condition)) except (parser.ConditionParsingError, filter.InvalidQuery) as e: raise voluptuous.Invalid( message=f"Invalid condition '{condition_raw}'. {str(e)}", error_message=str(e), )
async def test_relative_datetime_binary() -> None: tree = parser.parse("updated-at<2 days ago") f = filter.BinaryFilter(tree) assert await f(FakePR({"updated-at-relative": rdtime(2)})), tree assert await f(FakePR({"updated-at-relative": rdtime(10)})), tree assert not (await f(FakePR({"updated-at-relative": rdtime(12)}))), tree assert not (await f(FakePR({"updated-at-relative": rdtime(14)}))), tree assert not (await f(FakePR({"updated-at-relative": rdtime(16)}))), tree assert not (await f(FakePR({"updated-at-relative": rdtime(18)}))), tree tree = parser.parse("updated-at<=2 days ago") f = filter.BinaryFilter(tree) assert await f(FakePR({"updated-at-relative": rdtime(2)})), tree assert await f(FakePR({"updated-at-relative": rdtime(10)})), tree assert await f(FakePR({"updated-at-relative": rdtime(12)})), tree assert not (await f(FakePR({"updated-at-relative": rdtime(14)}))), tree assert not (await f(FakePR({"updated-at-relative": rdtime(16)}))), tree assert not (await f(FakePR({"updated-at-relative": rdtime(18)}))), tree tree = parser.parse("updated-at>2 days ago") f = filter.BinaryFilter(tree) assert not (await f(FakePR({"updated-at-relative": rdtime(2)}))), tree assert not (await f(FakePR({"updated-at-relative": rdtime(10)}))), tree assert not (await f(FakePR({"updated-at-relative": rdtime(12)}))), tree assert await f(FakePR({"updated-at-relative": rdtime(14)})), tree assert await f(FakePR({"updated-at-relative": rdtime(16)})), tree assert await f(FakePR({"updated-at-relative": rdtime(18)})), tree tree = parser.parse("updated-at>=2 days ago") f = filter.BinaryFilter(tree) assert not (await f(FakePR({"updated-at-relative": rdtime(2)}))), tree assert not (await f(FakePR({"updated-at-relative": rdtime(10)}))), tree assert await f(FakePR({"updated-at-relative": rdtime(12)})), tree assert await f(FakePR({"updated-at-relative": rdtime(14)})), tree assert await f(FakePR({"updated-at-relative": rdtime(16)})), tree assert await f(FakePR({"updated-at-relative": rdtime(18)})), tree
async def test_datetime_binary() -> None: assert "foo>=2012-01-05T00:00:00" == str( filter.BinaryFilter({">=": ("foo", dtime(5))}) ) assert "foo<=2012-01-05T23:59:00" == str( filter.BinaryFilter({"<=": ("foo", dtime(5).replace(hour=23, minute=59))}) ) assert "foo<=2012-01-05T03:09:00" == str( filter.BinaryFilter({"<=": ("foo", dtime(5).replace(hour=3, minute=9))}) ) f = filter.BinaryFilter({"<=": ("foo", date.utcnow())}) assert await f(FakePR({"foo": dtime(14)})) assert await f(FakePR({"foo": dtime(2)})) assert await f(FakePR({"foo": dtime(5)})) assert not await f(FakePR({"foo": dtime(18)})) assert not await f(FakePR({"foo": dtime(23)})) f = filter.BinaryFilter({">=": ("foo", date.utcnow())}) assert await f(FakePR({"foo": dtime(14)})) assert not await f(FakePR({"foo": dtime(2)})) assert not await f(FakePR({"foo": dtime(5)})) assert await f(FakePR({"foo": dtime(18)})) assert await f(FakePR({"foo": dtime(23)}))
async def test_none() -> None: f = filter.BinaryFilter({"=": ("foo", 1)}) assert not await f(FakePR({"foo": None})) f = filter.BinaryFilter({"=": ("foo", None)}) assert await f(FakePR({"foo": None})) f = filter.BinaryFilter({"!=": ("foo", 1)}) assert await f(FakePR({"foo": None})) f = filter.BinaryFilter({">=": ("foo", 1)}) assert not await f(FakePR({"foo": None})) f = filter.BinaryFilter({"<=": ("foo", 1)}) assert not await f(FakePR({"foo": None})) f = filter.BinaryFilter({"<": ("foo", 1)}) assert not await f(FakePR({"foo": None})) f = filter.BinaryFilter({">": ("foo", 1)}) assert not await f(FakePR({"foo": None})) f = filter.BinaryFilter({"~=": ("foo", "^foo")}) assert not await f(FakePR({"foo": None}))
async def test_time_binary() -> None: assert "foo>=00:00" == str( filter.BinaryFilter({">=": ("foo", date.Time(0, 0, UTC))}) ) assert "foo<=23:59" == str( filter.BinaryFilter({"<=": ("foo", date.Time(23, 59, UTC))}) ) assert "foo<=03:09" == str( filter.BinaryFilter({"<=": ("foo", date.Time(3, 9, UTC))}) ) assert "foo<=03:09[Europe/Paris]" == str( filter.BinaryFilter( {"<=": ("foo", date.Time(3, 9, zoneinfo.ZoneInfo("Europe/Paris")))} ) ) now = date.utcnow() f = filter.BinaryFilter({"<=": ("foo", date.Time(5, 8, UTC))}) assert await f(FakePR({"foo": now.replace(hour=5, minute=8)})) assert await f(FakePR({"foo": now.replace(hour=2, minute=1)})) assert await f(FakePR({"foo": now.replace(hour=5, minute=1)})) assert not await f(FakePR({"foo": now.replace(hour=6, minute=2)})) assert not await f(FakePR({"foo": now.replace(hour=8, minute=9)})) f = filter.BinaryFilter({">=": ("foo", date.Time(5, 8, UTC))}) assert await f(FakePR({"foo": now.replace(hour=5, minute=8)})) assert not await f(FakePR({"foo": now.replace(hour=2, minute=1)})) assert not await f(FakePR({"foo": now.replace(hour=5, minute=1)})) assert await f(FakePR({"foo": now.replace(hour=6, minute=2)})) assert await f(FakePR({"foo": now.replace(hour=8, minute=9)})) f = filter.BinaryFilter( {">=": ("foo", date.Time(5, 8, zoneinfo.ZoneInfo("Europe/Paris")))} ) assert await f(FakePR({"foo": now.replace(hour=4, minute=8)})) assert not await f(FakePR({"foo": now.replace(hour=1, minute=1)})) assert not await f(FakePR({"foo": now.replace(hour=4, minute=1)})) assert await f(FakePR({"foo": now.replace(hour=5, minute=2)})) assert await f(FakePR({"foo": now.replace(hour=7, minute=9)}))
async def test_or() -> None: f = filter.BinaryFilter({"or": ({"=": ("foo", 1)}, {"=": ("bar", 1)})}) assert await f(FakePR({"foo": 1, "bar": 1})) assert not await f(FakePR({"bar": 2, "foo": 2})) assert await f(FakePR({"bar": 2, "foo": 1})) assert await f(FakePR({"bar": 1, "foo": 2}))
async def test_set_value_expanders_unset_at_init() -> None: f = filter.BinaryFilter({"=": ("foo", "@bar")}) f.value_expanders = {"foo": lambda x: [x.replace("@", "foo")]} assert await f(FakePR({"foo": "foobar"})) assert not await f(FakePR({"foo": "x"}))
async def test_does_not_contain() -> None: f = filter.BinaryFilter({"!=": ("foo", 1)}) assert await f(FakePR({"foo": []})) assert await f(FakePR({"foo": [2, 3]})) assert not await f(FakePR({"foo": (1, 2)}))
async def test_set_value_expanders_does_not_contain() -> None: f = filter.BinaryFilter({"!=": ("foo", "@bar")}) f.value_expanders["foo"] = lambda x: ["foobaz", "foobar"] assert not await f(FakePR({"foo": "foobar"})) assert not await f(FakePR({"foo": "foobaz"})) assert await f(FakePR({"foo": "foobiz"}))
async def test_not() -> None: f = filter.BinaryFilter({"-": {"=": ("foo", 1)}}) assert not await f(FakePR({"foo": 1})) assert await f(FakePR({"foo": 2}))
async def test_string() -> None: f = filter.BinaryFilter({"=": ("foo", "bar")}) assert await f(FakePR({"foo": "bar"})) assert not await f(FakePR({"foo": 2}))
async def test_partial_datetime_year_str() -> None: assert "foo>=2005" == str(filter.BinaryFilter({">=": ("foo", date.Year(2005))})) assert "foo<=2004" == str(filter.BinaryFilter({"<=": ("foo", date.Year(2004))})) assert "foo=2003" == str(filter.BinaryFilter({"=": ("foo", date.Year(2003))}))
async def test_unknown_attribute() -> None: f = filter.BinaryFilter({"=": ("foo", 1)}) with pytest.raises(filter.UnknownAttribute): await f(FakePR({"bar": 1}))
async def test_parser_group() -> None: string = str( filter.BinaryFilter({"and": ({"=": ("head", "foobar")}, {">": ("#files", 3)})}) ) assert string == "(head=foobar and #files>3)"
async def test_parse_error() -> None: with pytest.raises(filter.ParseError): filter.BinaryFilter({})
async def test_unknown_operator() -> None: with pytest.raises(filter.UnknownOperator): filter.BinaryFilter({"oops": (1, 2)}) # type: ignore[arg-type]
async def test_invalid_arguments() -> None: with pytest.raises(filter.InvalidArguments): filter.BinaryFilter({"=": (1, 2, 3)}) # type: ignore[typeddict-item]
async def test_parser_leaf() -> None: for string in ("head=foobar", "-base=main", "#files>3"): tree = parser.parse(string) assert string == str(filter.BinaryFilter(tree))
async def test_dow_str() -> None: assert "foo>=Fri" == str(filter.BinaryFilter({">=": ("foo", date.DayOfWeek(5))})) assert "foo<=Sun" == str(filter.BinaryFilter({"<=": ("foo", date.DayOfWeek(7))})) assert "foo=Wed" == str(filter.BinaryFilter({"=": ("foo", date.DayOfWeek(3))}))
async def test_partial_datetime_str( klass: typing.Type[date.PartialDatetime], ) -> None: assert "foo>=5" == str(filter.BinaryFilter({">=": ("foo", klass(5))})) assert "foo<=4" == str(filter.BinaryFilter({"<=": ("foo", klass(4))})) assert "foo=3" == str(filter.BinaryFilter({"=": ("foo", klass(3))}))
async def test_regexp_invalid() -> None: with pytest.raises(filter.InvalidArguments): filter.BinaryFilter({"~=": ("foo", r"([^\s\w])(\s*\1+")})