diff --git a/conservancy_beancount/reconcile/helper.py b/conservancy_beancount/reconcile/helper.py index 54733104253990139232e1bbbb45af47db4786ce..708008e698ce4c6a94649a425e9ba79e4c372114 100644 --- a/conservancy_beancount/reconcile/helper.py +++ b/conservancy_beancount/reconcile/helper.py @@ -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) diff --git a/conservancy_beancount/reconcile/prototype_amex_reconciler.py b/conservancy_beancount/reconcile/prototype_amex_reconciler.py index 1f680b1ba2b585851af6a9ceb921e07697fc88c1..982874de9476836add6a726565c4708131dec186 100644 --- a/conservancy_beancount/reconcile/prototype_amex_reconciler.py +++ b/conservancy_beancount/reconcile/prototype_amex_reconciler.py @@ -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']