Import files

roastery.importer.import_csv(*, csv_file: Path, config: Config, extract: roastery.importer.ExtractFn, beancount_file: Path = None, clean: roastery.importer.CleanFn = None, csv_args: dict[str, any] = None) None[source]

Import a CSV file and write a beancount file.

For each row of the CSV file:

The resulting Beancount file is created in the same directory as the CSV file, but with the extension changed to .beancount. So: statements/foo.csv -> statements/foo.beancount You can specify a different path with the beancount_file parameter.

The transaction is flagged with "!" if the digest of the entry occurs in the JSON file at roastery.config.Config.flags_path.

Parameters:
  • csv_file (Path) – Path of the CSV file to import.

  • config (Config) – Configuration to use.

  • csv_args (dict[str, any]) – Arguments to forward to csv.DictReader. This is used to parse weird CSV dialects. For example: dict(delimiter=";", quotechar="|").

  • extract (roastery.importer.ExtractFn) – How to extract an Entry from a row of CSV data. See ExtractFn.

  • clean (roastery.importer.CleanFn) – User-implemented cleaning function. See CleanFn.

  • beancount_file (Path) – Path of the beancount file to write to.

Return type:

None

roastery.importer.CleanFn

Receives a Entry and can mutate it as desired to classify / clean up the transaction.

For example:

def my_clean(entry: Entry) -> None:
    payee = entry.payee.lower()

    if payee == "irs":
        entry.account.cleaned = "Expenses:Tax"

    elif payee in {"chipotle", "mcdonalds", "five guys"}:
        entry.account.cleaned = "Expenses:FastFood"

alias of Callable[[Entry], None]

roastery.importer.ExtractFn

Turns a row of CSV data into an Entry.

alias of Callable[[dict], Entry]

class roastery.importer.Entry(digest: str, date: ~datetime.date, amount: ~beancount.core.amount.Amount, account: ~roastery.importer.Cleanable, asset_account: str, payee: ~roastery.importer.Cleanable, narration: ~roastery.importer.Cleanable, meta: ~roastery.importer.EntryMeta = <factory>, tags: set[str] = <factory>, links: set[str] = <factory>, flag: str = '*')[source]

Entry represents a row of transaction data from a financial institution.

Entries are constructed during the import process. For example by roastery.importer.import_csv().

Entry does not aim to abstract all of beancount’s features. For example, as_transaction always generates two postings. That makes this abstraction well-suited for transactions from bank accounts or credit cards. It is less applicable to model transactions involving investments or salary.

Parameters:
digest: str

Computed digest of this entry.

Some banks / data sources do not provide a reliable number / ID for a given entry (in e.g. a CSV file). Therefore, implementors of this class will have to provide a way to compute a digest.

This digest is used when storing the user’s manual edits. See also roastery.edit.

date: date

Booking date of the entry.

amount: Amount

Amount of the entry.

account: Cleanable

Account name to associate this transaction with. For example: Expenses:Pub.

asset_account: str

Asset account to associate this transaction with. For example: Assets:Checking

payee: Cleanable

Payee to add to this transaction. For example: Rob de Wit.

narration: Cleanable

Narration to add to this transaction. For example: Settle the tab at ‘t Neutje.

meta: EntryMeta

Dictionary of arbitrary data to attach to the transaction.

Users can instantiate Entry with a TypedDict to get type safety for any extra fields they might want to store.

tags: set[str]

Set of arbitrary strings to tag this transaction with.

See https://beancount.github.io/docs/beancount_language_syntax.html#tags

Set of arbitrary strings to link this transaction with.

See https://beancount.github.io/docs/beancount_language_syntax.html#tags

flag: str = '*'

One of the strings * or !.

*

denotes a ‘normal’ transaction.

!

means there is something special / that requires attention about this entry. ! transactions are highlighted in red in Fava.

classmethod from_row(*, digest: str, date: date, amount: Amount, asset_account: str, meta: EntryMeta | None = None, original_payee: str | None = None, original_narration: str | None = None) Entry[source]

Convenience constructor that can be called by integrators of a new source data type.

Parameters:
  • digest (str)

  • date (date)

  • amount (Amount)

  • asset_account (str)

  • meta (EntryMeta | None)

  • original_payee (str | None)

  • original_narration (str | None)

Return type:

Entry

property is_income: bool

Does this entry represent income?

property is_expense: bool

Does this entry represent an expense?

as_transaction() Transaction[source]

Turn this entry into a beancount Transaction.

Return type:

Transaction

apply_manual_edits(edits: dict[str, ManualEdits]) None[source]

Apply manual edits to this entry.

Parameters:

edits (dict[str, ManualEdits]) – Dictionary of manual edits, as deserialized from roastery.config.Config.manual_edits_path. The keys are the digests of the entires. The values are roastery.edit.ManualEdits containing the updated field values.

Return type:

None

class roastery.importer.EntryMeta

Type annotation for the metadata dictionary in Entry.

Import formats can define their own institution specific metadata type if they want users to be able to benefit from autocomplete, and things like that.

alias of TypeVar(‘EntryMeta’, bound=dict)

roastery.importer.Digest

Hash digest of an Entry, as a string.

class roastery.importer.Cleanable(original: str | None = None, cleaned: str | None = None, edited: str | None = None)[source]

A string field which can store three variants: the original value, the automatically cleaned value, and the value manually edited by the end user.

The value property will return the first non-None value among the edited, cleaned, and original values.

Examples:

>>> Cleanable(original="foo").value
'foo'
>>> Cleanable(original="foo", cleaned="bar").value
'bar'
>>> Cleanable(original="foo", cleaned="bar", edited="baz").value
'baz'
Parameters:
  • original (str | None)

  • cleaned (str | None)

  • edited (str | None)

original: str | None = None
cleaned: str | None = None
edited: str | None = None
property value: str | None

The first not-None value edited, cleaned, and original