Hi Martin,

I finally got it to work.  I put the example you gave in an 
importers/capone/__init__.py file (the one that creates a subclass of the 
csv.Importer) and then created the capone.import which imports the capone 
with the CONFIG global variable set to 
capone.Importer('Liabilities:US:CapOne').  When I just put your example in 
a capone.import it was missing the CONFIG global variable, hence the error. 
 

Starting to understand a little bit.  Thanks for the help.

BTW, I have maybe 10 years of Quicken data that I exported to qif and qfx 
files that I would like to pull into Beancount someday.  So I wouldn't mind 
helping to debug and/or write some of that code.

Jonathan

On Saturday, October 29, 2016 at 9:09:17 AM UTC-4, Martin Blais wrote:
>
> On Fri, Oct 28, 2016 at 8:13 PM, <[email protected] <javascript:>> wrote:
>
>> Hi Martin,
>>
>> responses to your response below.
>>
>> On Monday, October 24, 2016 at 10:07:53 PM UTC-4, Martin Blais wrote:
>>>
>>> On Sun, Oct 23, 2016 at 9:01 PM, <[email protected]> wrote:
>>>
>>>> Hi Martin,
>>>>
>>>> Just started using beancount to get away from Quicken.  Your reasons 
>>>> for writing it and the documentation was my reason to give it a try.  It 
>>>> should also help my Python skills.  You sort of  have an example in 
>>>> csv_test.py.  It helped me determine what to put in my .import file.  
>>>> Strangely, csv.py and csv_test.py were not in my install, ofx.py and 
>>>> others 
>>>> were.  I just copied from 
>>>> https://bitbucket.org/blais/beancount/src/b73da2b4f8e3182b1fb537a75385406c6d4fee90/src/python/beancount/ingest/importers/csv.py?at=booking&fileviewer=file-view-default
>>>>  
>>>> and moved to the directory where ofx.py was and it worked, sort of.
>>>>
>>>
>>> Strange. I just tested this now and the csv.py module does appear to 
>>> install.
>>> Can you try running something like this?
>>>
>>>   mkdir -p /tmp/b/lib/python3.5/site-packages
>>>
>>>   PYTHONPATH=/tmp/b/lib/python3.5/site-packages:$PYTHONPATH python3 
>>> setup.py install --prefix=/tmp/b
>>>
>>>   ls -l 
>>> /tmp/b/lib/python3.5/site-packages/beancount-2.0b12-py3.5-macosx-10.11-x86_64.egg/beancount/ingest/importers
>>> and share the output?
>>>
>>>
>> I tried the above, but it didn't work.  I broke up the second line, but 
>> still no go.  Output below:
>> Enter code here...JFSMini1:Beancount$ ll /tmp
>>
>> lrwxr-xr-x@ 1 root  wheel    11B Aug 12 22:07 /tmp@ -> private/tmp
>>
>> JFSMini1:Beancount$ mkdir -p /tmp/b/lib/python3.5/site-packages
>>
>> JFSMini1:Beancount$ 
>> PYTHONPATH=/tmp/b/lib/python3.5/site-packages:$PYTHONPATH python3 setup.py 
>> install --prefix=/tmp/b
>>
>> /Library/Frameworks/Python.framework/Versions/3.5/Resources/Python.app/Contents/MacOS/Python:
>>  
>> can't open file 'setup.py': [Errno 2] No such file or directory
>>
>
> You have to be in the beancount directory in order to run this command, 
> that's where setup.py lives.
>
>
>  
>
>> JFSMini1:Beancount$ echo $PYTHONPATH
>>
>>
>> JFSMini1:Beancount$ PYTHONPATH=/tmp/b/lib/python3.5/site-packages
>>
>> JFSMini1:Beancount$ echo $PYTHONPATH
>>
>> /tmp/b/lib/python3.5/site-packages
>>
>> JFSMini1:Beancount$ echo $PYTHONPATH python3 setup.py install 
>> --prefix=/tmp/b
>>
>> /tmp/b/lib/python3.5/site-packages python3 setup.py install 
>> --prefix=/tmp/b
>>
>> JFSMini1:Beancount$ ls /tmp/b/lib/python3.5/site-packages/beancount
>>
>> ls: /tmp/b/lib/python3.5/site-packages/beancount: No such file or 
>> directory
>>
>> JFSMini1:Beancount$ ls /tmp/b/lib/python3.5/site-packages/
>>
>> JFSMini1:Beancount$ 
>>
>> I forgot to state this was installed on my MAC Mini running OS X 10.11.6, 
>> El Capitan.  I then installed on my Macbook Pro running OS X 10.10.5, 
>> Yosemite.  csv.py and csv_test.py were there.  It must have been something 
>> with that install.
>>
>>  
>>
>>>
>>> I ran bean-identify, then the bean-extract as in the example, but I used 
>>>> a file, not a directory.  However, the only thing in the output file was 
>>>> the header and the path/filename.  No transactions made it into the file.  
>>>> Maybe the regexp input?  
>>>>
>>>
>>> Does bean-identify detect and associate your input file with the 
>>> importer you created below?
>>> (If it does, it would clearly print out a few meaningful lines about 
>>> that.)
>>> I suspect your regexp may not match the file.
>>>
>>> Since bean-identify does print out  
>>
>> **** /Users/jonathan/Documents/Beancount/20161018CapOne.csv
>> I think it does associate it, but I must be missing something.
>>
>
> This output just means it saw and file.
> If there's nothing below it (e.g., an importer name with a few more lines) 
> it did not associate an importer with this filename, in other words, it did 
> not detect the file contents as being for your importer.
> This is the problem.
>
>
>
> I sort of guessed on that, I couldn't exactly see what to put in there 
>>>> except the headings.  Here is the import file I created.
>>>>
>>>> #!/usr/bin/env python3
>>>> """Example import configuration."""
>>>>
>>>> # Insert our custom importers path here.
>>>> # (In practice you might just change your PYTHONPATH environment.)
>>>> import sys
>>>> from os import path
>>>> sys.path.insert(0, path.join(path.dirname(__file__)))
>>>>
>>>> from beancount.ingest import extract
>>>> from beancount.ingest.importers import ofx
>>>> from beancount.ingest.importers import csv
>>>>
>>>> Col = csv.Col
>>>>
>>>> # Setting this variable provides a list of importer instances.
>>>> CONFIG = [
>>>>     csv.Importer({Col.DATE: 'Posted Date',
>>>>                   Col.TXN_DATE: 'Transaction Date',
>>>>                   Col.NARRATION1: 'Card No.',
>>>>                   Col.NARRATION2: 'Description',
>>>>                   Col.NARRATION3: 'Catagory',
>>>>
>>>
>>> There's a typo here: Catagory -> Category
>>> (I don't think it's what caused the problem though, just pointing it 
>>> out.)
>>>
>>
>> No, that wasn't the problem, but thanks for finding that.
>>  
>>
>>>  
>>>
>>>>                   Col.AMOUNT_DEBIT: 'Debit',
>>>>                   Col.AMOUNT_CREDIT: 'Credit'},
>>>>                  'Liabilities:US:CapOne',
>>>>                  'USD',
>>>>                  ('Transaction Date,Posted Date,Card No.,Description,'
>>>>                      'Category,Debit,Credit'),
>>>>                  'CapOne')
>>>> ]
>>>>
>>>>
>>>> # Override the header on extracted text (if desired).
>>>> extract.HEADER = ';; -*- mode: org; mode: beancount; coding: utf-8; 
>>>> -*-\n'
>>>>
>>>>
>>>> Am I correct in thinking I would need a separate import file for each 
>>>> different type of csv?
>>>>
>>>
>>> I'm not sure what you mean by "a separate import file."
>>>
>>
>> I think we are using different terminology, and I missed the 'dot' in 
>> front of the import.  I call the example.import the import file, I think 
>> you are calling them the config file. 
>>
>
> No, you can put all your importers in the same Python file if you like.
> The main reason to put them in their own files is that if you have a lot 
> of them, that would make a large file. But you can. It's really just some 
> Python code, nothing really special other than the tools evaluate it and 
> grab the special CONFIG attribute, that's it.
>
>
>
> - The source code for all the importers you create like this could very 
>>> well be in a one Python file, no problem with that.
>>>
>>> - You will need to instantiate a separate importer for each different 
>>> type of download, e.g. one for each source.
>>>
>>> BTW, here's an example configuration that ought to work on a US 
>>> CapitalOne CSV download:
>>>
>>> from beancount.ingest import regression
>>> from beancount.ingest.importers import csv
>>>
>>> class Importer(csv.Importer):
>>>
>>>     config = {csv.Col.DATE: 'Posted Date',
>>>               csv.Col.TXN_DATE: 'Transaction Date',
>>>               csv.Col.AMOUNT_DEBIT: 'Debit',
>>>               csv.Col.AMOUNT_CREDIT: 'Credit',
>>>               csv.Col.PAYEE: 'Description',
>>>               csv.Col.NARRATION: 'Category'}
>>>
>>>     def __init__(self, account):
>>>         csv.Importer.__init__(
>>>             self, self.config,
>>>             account, 'USD',
>>>             ('Stage, Transaction Date, Posted Date, Card No., 
>>> Description, Category, '
>>>              'Debit, Credit'),
>>>             'capitalone')
>>>
>>>     def get_description(self, row):
>>>         payee, narration = super().get_description()
>>>         narration = '{} ({})'.format(narration, row.category)
>>>         return payee, narration
>>>
>>> You can place this in another .py file and import that from your 
>>> importer configuration source.
>>>
>>> I put the above code in a file called capitalone.import, and incurred 
>> the following error:
>>
>> JFSMini1:Beancount$ bean-identify capitalone.import 20161018CapOne.csv 
>>
>> Traceback (most recent call last):
>>
>>   File "/usr/local/bin/bean-identify", line 2, in <module>
>>
>>     from beancount.ingest.identify import main; main()
>>
>>   File 
>> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/beancount/ingest/identify.py"
>> , line 92, in main
>>
>>     _, config, downloads_directories = scripts_utils.parse_arguments(
>> parser)
>>
>>   File 
>> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/beancount/ingest/scripts_utils.py"
>> , line 56, in parse_arguments
>>
>>     config = mod['CONFIG']
>>
>> KeyError: 'CONFIG'
>>
>> Should I have put the code in a capitaloneimport.py and then made a 
>> separate capone.import?  I have been looking at your code and reading some 
>> docs, but your Python coding is a lot more sophisticated than I am used 
>> to.  It is a good learning experience though.
>>
>
> It doesn't matter how you structure the files.
> All that matters is that the .import Python file provide a CONFIG global 
> variable which consists in a list of objects which implement Importer.
>
>
>  
>
>>  
>>
>>>
>>>  
>>>
>>>>
>>>> Thanks
>>>>
>>>> Jonathan
>>>>
>>>> On Friday, October 21, 2016 at 11:20:55 PM UTC-4, Martin Blais wrote:
>>>>>
>>>>> On Wed, Oct 19, 2016 at 4:19 AM, Saša Janiška <[email protected]> 
>>>>> wrote:
>>>>>
>>>>>> Hello,
>>>>>>
>>>>>> afaik, (h)ledger have some general CSV importer where one can define
>>>>>> some mapping rules for the desired CSV format and then import?
>>>>>>
>>>>>> CSV is also the only format I can use since the bank just provides 
>>>>>> Excel
>>>>>> file which can be converted to CSV.
>>>>>>
>>>>>
>>>>> Beancount offers a framework to define your own custom importers, 
>>>>> documented here:
>>>>> http://furius.ca/beancount/doc/ingest
>>>>>
>>>>> Unfortunately, you have to write some code to set that up.
>>>>>
>>>>> On the other hand, it also comes with a good example CSV importer 
>>>>> which is functional:
>>>>>
>>>>> https://bitbucket.org/blais/beancount/src/b73da2b4f8e3182b1fb537a75385406c6d4fee90/src/python/beancount/ingest/importers/csv.py?at=booking&fileviewer=file-view-default
>>>>>
>>>>> You just need to instantiate it and provide it with a dict that tells 
>>>>> it how to interpret each column of your CSV file.
>>>>> (I should provide some example on how to do that, in the meantime 
>>>>> you'd have to read the source code.)
>>>>>
>>>>> HTH,
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> Sincerely,
>>>>>> Gour
>>>>>>
>>>>>> --
>>>>>> While contemplating the objects of the senses, a person
>>>>>> develops attachment for them, and from such attachment lust
>>>>>> develops, and from lust anger arises.
>>>>>>
>>>>>> --
>>>>>> You received this message because you are subscribed to the Google 
>>>>>> Groups "Beancount" group.
>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>> send an email to [email protected].
>>>>>> To post to this group, send email to [email protected].
>>>>>> To view this discussion on the web visit 
>>>>>> https://groups.google.com/d/msgid/beancount/874m48rbsv.fsf%40atmarama.com
>>>>>> .
>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>
>>>>>
>>>>> -- 
>>>> You received this message because you are subscribed to the Google 
>>>> Groups "Beancount" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>> an email to [email protected].
>>>> To post to this group, send email to [email protected].
>>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/beancount/89102a4b-26aa-4c5e-82c6-0400d6268c38%40googlegroups.com
>>>>  
>>>> <https://groups.google.com/d/msgid/beancount/89102a4b-26aa-4c5e-82c6-0400d6268c38%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>>
>> On Monday, October 24, 2016 at 10:07:53 PM UTC-4, Martin Blais wrote:
>>>
>>> On Sun, Oct 23, 2016 at 9:01 PM, <[email protected]> wrote:
>>>
>>>> Hi Martin,
>>>>
>>>> Just started using beancount to get away from Quicken.  Your reasons 
>>>> for writing it and the documentation was my reason to give it a try.  It 
>>>> should also help my Python skills.  You sort of  have an example in 
>>>> csv_test.py.  It helped me determine what to put in my .import file.  
>>>> Strangely, csv.py and csv_test.py were not in my install, ofx.py and 
>>>> others 
>>>> were.  I just copied from 
>>>> https://bitbucket.org/blais/beancount/src/b73da2b4f8e3182b1fb537a75385406c6d4fee90/src/python/beancount/ingest/importers/csv.py?at=booking&fileviewer=file-view-default
>>>>  
>>>> and moved to the directory where ofx.py was and it worked, sort of.
>>>>
>>>
>>> Strange. I just tested this now and the csv.py module does appear to 
>>> install.
>>> Can you try running something like this?
>>>
>>>   mkdir -p /tmp/b/lib/python3.5/site-packages
>>>
>>>   PYTHONPATH=/tmp/b/lib/python3.5/site-packages:$PYTHONPATH python3 
>>> setup.py install --prefix=/tmp/b
>>>
>>>   ls -l 
>>> /tmp/b/lib/python3.5/site-packages/beancount-2.0b12-py3.5-macosx-10.11-x86_64.egg/beancount/ingest/importers
>>> and share the output?
>>>
>>>
>>> I ran bean-identify, then the bean-extract as in the example, but I used 
>>>> a file, not a directory.  However, the only thing in the output file was 
>>>> the header and the path/filename.  No transactions made it into the file.  
>>>> Maybe the regexp input?  
>>>>
>>>
>>> Does bean-identify detect and associate your input file with the 
>>> importer you created below?
>>> (If it does, it would clearly print out a few meaningful lines about 
>>> that.)
>>> I suspect your regexp may not match the file.
>>>
>>>  
>>>
>>>> I sort of guessed on that, I couldn't exactly see what to put in there 
>>>> except the headings.  Here is the import file I created.
>>>>
>>>> #!/usr/bin/env python3
>>>> """Example import configuration."""
>>>>
>>>> # Insert our custom importers path here.
>>>> # (In practice you might just change your PYTHONPATH environment.)
>>>> import sys
>>>> from os import path
>>>> sys.path.insert(0, path.join(path.dirname(__file__)))
>>>>
>>>> from beancount.ingest import extract
>>>> from beancount.ingest.importers import ofx
>>>> from beancount.ingest.importers import csv
>>>>
>>>> Col = csv.Col
>>>>
>>>> # Setting this variable provides a list of importer instances.
>>>> CONFIG = [
>>>>     csv.Importer({Col.DATE: 'Posted Date',
>>>>                   Col.TXN_DATE: 'Transaction Date',
>>>>                   Col.NARRATION1: 'Card No.',
>>>>                   Col.NARRATION2: 'Description',
>>>>                   Col.NARRATION3: 'Catagory',
>>>>
>>>
>>> There's a typo here: Catagory -> Category
>>> (I don't think it's what caused the problem though, just pointing it 
>>> out.)
>>>  
>>>
>>>>                   Col.AMOUNT_DEBIT: 'Debit',
>>>>                   Col.AMOUNT_CREDIT: 'Credit'},
>>>>                  'Liabilities:US:CapOne',
>>>>                  'USD',
>>>>                  ('Transaction Date,Posted Date,Card No.,Description,'
>>>>                      'Category,Debit,Credit'),
>>>>                  'CapOne')
>>>> ]
>>>>
>>>>
>>>> # Override the header on extracted text (if desired).
>>>> extract.HEADER = ';; -*- mode: org; mode: beancount; coding: utf-8; 
>>>> -*-\n'
>>>>
>>>>
>>>> Am I correct in thinking I would need a separate import file for each 
>>>> different type of csv?
>>>>
>>>
>>> I'm not sure what you mean by "a separate import file."
>>>
>>> - The source code for all the importers you create like this could very 
>>> well be in a one Python file, no problem with that.
>>>
>>> - You will need to instantiate a separate importer for each different 
>>> type of download, e.g. one for each source.
>>>
>>> BTW, here's an example configuration that ought to work on a US 
>>> CapitalOne CSV download:
>>>
>>> from beancount.ingest import regression
>>> from beancount.ingest.importers import csv
>>>
>>> class Importer(csv.Importer):
>>>
>>>     config = {csv.Col.DATE: 'Posted Date',
>>>               csv.Col.TXN_DATE: 'Transaction Date',
>>>               csv.Col.AMOUNT_DEBIT: 'Debit',
>>>               csv.Col.AMOUNT_CREDIT: 'Credit',
>>>               csv.Col.PAYEE: 'Description',
>>>               csv.Col.NARRATION: 'Category'}
>>>
>>>     def __init__(self, account):
>>>         csv.Importer.__init__(
>>>             self, self.config,
>>>             account, 'USD',
>>>             ('Stage, Transaction Date, Posted Date, Card No., 
>>> Description, Category, '
>>>              'Debit, Credit'),
>>>             'capitalone')
>>>
>>>     def get_description(self, row):
>>>         payee, narration = super().get_description()
>>>         narration = '{} ({})'.format(narration, row.category)
>>>         return payee, narration
>>>
>>>
>>> You can place this in another .py file and import that from your 
>>> importer configuration source.
>>>
>>>
>>>  
>>>
>>>>
>>>> Thanks
>>>>
>>>> Jonathan
>>>>
>>>> On Friday, October 21, 2016 at 11:20:55 PM UTC-4, Martin Blais wrote:
>>>>>
>>>>> On Wed, Oct 19, 2016 at 4:19 AM, Saša Janiška <[email protected]> 
>>>>> wrote:
>>>>>
>>>>>> Hello,
>>>>>>
>>>>>> afaik, (h)ledger have some general CSV importer where one can define
>>>>>> some mapping rules for the desired CSV format and then import?
>>>>>>
>>>>>> CSV is also the only format I can use since the bank just provides 
>>>>>> Excel
>>>>>> file which can be converted to CSV.
>>>>>>
>>>>>
>>>>> Beancount offers a framework to define your own custom importers, 
>>>>> documented here:
>>>>> http://furius.ca/beancount/doc/ingest
>>>>>
>>>>> Unfortunately, you have to write some code to set that up.
>>>>>
>>>>> On the other hand, it also comes with a good example CSV importer 
>>>>> which is functional:
>>>>>
>>>>> https://bitbucket.org/blais/beancount/src/b73da2b4f8e3182b1fb537a75385406c6d4fee90/src/python/beancount/ingest/importers/csv.py?at=booking&fileviewer=file-view-default
>>>>>
>>>>> You just need to instantiate it and provide it with a dict that tells 
>>>>> it how to interpret each column of your CSV file.
>>>>> (I should provide some example on how to do that, in the meantime 
>>>>> you'd have to read the source code.)
>>>>>
>>>>> HTH,
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> Sincerely,
>>>>>> Gour
>>>>>>
>>>>>> --
>>>>>> While contemplating the objects of the senses, a person
>>>>>> develops attachment for them, and from such attachment lust
>>>>>> develops, and from lust anger arises.
>>>>>>
>>>>>> --
>>>>>> You received this message because you are subscribed to the Google 
>>>>>> Groups "Beancount" group.
>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>> send an email to [email protected].
>>>>>> To post to this group, send email to [email protected].
>>>>>> To view this discussion on the web visit 
>>>>>> https://groups.google.com/d/msgid/beancount/874m48rbsv.fsf%40atmarama.com
>>>>>> .
>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>
>>>>>
>>>>> -- 
>>>> You received this message because you are subscribed to the Google 
>>>> Groups "Beancount" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>> an email to [email protected].
>>>> To post to this group, send email to [email protected].
>>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/beancount/89102a4b-26aa-4c5e-82c6-0400d6268c38%40googlegroups.com
>>>>  
>>>> <https://groups.google.com/d/msgid/beancount/89102a4b-26aa-4c5e-82c6-0400d6268c38%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Beancount" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected] <javascript:>.
>> To post to this group, send email to [email protected] 
>> <javascript:>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/beancount/3f76bc72-b536-4d90-8736-fd8a82e7cb6d%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/beancount/3f76bc72-b536-4d90-8736-fd8a82e7cb6d%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/beancount/656893d3-711b-4bee-8b9e-61e3c69dc9bd%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to