feat(rules): Add extended mode
This commit is contained in:
@@ -1,22 +1,40 @@
|
||||
import re
|
||||
from typing import Self
|
||||
import os
|
||||
|
||||
|
||||
class Rule:
|
||||
__slots__ = ("conditions", "values")
|
||||
__slots__ = ("conditions", "values", "extended")
|
||||
|
||||
def __init__(self, conditions: dict[str, str], values: dict[str, str]):
|
||||
def __init__(
|
||||
self, conditions: dict[str, str], values: dict[str, str], extended=False
|
||||
):
|
||||
self.conditions = conditions
|
||||
self.values = values
|
||||
self.extended = extended
|
||||
|
||||
def check(self, record: dict[str, str]) -> bool:
|
||||
"""
|
||||
Check whether this rule applies to the given record fields.
|
||||
"""
|
||||
return all(
|
||||
if self.extended:
|
||||
match = True
|
||||
for key, pattern in self.conditions.items():
|
||||
actualvalue = record.get(key, None)
|
||||
if isinstance(pattern, str) and isinstance(actualvalue, str):
|
||||
match = match and bool(re.match(pattern, actualvalue))
|
||||
else:
|
||||
# Fallback to equality
|
||||
match = match and (pattern == actualvalue)
|
||||
if not match:
|
||||
break
|
||||
else:
|
||||
match = all(
|
||||
record.get(key, None) == value for key, value in self.conditions.items()
|
||||
)
|
||||
|
||||
return match
|
||||
|
||||
|
||||
class RuleInterface:
|
||||
"""
|
||||
@@ -71,6 +89,7 @@ class JSONRuleInterface(RuleInterface):
|
||||
rule = Rule(
|
||||
conditions=rule_data["record_fields"],
|
||||
values=rule_data["transaction_fields"],
|
||||
extended=rule_data.get("extended", False),
|
||||
)
|
||||
rules.append(rule)
|
||||
|
||||
@@ -85,6 +104,7 @@ class JSONRuleInterface(RuleInterface):
|
||||
{
|
||||
"record_fields": rule.conditions,
|
||||
"transaction_fields": rule.values,
|
||||
"extended": rule.extended,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -167,9 +167,9 @@ class MainWindow(ThemedTk):
|
||||
|
||||
def rule_created(self, event):
|
||||
logger.debug(f"Received RowEditor rulecreated event {event!r}")
|
||||
conditions, values = self.editor.make_rule()
|
||||
conditions, values, extended = self.editor.make_rule()
|
||||
|
||||
rule = Rule(conditions, values)
|
||||
rule = Rule(conditions, values, extended)
|
||||
|
||||
affected = sum(rule.check(record.match_fields()) for record in self.rows)
|
||||
self.ruleset.add_rule(rule)
|
||||
|
||||
@@ -59,13 +59,29 @@ class RowEditor(ttk.Frame):
|
||||
)
|
||||
self.txn_frame.columnconfigure(2, weight=1)
|
||||
|
||||
self.matchopt_frame = ttk.Frame(self)
|
||||
self.matchopt_frame.grid(row=0, column=1, sticky="ew")
|
||||
self.matchopt_frame.columnconfigure(0, weight=0)
|
||||
self.matchopt_frame.columnconfigure(1, weight=1)
|
||||
self.matchopt_frame.columnconfigure(2, weight=0)
|
||||
self.matchopt_frame.columnconfigure(3, weight=0)
|
||||
|
||||
self.match_var = BooleanVar()
|
||||
self.match_toggle = ttk.Checkbutton(
|
||||
self, variable=self.match_var, command=self._display_matchboxes
|
||||
)
|
||||
self.match_label = ttk.Label(self, text="Rule creation mode")
|
||||
self.match_toggle.grid(row=0, column=0, padx=11, pady=10, sticky="nw")
|
||||
self.match_label.grid(row=0, column=1, padx=7, pady=10, sticky="nw")
|
||||
|
||||
self.match_label = ttk.Label(self.matchopt_frame, text="Rule creation mode")
|
||||
self.match_label.grid(row=0, column=0, padx=7, pady=10, sticky="nw")
|
||||
|
||||
self.extended_var = BooleanVar()
|
||||
self.extended_toggle = ttk.Checkbutton(
|
||||
self.matchopt_frame, variable=self.extended_var
|
||||
)
|
||||
self.extended_label = ttk.Label(self.matchopt_frame, text="Extended")
|
||||
self.extended_toggle.grid(row=0, column=2, padx=11, pady=10, sticky="nw")
|
||||
self.extended_label.grid(row=0, column=3, padx=7, pady=10, sticky="nw")
|
||||
|
||||
self.button_frame = ttk.Frame(self, padding=(2, 2, 3, 3))
|
||||
self.button_frame.grid(row=3, column=0, columnspan=2, sticky="s")
|
||||
@@ -236,6 +252,8 @@ class RowEditor(ttk.Frame):
|
||||
label.grid_remove()
|
||||
entry.grid(row=i, column=2, sticky="ew", padx=5)
|
||||
self.rule_button.configure(state="enabled")
|
||||
self.extended_toggle.grid(row=0, column=2, padx=11, pady=10, sticky="nw")
|
||||
self.extended_label.grid(row=0, column=3, padx=7, pady=10, sticky="nw")
|
||||
else:
|
||||
# Disable match boxes
|
||||
for i, (box, _, _) in enumerate(self.txn_rows.values()):
|
||||
@@ -249,6 +267,8 @@ class RowEditor(ttk.Frame):
|
||||
entry.grid_remove()
|
||||
# Also disable rule button
|
||||
self.rule_button.configure(state="disabled")
|
||||
self.extended_toggle.grid_remove()
|
||||
self.extended_label.grid_remove()
|
||||
|
||||
def do_save_txn(self):
|
||||
if not self.rows:
|
||||
@@ -299,7 +319,7 @@ class RowEditor(ttk.Frame):
|
||||
}
|
||||
update_fields = txn.parse_input(input_fields)
|
||||
|
||||
return (rule_record_fields, update_fields)
|
||||
return (rule_record_fields, update_fields, self.extended_var.get())
|
||||
|
||||
def _display_txns(self, txns: list[PartialTXN]):
|
||||
if txns and not self.showing_txn:
|
||||
|
||||
Reference in New Issue
Block a user