Due to the use of the dataclasses mixin on the SQLAlchemy types, a back_populates creates a RecursiveError when comparing two types. This occurs because the dataclass will overwrite the __eq__ operator, and it doesn't know when to stop comparing relationships. Removing the dataclasses isn't the best approach, since then __init__, __eq__ and __repr__ methods would have to be added to all types. Thus the solution was to remove the relationship on the child (on a one-to-one relationship) from the __eq__ operation, with the use of the compare parameter. Took the opportunity to define more logical __init__ methods on the `Rule` and child classes. Also revised the parameter options on some DB types.
110 lines
3.3 KiB
Python
110 lines
3.3 KiB
Python
from datetime import date
|
|
from decimal import Decimal
|
|
|
|
import mocks.categories as mock
|
|
|
|
from pfbudget.db.model import (
|
|
BankTransaction,
|
|
CategoryRule,
|
|
CategorySelector,
|
|
Selector_T,
|
|
TransactionCategory,
|
|
TransactionTag,
|
|
)
|
|
from pfbudget.transform.categorizer import Categorizer
|
|
from pfbudget.transform.nullifier import Nullifier
|
|
from pfbudget.transform.tagger import Tagger
|
|
from pfbudget.transform.transform import Transformer
|
|
|
|
|
|
class TestTransform:
|
|
def test_nullifier(self):
|
|
transactions = [
|
|
BankTransaction(date(2023, 1, 1), "", Decimal("-500"), bank="Bank#1"),
|
|
BankTransaction(date(2023, 1, 2), "", Decimal("500"), bank="Bank#2"),
|
|
]
|
|
|
|
for t in transactions:
|
|
assert not t.category
|
|
|
|
categorizer: Transformer = Nullifier()
|
|
transactions = categorizer.transform(transactions)
|
|
|
|
for t in transactions:
|
|
assert t.category == TransactionCategory(
|
|
"null", CategorySelector(Selector_T.nullifier)
|
|
)
|
|
|
|
def test_nullifier_inplace(self):
|
|
transactions = [
|
|
BankTransaction(date(2023, 1, 1), "", Decimal("-500"), bank="Bank#1"),
|
|
BankTransaction(date(2023, 1, 2), "", Decimal("500"), bank="Bank#2"),
|
|
]
|
|
|
|
for t in transactions:
|
|
assert not t.category
|
|
|
|
categorizer: Transformer = Nullifier()
|
|
categorizer.transform_inplace(transactions)
|
|
|
|
for t in transactions:
|
|
assert t.category == TransactionCategory(
|
|
"null", CategorySelector(Selector_T.nullifier)
|
|
)
|
|
|
|
def test_nullifier_with_rules(self):
|
|
transactions = [
|
|
BankTransaction(date(2023, 1, 1), "", Decimal("-500"), bank="Bank#1"),
|
|
BankTransaction(date(2023, 1, 2), "", Decimal("500"), bank="Bank#2"),
|
|
]
|
|
|
|
for t in transactions:
|
|
assert not t.category
|
|
|
|
rules = [CategoryRule("null", bank="Bank#1")]
|
|
|
|
categorizer: Transformer = Nullifier(rules)
|
|
transactions = categorizer.transform(transactions)
|
|
|
|
for t in transactions:
|
|
assert not t.category
|
|
|
|
rules.append(CategoryRule("null", bank="Bank#2"))
|
|
categorizer = Nullifier(rules)
|
|
transactions = categorizer.transform(transactions)
|
|
|
|
for t in transactions:
|
|
assert t.category == TransactionCategory(
|
|
"null", CategorySelector(Selector_T.nullifier)
|
|
)
|
|
|
|
def test_tagger(self):
|
|
transactions = [
|
|
BankTransaction(date(2023, 1, 1), "desc#1", Decimal("-10"), bank="Bank#1")
|
|
]
|
|
|
|
for t in transactions:
|
|
assert not t.category
|
|
|
|
categorizer: Transformer = Tagger(mock.tag_1.rules)
|
|
transactions = categorizer.transform(transactions)
|
|
|
|
for t in transactions:
|
|
assert TransactionTag("tag#1") in t.tags
|
|
|
|
def test_categorize(self):
|
|
transactions = [
|
|
BankTransaction(date(2023, 1, 1), "desc#1", Decimal("-10"), bank="Bank#1")
|
|
]
|
|
|
|
for t in transactions:
|
|
assert not t.category
|
|
|
|
categorizer: Transformer = Categorizer(mock.category1.rules)
|
|
transactions = categorizer.transform(transactions)
|
|
|
|
for t in transactions:
|
|
assert t.category == TransactionCategory(
|
|
"cat#1", CategorySelector(Selector_T.rules)
|
|
)
|