[Refactor] Categorizer now implements Transform
Test adapted for new interface. Exchanged manual input functionality for throwing an exception. Removed timer at transformer level.
This commit is contained in:
parent
2c7c527ea9
commit
b1de4d519a
@ -103,10 +103,11 @@ class Manager:
|
||||
categories = session.get(Category)
|
||||
tags = session.get(Tag)
|
||||
|
||||
null_rules = [cat.rules for cat in categories if cat.name == "null"]
|
||||
Nullifier(null_rules).transform_inplace(uncategorized)
|
||||
rules = [cat.rules for cat in categories if cat.name == "null"]
|
||||
Nullifier(rules).transform_inplace(uncategorized)
|
||||
|
||||
Categorizer().rules(uncategorized, categories, tags, params[0])
|
||||
rules = [rule for cat in categories for rule in cat.rules]
|
||||
Categorizer(rules).transform_inplace(uncategorized)
|
||||
|
||||
rules = [rule for tag in tags for rule in tag.rules]
|
||||
Tagger(rules).transform_inplace(uncategorized)
|
||||
|
||||
@ -1,78 +1,36 @@
|
||||
from codetiming import Timer
|
||||
from copy import deepcopy
|
||||
from typing import Sequence
|
||||
|
||||
import pfbudget.db.model as t
|
||||
from pfbudget.db.model import (
|
||||
CategoryRule,
|
||||
CategorySelector,
|
||||
Selector_T,
|
||||
Transaction,
|
||||
TransactionCategory,
|
||||
)
|
||||
from .exceptions import TransactionCategorizedError
|
||||
from .transform import Transformer
|
||||
|
||||
|
||||
class Categorizer:
|
||||
options = {}
|
||||
class Categorizer(Transformer):
|
||||
def __init__(self, rules: Sequence[CategoryRule]):
|
||||
self.rules = rules
|
||||
|
||||
def __init__(self):
|
||||
self.options["null_days"] = 3
|
||||
def transform(self, transactions: Sequence[Transaction]) -> Sequence[Transaction]:
|
||||
result = deepcopy(transactions)
|
||||
self.transform_inplace(result)
|
||||
|
||||
def rules(
|
||||
self,
|
||||
transactions: Sequence[t.BankTransaction],
|
||||
categories: Sequence[t.Category],
|
||||
tags: Sequence[t.Tag],
|
||||
nullify: bool = True
|
||||
):
|
||||
"""Overarching categorization tool
|
||||
return result
|
||||
|
||||
Receives a list of transactions (by ref) and updates their category according
|
||||
to the rules defined for each category
|
||||
def transform_inplace(self, transactions: Sequence[Transaction]) -> None:
|
||||
for rule in self.rules:
|
||||
for transaction in transactions:
|
||||
if transaction.category:
|
||||
raise TransactionCategorizedError(transaction)
|
||||
|
||||
Args:
|
||||
transactions (Sequence[BankTransaction]): uncategorized transactions
|
||||
categories (Sequence[Category]): available categories
|
||||
tags (Sequence[Tag]): currently available tags
|
||||
"""
|
||||
if not rule.matches(transaction):
|
||||
continue
|
||||
|
||||
categories = [cat for cat in categories if cat.name != "null"]
|
||||
|
||||
self._rule_based_categories(transactions, categories)
|
||||
|
||||
@Timer(name="categoryrules")
|
||||
def _rule_based_categories(
|
||||
self,
|
||||
transactions: Sequence[t.BankTransaction],
|
||||
categories: Sequence[t.Category],
|
||||
):
|
||||
print(f"Categorizing {len(transactions)} transactions")
|
||||
d = {}
|
||||
for category in [c for c in categories if c.rules]:
|
||||
for rule in category.rules:
|
||||
# for transaction in [t for t in transactions if not t.category]:
|
||||
for transaction in [
|
||||
t
|
||||
for t in transactions
|
||||
if not t.category or t.category.name != "null"
|
||||
]:
|
||||
if not rule.matches(transaction):
|
||||
continue
|
||||
|
||||
# passed all conditions, assign category
|
||||
if transaction.category:
|
||||
if transaction.category.name == category.name:
|
||||
continue
|
||||
|
||||
if (
|
||||
input(
|
||||
f"Overwrite {transaction} with {category.name}? (y/n)"
|
||||
)
|
||||
== "y"
|
||||
):
|
||||
transaction.category.name = category.name
|
||||
transaction.category.selector.selector = t.Selector_T.rules
|
||||
else:
|
||||
transaction.category = t.TransactionCategory(
|
||||
category.name, t.CategorySelector(t.Selector_T.rules)
|
||||
)
|
||||
|
||||
if rule in d:
|
||||
d[rule] += 1
|
||||
else:
|
||||
d[rule] = 1
|
||||
|
||||
for k, v in d.items():
|
||||
print(f"{v}: {k}")
|
||||
transaction.category = TransactionCategory(
|
||||
rule.name, CategorySelector(Selector_T.rules)
|
||||
)
|
||||
|
||||
@ -1,2 +1,6 @@
|
||||
class MoreThanOneMatchError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TransactionCategorizedError(Exception):
|
||||
pass
|
||||
|
||||
@ -71,7 +71,7 @@ class TestTransform:
|
||||
assert not t.category
|
||||
|
||||
rules.append(CategoryRule(None, None, None, None, "Bank#2", None, None, "null"))
|
||||
categorizer: Transformer = Nullifier(rules)
|
||||
categorizer = Nullifier(rules)
|
||||
transactions = categorizer.transform(transactions)
|
||||
|
||||
for t in transactions:
|
||||
@ -87,7 +87,7 @@ class TestTransform:
|
||||
for t in transactions:
|
||||
assert not t.category
|
||||
|
||||
categorizer = Tagger(mock.tag_1.rules)
|
||||
categorizer: Transformer = Tagger(mock.tag_1.rules)
|
||||
transactions = categorizer.transform(transactions)
|
||||
|
||||
for t in transactions:
|
||||
@ -101,8 +101,8 @@ class TestTransform:
|
||||
for t in transactions:
|
||||
assert not t.category
|
||||
|
||||
categorizer = Categorizer()
|
||||
categorizer.rules(transactions, [mock.category1], [])
|
||||
categorizer: Transformer = Categorizer(mock.category1.rules)
|
||||
transactions: Transformer = categorizer.transform(transactions)
|
||||
|
||||
for t in transactions:
|
||||
assert t.category == TransactionCategory(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user