reconcile: Add type checking information to new prototype reconcilers.

This commit is contained in:
Ben Sturmfels 2022-02-04 15:03:23 +11:00
parent 43548a1ac9
commit ed0bc469ce
Signed by: bsturmfels
GPG key ID: 023C05E2C9C068F0
2 changed files with 17 additions and 13 deletions

View file

@ -20,19 +20,21 @@ import datetime
import io
import tempfile
import textwrap
import typing
from typing import List
import os
from beancount import loader
from beancount.query.query import run_query
def end_of_month(date):
def end_of_month(date: datetime.date) -> datetime.date:
"""Given a date, return the last day of the month."""
# Using 'day' replaces, rather than adds.
return date + relativedelta(day=31)
def format_record_for_grep(row, homedir):
def format_record_for_grep(row: typing.List, homedir: str) -> typing.List:
"""Return a line in a grep-style.
This is so the line can be fed into Emacs grep-mode for quickly jumping to
@ -42,7 +44,7 @@ def format_record_for_grep(row, homedir):
return [f'{file}:{row[1]}:'] + row[2:]
def max_column_widths(rows):
def max_column_widths(rows: List) -> List[int]:
"""Return the max width for each column in a table of data."""
if not rows:
return []
@ -55,7 +57,7 @@ def max_column_widths(rows):
return maxes
def tabulate(rows, headers=None):
def tabulate(rows: List, headers: List=None) -> str:
"""Format a table of data as a string.
Implemented here to avoid adding dependency on "tabulate" package.
@ -101,8 +103,9 @@ else:
if not (args.cur_end_date and args.prev_end_date):
parser.error(' --prev-end-date and --cur-end-date must be used together')
preDate = args.prev_end_date
lastDateInPeriod = args.cur_end_date
month = lastDateInPeriod.strftime('%Y-%m')
lastDateInPeriod = args.cur_end_date.isoformat()
month = args.cur_end_date.strftime('%Y-%m')
grep_output_file: typing.IO
if args.grep_output_filename:
grep_output_file = open(args.grep_output_filename, 'w')
else:
@ -168,7 +171,7 @@ for desc, query in QUERIES.items():
if not rrows:
print(f'{desc:<55} {"N/A":>11}')
elif desc.startswith('04'):
homedir = os.getenv('HOME')
homedir = os.getenv('HOME', '')
print(f'{desc}\n See {grep_output_file.name}')
grep_rows = [format_record_for_grep(row, homedir) for row in rrows]
print(tabulate(grep_rows), file=grep_output_file)

View file

@ -10,14 +10,15 @@ import argparse
import csv
import datetime
import decimal
from typing import Dict, List, Tuple
from beancount import loader
from beancount.query.query import run_query
from thefuzz import fuzz
from thefuzz import fuzz # type: ignore
# NOTE: Statement doesn't seem to give us a running balance or a final total.
def standardize_amex_record(row):
def standardize_amex_record(row: Dict) -> Dict:
return {
'date': datetime.datetime.strptime(row['Date'], '%m/%d/%Y').date(),
'amount': -1 * decimal.Decimal(row['Amount']),
@ -25,7 +26,7 @@ def standardize_amex_record(row):
}
def standardize_beancount_record(row):
def standardize_beancount_record(row) -> Dict: # type: ignore[no-untyped-def]
return {
'date': row.date,
'amount': row.number_cost_position,
@ -33,15 +34,15 @@ def standardize_beancount_record(row):
}
def format_record(record):
def format_record(record: Dict) -> str:
return f"{record['date'].isoformat()}: {record['amount']:>8} {record['payee'][:20]:<20}"
def sort_records(records):
def sort_records(records: List) -> List:
return sorted(records, key=lambda x: (x['date'], x['amount']))
def records_match(r1, r2):
def records_match(r1: Dict, r2: Dict) -> Tuple[bool, str]:
"""Do these records represent the same transaction?"""
date_matches = r1['date'] >= r2['date'] - datetime.timedelta(days=1) and r1['date'] <= r2['date'] + datetime.timedelta(days=1)
amount_matches = r1['amount'] == r2['amount']