~trufas/ledgeroni

97851fc857fedc648e6c5165fc587bce4354bb9f — Rafael Castillo 1 year, 10 months ago 3c2756c
propery filter in balance command
4 files changed, 35 insertions(+), 30 deletions(-)

M ledgeroni/commands/balance.py
M ledgeroni/expression.py
M ledgeroni/query.py
M tests/test_expression.py
M ledgeroni/commands/balance.py => ledgeroni/commands/balance.py +3 -1
@@ 1,6 1,7 @@
"""
balance.py: Defines the `balance` subcommand
"""
import sys
import click
from colorama import Fore, Style



@@ 9,6 10,7 @@ from ledgeroni.aggregate import AccountAggregate
from ledgeroni.util import format_amount
from ledgeroni import expression


@click.command()
@click.argument('filter_strs', nargs=-1)
@click.pass_context


@@ 19,7 21,7 @@ def print_balance(ctx, filter_strs):
        filter_query = expression.build_expression(' '.join(filter_strs))
    journal = Journal(query=filter_query)

    aggregate = AccountAggregate()
    aggregate = AccountAggregate(query=filter_query)

    price_db = ctx.obj.get('PRICE_DB', None)
    if price_db:

M ledgeroni/expression.py => ledgeroni/expression.py +10 -10
@@ 68,21 68,21 @@ def build_expr_from_postfix(postfix_expr):
    operand_stack = deque()
    for token in postfix_expr:
        if token == 'and':
            a, b = operand_stack.pop(), operand_stack.pop()
            operand_stack.append(And((a, b)))
            op1, op2 = operand_stack.pop(), operand_stack.pop()
            operand_stack.append(And((op1, op2)))
        elif token == 'or':
            a, b = operand_stack.pop(), operand_stack.pop()
            operand_stack.append(Or((a, b)))
            op1, op2 = operand_stack.pop(), operand_stack.pop()
            operand_stack.append(Or((op1, op2)))
        elif token == 'not':
            a = operand_stack.pop()
            operand_stack.append(Not(a))
            operand = operand_stack.pop()
            operand_stack.append(Not(operand))
        elif token in ('payee', '@'):
            a = operand_stack.pop()
            if not isinstance(a, RegexQuery):
            operand = operand_stack.pop()
            if not isinstance(operand, RegexQuery):
                raise ValueError
            operand_stack.append(PayeeQuery(a))
            operand_stack.append(PayeeQuery(operand))
        else:
            operand = RegexQuery(re.compile(token, re.IGNORECASE))
            operand = RegexQuery.from_string(token)
            operand_stack.append(operand)

    if len(operand_stack) != 1:

M ledgeroni/query.py => ledgeroni/query.py +4 -0
@@ 28,6 28,10 @@ class RegexQuery(Query):
        return {i for i, posting in enumerate(trans.postings)
                if self.regex.search(posting.account_name) is not None}

    @classmethod
    def from_string(cls, s):
        return cls(regex=re.compile(s, re.IGNORECASE))


@dataclass(frozen=True)
class Or(Query):

M tests/test_expression.py => tests/test_expression.py +18 -19
@@ 1,4 1,3 @@
import re
import pytest
from ledgeroni import expression
from ledgeroni.query import Or, And, Not, RegexQuery, PayeeQuery


@@ 78,43 77,43 @@ class TestBuildExprFromPostfix:
    def test_binary(self):
        postfix = ['x', 'y', 'or']
        result = expression.build_expr_from_postfix(postfix)
        query = Or((RegexQuery(re.compile('y')),
                    RegexQuery(re.compile('x'))))
        query = Or((RegexQuery.from_string('y'),
                    RegexQuery.from_string('x')))

        assert result == query

        postfix = ['x', 'y', 'and']
        result = expression.build_expr_from_postfix(postfix)
        query = And((RegexQuery(re.compile('y')),
                     RegexQuery(re.compile('x'))))
        query = And((RegexQuery.from_string('y'),
                     RegexQuery.from_string('x')))

        assert result == query

    def test_unary(self):
        postfix = ['x', 'not']
        result = expression.build_expr_from_postfix(postfix)
        query = Not(RegexQuery(re.compile('x')))
        query = Not(RegexQuery.from_string('x'))

        assert result == query

    def test_single(self):
        postfix = ['x']
        result = expression.build_expr_from_postfix(postfix)
        query = RegexQuery(re.compile('x'))
        query = RegexQuery.from_string('x')

        assert result == query

    def test_payee(self):
        postfix = ['x', 'payee']
        result = expression.build_expr_from_postfix(postfix)
        query = PayeeQuery(RegexQuery(re.compile('x')))
        query = PayeeQuery(RegexQuery.from_string('x'))

        assert result == query

    def test_payee_at(self):
        postfix = ['x', '@']
        result = expression.build_expr_from_postfix(postfix)
        query = PayeeQuery(RegexQuery(re.compile('x')))
        query = PayeeQuery(RegexQuery.from_string('x'))

        assert result == query



@@ 126,8 125,8 @@ class TestBuildExprFromPostfix:
    def test_precedence(self):
        postfix = ['y', 'not', 'x', '@', 'and']
        result = expression.build_expr_from_postfix(postfix)
        query = And((PayeeQuery(RegexQuery(re.compile('x'))),
                    Not(RegexQuery(re.compile('y')))))
        query = And((PayeeQuery(RegexQuery.from_string('x')),
                     Not(RegexQuery.from_string('y'))))

        assert result == query



@@ 136,37 135,37 @@ class TestBuildExpression:
    def test_binary(self):
        postfix = 'x or y'
        result = expression.build_expression(postfix)
        query = Or((RegexQuery(re.compile('y')),
                    RegexQuery(re.compile('x'))))
        query = Or((RegexQuery.from_string('y'),
                    RegexQuery.from_string('x')))

        assert result == query

        postfix = 'x and y'
        result = expression.build_expression(postfix)
        query = And((RegexQuery(re.compile('y')),
                     RegexQuery(re.compile('x'))))
        query = And((RegexQuery.from_string('y'),
                     RegexQuery.from_string('x')))

        assert result == query

    def test_unary(self):
        postfix = 'not x'
        result = expression.build_expression(postfix)
        query = Not(RegexQuery(re.compile('x')))
        query = Not(RegexQuery.from_string('x'))

        assert result == query

    def test_single(self):
        postfix = 'x'
        result = expression.build_expression(postfix)
        query = RegexQuery(re.compile('x'))
        query = RegexQuery.from_string('x')

        assert result == query

    def test_implicit_or(self):
        postfix = 'x y'
        result = expression.build_expression(postfix)
        query = Or((RegexQuery(re.compile('y')),
                    RegexQuery(re.compile('x'))))
        query = Or((RegexQuery.from_string('y'),
                    RegexQuery.from_string('x')))

        assert result == query