Skip to content

Commit

Permalink
Support after, before, newer/older_than searches on dates
Browse files Browse the repository at this point in the history
  • Loading branch information
mesozoic committed Feb 16, 2024
1 parent 24e8305 commit 8026938
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 49 deletions.
15 changes: 12 additions & 3 deletions gmail_yaml_filters/ruleset.py
Expand Up @@ -3,7 +3,7 @@
from __future__ import print_function, unicode_literals

from collections import OrderedDict
from datetime import datetime
from datetime import date, datetime
from functools import total_ordering
from itertools import chain
from operator import attrgetter
Expand Down Expand Up @@ -125,13 +125,15 @@ def _format_has_shortcuts(key, value):
return (key, value)


def _search_operator(keyword):
def _search_operator(keyword, wrap=True):
def formatter(key, value):
condition = "hasTheWord"
if value and value[0] == "-":
condition = "doesNotHaveTheWord"
value = value[1:]
return (condition, "{}:({})".format(keyword, value))
if wrap:
value = f"({value})"
return (condition, f"{keyword}:{value}")

return formatter

Expand Down Expand Up @@ -191,15 +193,20 @@ class RuleCondition(_RuleConstruction):
# allows `has: attachment`, `has: drive`, etc. in YAML
"has": _format_has_shortcuts,
# allows `bcc: whatever`, `is: starred`, etc. in YAML
"after": _search_operator("after", wrap=False),
"bcc": _search_operator("bcc"),
"before": _search_operator("before", wrap=False),
"category": _search_operator("category"),
"cc": _search_operator("cc"),
"deliveredto": _search_operator("deliveredto"),
"filename": _search_operator("filename"),
"in": _search_operator("in"),
"is": _search_operator("is"),
"labeled": _search_operator("label"),
"larger": _search_operator("larger"),
"list": _search_operator("list"),
"newer_than": _search_operator("newer_than", wrap=False),
"older_than": _search_operator("older_than", wrap=False),
"rfc822msgid": _search_operator("rfc822msgid"),
"size": _search_operator("size"),
"smaller": _search_operator("smaller"),
Expand Down Expand Up @@ -417,6 +424,8 @@ def add(self, key, value, validate=True):
elif isinstance(value, Iterable):
for actual_value in value:
self.add(key, actual_value)
elif isinstance(value, date):
self.add_construction(key, value.isoformat())
else:
raise InvalidRuleType(type(value))

Expand Down
76 changes: 30 additions & 46 deletions gmail_yaml_filters/tests/test_ruleset.py
@@ -1,6 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from datetime import date

import pytest

from gmail_yaml_filters.ruleset import RuleAction, RuleCondition, RuleSet


Expand All @@ -22,52 +26,32 @@ def sample_rule(name):
# Test how identifier_map and formatter_map operate


def test_condition_has():
assert _flat({"has": "whatever"}) == {
"hasTheWord": RuleCondition("hasTheWord", "whatever"),
}


def test_condition_has_special():
assert _flat({"has": "drive"}) == {
"hasTheWord": RuleCondition("hasTheWord", "has:drive"),
}


def test_condition_has_label():
assert _flat({"labeled": "whatever"}) == {
"hasTheWord": RuleCondition("hasTheWord", "label:(whatever)"),
}


def test_condition_does_not_have_label():
assert _flat({"labeled": "-whatever"}) == {
"doesNotHaveTheWord": RuleCondition("doesNotHaveTheWord", "label:(whatever)"),
}


def test_condition_is():
assert _flat({"is": "snoozed"}) == {
"hasTheWord": RuleCondition("hasTheWord", "is:(snoozed)"),
}


def test_condition_is_not():
assert _flat({"is": "-snoozed"}) == {
"doesNotHaveTheWord": RuleCondition("doesNotHaveTheWord", "is:(snoozed)"),
}


def test_action_archive():
assert _flat({"archive": True}) == {
"shouldArchive": RuleAction("shouldArchive", "true"),
}


def test_action_forward():
assert _flat({"forward": "someone@example.com"}) == {
"forwardTo": RuleAction("forwardTo", "someone@example.com"),
}
@pytest.mark.parametrize(
"input,condition,value",
[
({"has": "whatever"}, "hasTheWord", "whatever"),
({"has": "drive"}, "hasTheWord", "has:drive"),
({"labeled": "whatever"}, "hasTheWord", "label:(whatever)"),
({"labeled": "-whatever"}, "doesNotHaveTheWord", "label:(whatever)"),
({"is": "snoozed"}, "hasTheWord", "is:(snoozed)"),
({"is": "-snoozed"}, "doesNotHaveTheWord", "is:(snoozed)"),
({"after": date(2024, 2, 15)}, "hasTheWord", "after:2024-02-15"),
({"before": date(2024, 2, 15)}, "hasTheWord", "before:2024-02-15"),
],
)
def test_flattened_condition(input, condition, value):
assert _flat(input) == {condition: RuleCondition(condition, value)}


@pytest.mark.parametrize(
"input,condition,value",
[
({"archive": True}, "shouldArchive", "true"),
({"forward": "someone@example.com"}, "forwardTo", "someone@example.com"),
],
)
def test_flattened_action(input, condition, value):
assert _flat(input) == {condition: RuleAction(condition, value)}


def test_publishable():
Expand Down

0 comments on commit 8026938

Please sign in to comment.