def test_filter(): t = table.Table( ['units', 'currency'], [D, str], [[D('0.01'), 'USD'], [D('0.02'), 'CAD'], [D('0.03'), 'AUD']]) nt = t.filter(lambda row: row.currency == 'USD') assert nt.columns == t.columns assert nt.types == t.types assert nt.rows == list(map(nt.Row._make, [[D('0.01'), 'USD']]))
def test_select(): t = table.Table( ['units', 'currency'], [D, str], [[D('0.01'), 'USD'], [D('0.02'), 'CAD'], [D('0.03'), 'AUD']]) nt = t.select(['currency']) assert nt.columns == ['currency'] assert nt.types == [str] assert nt.rows == list(map(nt.Row, ['USD', 'CAD', 'AUD']))
def test_constructor(): t = table.Table( ['units', 'currency'], [D, str], [[D('0.01'), 'USD'], [D('0.02'), 'CAD'], [D('0.03'), 'AUD']]) assert isinstance(t, table.Table) assert isinstance(t.Row, type) assert issubclass(t.Row, tuple) assert isinstance(t.rows, list) assert isinstance(t.rows[0], t.Row)
def test_update(): t = table.Table( ['units', 'currency'], [D, str], [[D('0.01'), 'USD'], [D('0.02'), 'CAD'], [D('0.03'), 'AUD']]) nt = t.update('currency', lambda row: row.currency.lower()) assert nt.columns == ['units', 'currency'] assert nt.types == [D, str] assert nt.rows == list( map(nt.Row._make, [[D('0.01'), 'usd'], [D('0.02'), 'cad'], [D('0.03'), 'aud']]))
def parse(filename: str) -> table.Table: """Parse the NASDAQ ETFs list.""" tbl = table.read_csv(filename) outrows = [] for row in tbl: for regexp, issuer in [('Vanguard', 'Vanguard'), ('iShares', 'iShares'), ('PowerShares', 'PowerShares'), ('StateStreet', 'StateStreet')]: if re.search(regexp, row.name): outrows.append((row.symbol, issuer, row.name)) break return table.Table(['ticker', 'issuer', 'name'], [str, str, str], outrows)
def test_read_csv(): buf = io.StringIO( textwrap.dedent(""" units,currency 0.01,USD 0.02,CAD 0.03,AUD """)) t = table.read_csv(buf) e = table.Table(['units', 'currency'], [str, str], [[('0.01'), 'USD'], [('0.02'), 'CAD'], [('0.03'), 'AUD']]) assert t.columns == e.columns assert t.types == e.types assert t.rows == e.rows
def main(): logging.basicConfig(level=logging.INFO, format='%(levelname)-8s: %(message)s') parser = argparse.ArgumentParser(description=__doc__.strip()) parser.add_argument('filename', help='Beancount filename') parser.add_argument('--currency', action='store', default='USD') parser.add_argument('--quantize', action='store', default='0.') parser.add_argument('-o', '--output', action='store', help="Output file") args = parser.parse_args() Q = Decimal(args.quantize) # Read input. entries, errors, options_map = loader.load_file(args.filename) price_map = prices.build_price_map(entries) acctypes = options.get_account_types(options_map) # Compute start of period. today = datetime.date.today() date_min = today - datetime.timedelta(days=2 * 365) date_start = datetime.date(date_min.year, date_min.month, 1) month_start = (date_min.year, date_min.month) # Compute end of period. date_max = datetime.date(today.year, today.month, 1) # Accumulate expenses for the period. balances = collections.defaultdict( lambda: collections.defaultdict(inventory.Inventory)) all_months = set() for entry in data.filter_txns(entries): if entry.date < date_start or entry.date >= date_max: continue if any(tag.startswith(EXCLUDE_TAG_PREFIX) for tag in entry.tags): continue month = (entry.date.year, entry.date.month) all_months.add(month) for posting in entry.postings: if account_types.get_account_type( posting.account) != acctypes.expenses: continue if any(regexp.match(posting.account) for regexp in EXCLUDES): continue if posting.units.currency != args.currency: continue account = posting.account for regexp, target_account in MAPS: if regexp.match(account): account = target_account break balances[account][month].add_position(posting) # Reduce the final balances to numbers. sbalances = collections.defaultdict(dict) for account, months in sorted(balances.items()): for month, balance in sorted(months.items()): year, mth = month date = datetime.date(year, mth, 1) balance = balance.reduce(convert.get_value, price_map, date) balance = balance.reduce(convert.convert_position, args.currency, price_map, date) try: pos = balance.get_only_position() except AssertionError: print(balance) raise total = pos.units.number if pos and pos.units else None sbalances[account][month] = total # Pivot the table. header_months = sorted(all_months) header = ['account'] + ['{}-{:02d}'.format(*m) for m in header_months] rows = [] for account in sorted(sbalances.keys()): row = [account] for month in header_months: total = sbalances[account].get(month, None) row.append(str(total.quantize(Q)) if total else '') rows.append(row) # Write out the table. tbl = table.Table(header, [str] + [Decimal] * (len(header) - 1), rows) if args.output: with open(args.output, 'w') as outfile: table.write_csv(tbl, outfile) print(tbl)
def AssetsTable(rows): """A table describing the list of assets.""" return table.Table(['ticker', 'issuer', 'quantity'], [str, str, float], rows)