Bulk changing all transactions in my scripts

142 views
Skip to first unread message

Holger Rapp

unread,
Oct 16, 2017, 3:24:09 PM10/16/17
to Beancount
Heyho,

Thanks for beancount, it is an awesome piece of technology!

My situation: My root file "root.beancount" includes sub files for all my individual accounts, i.e "my_bank.beancount". What I'd like to do is run over all Transactions in "my_bank.beancount", potentially changing the Accounts in the postings of each Transaction and write it back out into the file it was read from - keeping the order of the entries in the file.

I tried this:

entries, _, _ = beancount.loader.load_file("root.beancount") 
for e in entries:
    if not os.path.basename(e.meta['filename']) == "my_bank.beancount":
        continue
    if isinstance(e, data.Transaction):
        change_around_account(e)
    printer.print_entry(e)

This does not work as expected:

- it changes whitespace: while all my postings used to be indented by four spaces, after running this they are only indented by 2.
- I have several "balance" and "note" statements in the file which get reordered and empty lines inserted before and after. I understand that this is insignificant for beancount, but the ordering is meaningful to me.

It is not too hard to parse out the individual pieces that I am interested in the files and iterate over the items myself that way, but I wondered if there was a blessed way of doing what I want.

Thanks,
Holger




Martin Blais

unread,
Oct 16, 2017, 11:02:00 PM10/16/17
to Beancount
On Mon, Oct 16, 2017 at 3:24 PM, Holger Rapp <holge...@gmail.com> wrote:
Heyho,
 

Thanks for beancount, it is an awesome piece of technology!

Really glad it's doing things for you! :-)
 

My situation: My root file "root.beancount" includes sub files for all my individual accounts, i.e "my_bank.beancount". What I'd like to do is run over all Transactions in "my_bank.beancount", potentially changing the Accounts in the postings of each Transaction and write it back out into the file it was read from - keeping the order of the entries in the file.

I tried this:

entries, _, _ = beancount.loader.load_file("root.beancount") 
for e in entries:
    if not os.path.basename(e.meta['filename']) == "my_bank.beancount":
        continue
    if isinstance(e, data.Transaction):
        change_around_account(e)
    printer.print_entry(e)

This does not work as expected:

- it changes whitespace: while all my postings used to be indented by four spaces, after running this they are only indented by 2.
- I have several "balance" and "note" statements in the file which get reordered and empty lines inserted before and after. I understand that this is insignificant for beancount, but the ordering is meaningful to me.

Yep. This is all sensible. The input file and the parsed contents are fairly different. Input is incomplete, and parsing and the various interpolation and processing that Beancount does, as well as the plugins, generate a lot of other stuff. It also throws away the order (though the original location is secretely stored in the metadata, which you can access as ".meta" on all directives.)  It's not really intended to be able to rerender the original input from the parsed stream.
 

It is not too hard to parse out the individual pieces that I am interested in the files and iterate over the items myself that way, but I wondered if there was a blessed way of doing what I want.

In order to do that, I would suggest going LO-FI and using sed (or Python), and working off of the input text directly. Working off of the parsed input will just cause you headaches.

 


Zhuoyun Wei

unread,
Oct 17, 2017, 3:58:51 AM10/17/17
to bean...@googlegroups.com

2017-10-16 23:01:36 Martin Blais <bl...@furius.ca>:
>
> In order to do that, I would suggest going LO-FI and using sed (or Python), and working off of the input text directly.
> Working off of the parsed input will just cause you headaches.
>

I had a few similar use cases with Holger -- renaming a account while
preserving the indentation and whitespace, reformat the payee +
narration field, etc.

I found the fileinput module from Python stdlib extremely useful in
these cases:


with fileinput.input('ledger.bean', inplace=True) as f:
for line in f:
new_line = process_line(line)
print(new_line, end='')


With inplace=True parameter, it's like `sed -i`, but with all the
powerful batteries of Python.


--
Zhuoyun Wei
signature.asc

Holger Rapp

unread,
Oct 18, 2017, 2:59:53 PM10/18/17
to Beancount
Thanks guys, that helps a ton!
Reply all
Reply to author
Forward
0 new messages