From 61f7613b8d7a88b31b37ad1c82063a5a5a46a29e Mon Sep 17 00:00:00 2001 From: Christoph Holtermann Date: Sun, 2 Sep 2018 16:25:04 +0200 Subject: [PATCH 1/6] fix for python3 --- bindings/python/example_scripts/gncinvoice_jinja.py | 10 +++++----- bindings/python/example_scripts/str_methods.py | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/bindings/python/example_scripts/gncinvoice_jinja.py b/bindings/python/example_scripts/gncinvoice_jinja.py index 73aa805b82..c6d59c4dfa 100644 --- a/bindings/python/example_scripts/gncinvoice_jinja.py +++ b/bindings/python/example_scripts/gncinvoice_jinja.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- ##@file @@ -63,7 +63,7 @@ def main(argv=None): try: opts, args = getopt.getopt(argv[1:], "fhlI:t:o:", ["help"]) - except getopt.error, msg: + except getopt.error as msg: raise Usage(msg) for opt in opts: @@ -105,12 +105,12 @@ def main(argv=None): filename_output = filename_template + ".out" print("no output filename given, will be:", filename_output) - except Usage, err: + except Usage as err: if err.msg == "Help:": retcode=0 else: - print(>>sys.stderr, "Error:",err.msg) - print(>>sys.stderr, "for help use --help") + print("Error:", err.msg, file=sys.stderr) + print("for help use --help", file=sys.stderr) retcode=2 print() diff --git a/bindings/python/example_scripts/str_methods.py b/bindings/python/example_scripts/str_methods.py index d1f2f52b8d..64c81445ce 100644 --- a/bindings/python/example_scripts/str_methods.py +++ b/bindings/python/example_scripts/str_methods.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 ## @file # @brief Add __str__ and __unicode__ methods to financial objects so that @code print object @endcode leads to human readable results """ @package str_methods.py -- Add __str__ and __unicode__ methods to financial objects @@ -30,7 +30,8 @@ # * It seems useful to have an object for each modification. That is because there is some Initialisation to be done. # -import gnucash, function_class +import gnucash +from gnucash import function_class # Default values for encoding of strings in GnuCashs Database DEFAULT_ENCODING = "UTF-8" From 002595f4ccf6912235f5d41117b4796dae7f223a Mon Sep 17 00:00:00 2001 From: Christoph Holtermann Date: Thu, 6 Sep 2018 13:15:20 +0200 Subject: [PATCH 2/6] add options iOP --- .../example_scripts/gncinvoice_jinja.py | 56 +++++++++++++++---- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/bindings/python/example_scripts/gncinvoice_jinja.py b/bindings/python/example_scripts/gncinvoice_jinja.py index c6d59c4dfa..6066d5812c 100644 --- a/bindings/python/example_scripts/gncinvoice_jinja.py +++ b/bindings/python/example_scripts/gncinvoice_jinja.py @@ -32,6 +32,7 @@ try: import locale + import os import sys import getopt import gnucash @@ -60,9 +61,12 @@ def main(argv=None): list_invoices = False invoice_number = None invoice_id = None + filename_from_invoice = False + output_path = None + with_ipshell = False try: - opts, args = getopt.getopt(argv[1:], "fhlI:t:o:", ["help"]) + opts, args = getopt.getopt(argv[1:], "fhliI:t:o:OP:", ["help"]) except getopt.error as msg: raise Usage(msg) @@ -74,16 +78,27 @@ def main(argv=None): raise Usage("Help:") if opt[0] in ["-I"]: invoice_id = opt[1] - print("using invoice ID '" + str(invoice_id) + "'.") + print ("using invoice ID '" + str(invoice_id) + "'.") + if opt[0] in ["-i"]: + print ("Using ipshell") + with_ipshell = True if opt[0] in ["-o"]: filename_output = opt[1] print("using output file", filename_output) + if opt[0] in ["-O"]: + if filename_output: + print ("given output filename will be overwritten,") + print ("creating output filename from Invoice data.") + filename_from_invoice = True if opt[0] in ["-t"]: filename_template = opt[1] print("using template file", filename_template) if opt[0] in ["-l"]: list_invoices = True print("listing invoices") + if opt[0] in ["-P"]: + output_path = opt[1] + print ("output path is", output_path + ".") # Check for correct input if len(args)>1: @@ -100,7 +115,7 @@ def main(argv=None): raise Usage("No template given !") # Check for output file - if not filename_output: + if not (filename_output or filename_from_invoice): if filename_template: filename_output = filename_template + ".out" print("no output filename given, will be:", filename_output) @@ -128,6 +143,9 @@ def main(argv=None): print("-I ID use invoice ID") print("-t filename use filename as template file") print("-o filename use filename as output file") + print( "-o filename use filename as output file" ) + print( "-O create output filename by date, owner and invoice number" ) + print( "-P path path for output file. Overwrites path in -o option" ) return retcode @@ -166,17 +184,35 @@ def main(argv=None): print("Using the following invoice:") print(invoice) - loader = jinja2.FileSystemLoader('.') + + path_template = os.path.dirname(filename_template) + filename_template_basename = os.path.basename(filename_template) + + loader = jinja2.FileSystemLoader(path_template) env = jinja2.Environment(loader=loader) - template = env.get_template(filename_template) + template = env.get_template(filename_template_basename) - #import IPython - #IPython.embed() - output = template.render(invoice=invoice, locale=locale) + #company = gnucash_business.Company(book.instance) - print("Writing output", filename_output, ".") + output = template.render(invoice=invoice, locale=locale) #, company=company) + + if filename_from_invoice: + filename_date = str(invoice.GetDatePosted()) # something like 2014-11-01 + filename_owner_name = str(invoice.GetOwner().GetName()) + filename_invoice_id = str(invoice.GetID()) + filename_output = filename_date + "_" + filename_owner_name + "_" + filename_invoice_id + ".tex" + + if output_path: + filename_output = os.path.join(output_path, os.path.basename(filename_output)) + + print ("Writing output", filename_output, ".") with open(filename_output, 'w') as f: - f.write(output.encode('utf-8')) + f.write(output) + + if with_ipshell: + import IPython + IPython.embed() + if __name__ == "__main__": sys.exit(main()) From 1184e92687e704d67373e4ce6c55165577faa132 Mon Sep 17 00:00:00 2001 From: Christoph Holtermann Date: Thu, 6 Sep 2018 13:17:31 +0200 Subject: [PATCH 3/6] 2to3 --- .../python/example_scripts/str_methods.py | 129 ++++++------------ 1 file changed, 43 insertions(+), 86 deletions(-) diff --git a/bindings/python/example_scripts/str_methods.py b/bindings/python/example_scripts/str_methods.py index 64c81445ce..dfbec36c66 100644 --- a/bindings/python/example_scripts/str_methods.py +++ b/bindings/python/example_scripts/str_methods.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 ## @file -# @brief Add __str__ and __unicode__ methods to financial objects so that @code print object @endcode leads to human readable results -""" @package str_methods.py -- Add __str__ and __unicode__ methods to financial objects +# @brief Add __str__ methods to financial objects so that @code print object @endcode leads to human readable results +""" @package str_methods.py -- Add __str__ methods to financial objects - Import this module and str(Object) and unicode(Object) where Object is Transaction, Split,Invoice - or Entry leads to human readable results. That is handy when using @code print object @endcode + Import this module and str(Object) where Object is Transaction, Split, Invoice or Entry leads to + human readable results. That is handy when using @code print object @endcode I chose to put these functions/methods in a separate file to develop them like this and maybe if they prove to be useful they can be put in gnucash_core.py. @@ -150,29 +150,29 @@ class ClassWithCutting__format__(): value=self.value # Replace Tabs and linebreaks - import types - if type(value) in [types.StringType, types.UnicodeType]: - value=value.replace("\t","|") - value=value.replace("\n","|") + #import types + if isinstance(value, str): + value = value.replace("\t","|") + value = value.replace("\n","|") # Do regular formatting of object - value=value.__format__(fmt) + value = value.__format__(fmt) # Cut resulting value if longer than specified by width - width=get_width(fmt) + width = get_width(fmt) if width: - value=cut(value, width, "...") + value = cut(value, width, "...") return value def all_as_classwithcutting__format__(*args): """Converts every argument to instance of ClassWithCutting__format__""" - import types + #import types l=[] for a in args: - if type(a) in [types.StringType, types.UnicodeType]: - a=a.decode("UTF-8") + #if type(a) in [types.StringType, types.UnicodeType]: + # a=a.decode("UTF-8") l.append(ClassWithCutting__format__(a)) return l @@ -180,15 +180,15 @@ def all_as_classwithcutting__format__(*args): def all_as_classwithcutting__format__keys(encoding=None, error=None, **keys): """Converts every argument to instance of ClassWithCutting__format__""" - import types + #import types d={} if encoding==None: encoding=DEFAULT_ENCODING if error==None: error=DEFAULT_ERROR for a in keys: - if type(keys[a]) in [types.StringType, types.UnicodeType]: - keys[a]=keys[a].decode(encoding,error) + #if isinstance(keys[a], str): + # keys[a]=keys[a].decode(encoding,error) d[a]=ClassWithCutting__format__(keys[a]) return d @@ -196,8 +196,8 @@ def all_as_classwithcutting__format__keys(encoding=None, error=None, **keys): # Split -def __split__unicode__(self, encoding=None, error=None): - """__unicode__(self, encoding=None, error=None) -> object +def __split__str__(self, encoding=None, error=None): + """__str__(self, encoding=None, error=None) -> object Serialize the Split object and return as a new Unicode object. @@ -229,40 +229,31 @@ def __split__unicode__(self, encoding=None, error=None): "memo":self.GetMemo(), "lot":lot_str} - fmt_str= (u"Account: {account:20} "+ - u"Value: {value:>10} "+ - u"Memo: {memo:30} ") + fmt_str= ("Account: {account:20} "+ + "Value: {value:>10} "+ + "Memo: {memo:30} ") if self.optionflags & self.OPTIONFLAGS_BY_NAME["PRINT_TRANSACTION"]: fmt_t_dict={ "transaction_time":time.ctime(transaction.GetDate()), "transaction2":transaction.GetDescription()} fmt_t_str=( - u"Transaction: {transaction_time:30} "+ - u"- {transaction2:30} "+ - u"Lot: {lot:10}") + "Transaction: {transaction_time:30} "+ + "- {transaction2:30} "+ + "Lot: {lot:10}") fmt_dict.update(fmt_t_dict) fmt_str += fmt_t_str return fmt_str.format(**all_as_classwithcutting__format__keys(encoding,error,**fmt_dict)) -def __split__str__(self): - """Returns a bytestring representation of self.__unicode__""" - - from gnucash import Split - #self=Split(instance=self) - - return unicode(self).encode('utf-8') - # This could be something like an __init__. Maybe we could call it virus because it infects the Split object which # thereafter mutates to have better capabilities. infect(gnucash.Split,__split__str__,"__str__") -infect(gnucash.Split,__split__unicode__,"__unicode__") gnucash.Split.register_optionflag("PRINT_TRANSACTION") gnucash.Split.setflag("PRINT_TRANSACTION",True) -def __transaction__unicode__(self): - """__unicode__ method for Transaction class""" +def __transaction__str__(self): + """__str__ method for Transaction class""" from gnucash import Transaction import time self=Transaction(instance=self) @@ -271,7 +262,7 @@ def __transaction__unicode__(self): 'Description:',self.GetDescription(), 'Notes:',self.GetNotes()) - transaction_str = u"{0:6}{1:25} {2:14}{3:40} {4:7}{5:40}".format( + transaction_str = "{0:6}{1:25} {2:14}{3:40} {4:7}{5:40}".format( *all_as_classwithcutting__format__(*fmt_tuple)) transaction_str += "\n" @@ -282,29 +273,18 @@ def __transaction__unicode__(self): transaction_flag = split.getflag("PRINT_TRANSACTION") split.setflag("PRINT_TRANSACTION",False) - splits_str += u"[{0:>2}] ".format(unicode(n)) - splits_str += unicode(split) + splits_str += "[{0:>2}] ".format(str(n)) + splits_str += str(split) splits_str += "\n" split.setflag("PRINT_TRANSACTION",transaction_flag) return transaction_str + splits_str -def __transaction__str__(self): - """__str__ method for Transaction class""" - from gnucash import Transaction - - self=Transaction(instance=self) - return unicode(self).encode('utf-8') - -# These lines add transaction_str as method __str__ to Transaction object gnucash.gnucash_core_c.__transaction__str__=__transaction__str__ gnucash.Transaction.add_method("__transaction__str__","__str__") -gnucash.gnucash_core_c.__transaction__unicode__=__transaction__unicode__ -gnucash.Transaction.add_method("__transaction__unicode__","__unicode__") - -def __invoice__unicode__(self): - """__unicode__ method for Invoice""" +def __invoice__str__(self): + """__str__ method for Invoice""" from gnucash.gnucash_business import Invoice self=Invoice(instance=self) @@ -324,37 +304,27 @@ def __invoice__unicode__(self): "total_value":str(self.GetTotal()), "currency_mnemonic":self.GetCurrency().get_mnemonic()} - ret_invoice= (u"{id_name:4}{id_value:10} {notes_name:7}{notes_value:20} {active_name:8}{active_value:7} {owner_name:12}{owner_value:20}"+ - u"{total_name:8}{total_value:10}{currency_mnemonic:3}").\ + ret_invoice= ("{id_name:4}{id_value:10} {notes_name:7}{notes_value:20} {active_name:8}{active_value:7} {owner_name:12}{owner_value:20}"+ + "{total_name:8}{total_value:10}{currency_mnemonic:3}").\ format(**all_as_classwithcutting__format__keys(**fmt_dict)) - ret_entries=u"" + ret_entries="" entry_list = self.GetEntries() for entry in entry_list: # Type of entry has to be checked if not(type(entry)==Entry): entry=Entry(instance=entry) - ret_entries += " "+unicode(entry)+"\n" + ret_entries += " "+str(entry)+"\n" return ret_invoice+"\n"+ret_entries -def __invoice__str__(self): - """__str__ method for invoice class""" - - from gnucash.gnucash_business import Invoice - self=Invoice(instance=self) - - return unicode(self).encode('utf-8') from gnucash.gnucash_business import Invoice gnucash.gnucash_core_c.__invoice__str__=__invoice__str__ gnucash.gnucash_business.Invoice.add_method("__invoice__str__","__str__") -gnucash.gnucash_core_c.__invoice__unicode__=__invoice__unicode__ -gnucash.gnucash_business.Invoice.add_method("__invoice__unicode__","__unicode__") - -def __entry__unicode__(self): - """__unicode__ method for Entry""" +def __entry__str__(self): + """__str__ method for Entry""" from gnucash.gnucash_business import Entry self=Entry(instance=self) @@ -362,34 +332,21 @@ def __entry__unicode__(self): # This dict and the return statement can be changed according to individual needs fmt_dict={ "date_name":"Date:", - "date_value":unicode(self.GetDate()), + "date_value":str(self.GetDate()), "description_name":"Description:", "description_value":self.GetDescription(), "notes_name":"Notes:", "notes_value":self.GetNotes(), "quant_name":"Quantity:", - "quant_value":unicode(self.GetQuantity()), + "quant_value":str(self.GetQuantity()), "invprice_name":"InvPrice:", - "invprice_value":unicode(self.GetInvPrice())} + "invprice_value":str(self.GetInvPrice())} - return (u"{date_name:6}{date_value:15} {description_name:13}{description_value:20} {notes_name:7}{notes_value:20}"+ - u"{quant_name:12}{quant_value:7} {invprice_name:10}{invprice_value:7}").\ + return ("{date_name:6}{date_value:15} {description_name:13}{description_value:20} {notes_name:7}{notes_value:20}"+ + "{quant_name:12}{quant_value:7} {invprice_name:10}{invprice_value:7}").\ format(**all_as_classwithcutting__format__keys(**fmt_dict)) -def __entry__str__(self): - """__str__ method for Entry class""" - - from gnucash.gnucash_business import Entry - self=Entry(instance=self) - - return unicode(self).encode('utf-8') - from gnucash.gnucash_business import Entry gnucash.gnucash_core_c.__entry__str__=__entry__str__ gnucash.gnucash_business.Entry.add_method("__entry__str__","__str__") - -gnucash.gnucash_core_c.__entry__unicode__=__entry__unicode__ -gnucash.gnucash_business.Entry.add_method("__entry__unicode__","__unicode__") - - From 247d04a5441d8a102555c8bd69c154f9060dd06e Mon Sep 17 00:00:00 2001 From: Christoph Holtermann Date: Fri, 21 Sep 2018 08:49:48 +0200 Subject: [PATCH 4/6] make executable, remove double -o --- bindings/python/example_scripts/gncinvoice_jinja.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) mode change 100644 => 100755 bindings/python/example_scripts/gncinvoice_jinja.py diff --git a/bindings/python/example_scripts/gncinvoice_jinja.py b/bindings/python/example_scripts/gncinvoice_jinja.py old mode 100644 new mode 100755 index 6066d5812c..e199eb262e --- a/bindings/python/example_scripts/gncinvoice_jinja.py +++ b/bindings/python/example_scripts/gncinvoice_jinja.py @@ -5,7 +5,7 @@ # @brief exports an invoice from gnucash using a template file, see \ref py_invoice_export # @ingroup python_bindings_examples # @author Christoph Holtermann (c.holtermann (at) gmx.de) -# @date 2014-11 +# @date 2014-2018 # # @details # Input is a template file that will be filled with information from @@ -143,9 +143,8 @@ def main(argv=None): print("-I ID use invoice ID") print("-t filename use filename as template file") print("-o filename use filename as output file") - print( "-o filename use filename as output file" ) - print( "-O create output filename by date, owner and invoice number" ) - print( "-P path path for output file. Overwrites path in -o option" ) + print("-O create output filename by date, owner and invoice number") + print("-P path path for output file. Overwrites path in -o option") return retcode From 206ed63233ede3a7bd7e00961d85f78bd7aa4b5d Mon Sep 17 00:00:00 2001 From: Christoph Holtermann Date: Fri, 21 Sep 2018 08:53:16 +0200 Subject: [PATCH 5/6] typo --- bindings/python/example_scripts/gncinvoice_jinja.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/example_scripts/gncinvoice_jinja.py b/bindings/python/example_scripts/gncinvoice_jinja.py index e199eb262e..bcfd3441ea 100755 --- a/bindings/python/example_scripts/gncinvoice_jinja.py +++ b/bindings/python/example_scripts/gncinvoice_jinja.py @@ -9,8 +9,8 @@ # # @details # Input is a template file that will be filled with information from -# gnucash Invoices. Jinja2 templating engine ist used. Templates can -# be Latex, Html or anything. +# gnucash Invoices. Jinja2 templating engine is being used for this. +# Templates can be Latex, Html or anything. # # Example templates for german invoices: # - Invoice.tex.tmpl From 298797a9bebb1140a61dee87b89d2ff962b78f58 Mon Sep 17 00:00:00 2001 From: c-holtermann Date: Thu, 4 Apr 2019 11:03:52 +0200 Subject: [PATCH 6/6] fix due to different invoice date handling --- bindings/python/example_scripts/gncinvoice_jinja.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/example_scripts/gncinvoice_jinja.py b/bindings/python/example_scripts/gncinvoice_jinja.py index bcfd3441ea..f44f308ab2 100755 --- a/bindings/python/example_scripts/gncinvoice_jinja.py +++ b/bindings/python/example_scripts/gncinvoice_jinja.py @@ -196,7 +196,7 @@ def main(argv=None): output = template.render(invoice=invoice, locale=locale) #, company=company) if filename_from_invoice: - filename_date = str(invoice.GetDatePosted()) # something like 2014-11-01 + filename_date = invoice.GetDatePosted().strftime("%Y-%m-%d") # something like 2014-11-01 filename_owner_name = str(invoice.GetOwner().GetName()) filename_invoice_id = str(invoice.GetID()) filename_output = filename_date + "_" + filename_owner_name + "_" + filename_invoice_id + ".tex"