4 """ @package str_methods.py -- Add __str__ methods to financial objects 6 Import this module and str(Object) where Object is Transaction, Split, Invoice or Entry leads to 7 human readable results. That is handy when using @code print object @endcode 9 I chose to put these functions/methods in a separate file to develop them like this and maybe if 10 they prove to be useful they can be put in gnucash_core.py. 12 I am searching to find the best way to serialize these complex objects. Ideally this serialization 13 would be configurable. 15 If someone has suggestions how to beautify, purify or improve this code in any way please feel 18 This is written as a first approach to a shell-environment using ipython to interactively manipulate 34 from gnucash
import function_class
37 DEFAULT_ENCODING =
"UTF-8" 38 DEFAULT_ERROR =
"ignore" 40 def setflag(self, name, value):
41 if not(name
in self.OPTIONFLAGS_BY_NAME):
42 self.register_optionflag(name)
44 self.optionflags |= self.OPTIONFLAGS_BY_NAME[name]
46 self.optionflags &= ~self.OPTIONFLAGS_BY_NAME[name]
48 def getflag(self, name):
49 if not(name
in self.OPTIONFLAGS_BY_NAME):
50 raise KeyError(str(name)+
" is not a registered key.")
51 return ((self.optionflags & self.OPTIONFLAGS_BY_NAME[name]) != 0)
53 def register_optionflag(self,name):
54 """Taken from doctest.py""" 56 return self.OPTIONFLAGS_BY_NAME.setdefault(name, 1 << len(self.OPTIONFLAGS_BY_NAME))
58 def ya_add_method(_class, function, method_name=None, clsmethod=False, noinstance=False):
59 """Calls add_method from function_methods.py but makes it 60 possible to use functions in this module. Also keeps the 63 if method_name ==
None:
64 method_name = function.__name__
66 setattr(gnucash.gnucash_core_c,function.__name__,function)
68 mf=_class.ya_add_classmethod(function.__name__,method_name)
70 mf=_class.add_method(function.__name__,method_name)
72 mf=_class.ya_add_method(function.__name__,method_name)
73 if function.__doc__ !=
None:
74 setattr(mf,
"__doc__", function.__doc__)
76 def infect(_class, function, method_name):
77 if not getattr(_class,
"OPTIONFLAGS_BY_NAME",
None):
78 _class.OPTIONFLAGS_BY_NAME={}
80 ya_add_method(_class,register_optionflag,clsmethod=
True)
81 ya_add_method(_class,setflag,clsmethod=
True)
82 ya_add_method(_class,getflag,clsmethod=
True)
83 ya_add_method(_class, function, method_name)
86 """This class provides a __format__ method which cuts values to a certain width. 88 If width is too big '...' will be put at the end of the resulting string.""" 90 def __init__(self,value):
93 def __format__(self, fmt):
94 def get_width(fmt_spec):
95 """Parse fmt_spec to obtain width""" 97 def remove_alignment(fmt_spec):
98 if fmt_spec[1]
in [
"<",
"^",
">"]:
99 fmt_spec=fmt_spec[2:len(fmt_spec)]
102 def remove_sign(fmt_spec):
103 if fmt_spec[0]
in [
"-",
"+",
" "]:
104 fmt_spec=fmt_spec[1:len(fmt_spec)]
107 def remove_cross(fmt_spec):
108 if fmt_spec[0]
in [
"#"]:
109 fmt_spec=fmt_spec[1:len(fmt_spec)]
112 def do_width(fmt_spec):
115 while len(fmt_spec)>0:
116 if fmt_spec[0].isdigit():
118 fmt_spec=fmt_spec[1:len(fmt_spec)]
127 fmt_spec=remove_alignment(fmt_spec)
129 fmt_spec=remove_sign(fmt_spec)
131 fmt_spec=remove_cross(fmt_spec)
132 width=do_width(fmt_spec)
137 def cut(s, width, replace_string="..."):
138 """Cuts s to width and puts replace_string at it's end.""" 143 if len(replace_string)>width:
144 replace_string=replace_string[0:width]
145 s=s[0:width-len(replace_string)]
154 if isinstance(value, str):
155 value = value.replace(
"\t",
"|")
156 value = value.replace(
"\n",
"|")
159 value = value.__format__(fmt)
162 width = get_width(fmt)
164 value = cut(value, width,
"...")
168 def all_as_classwithcutting__format__(*args):
169 """Converts every argument to instance of ClassWithCutting__format__""" 180 def all_as_classwithcutting__format__keys(encoding=None, error=None, **keys):
181 """Converts every argument to instance of ClassWithCutting__format__""" 186 encoding=DEFAULT_ENCODING
199 def __split__str__(self, encoding=None, error=None):
200 """__str__(self, encoding=None, error=None) -> object 202 Serialize the Split object and return as a new Unicode object. 205 encoding -- defaults to str_methods.default_encoding 206 error -- defaults to str_methods.default_error 207 See help(unicode) for more details or http://docs.python.org/howto/unicode.html. 211 from gnucash
import Split
217 if type(lot).__name__ ==
'SwigPyObject':
218 lot=gnucash.GncLot(instance=lot)
219 lot_str=lot.get_title()
223 transaction=self.GetParent()
227 "account":self.GetAccount().name,
228 "value":self.GetValue(),
229 "memo":self.GetMemo(),
232 fmt_str= (
"Account: {account:20} "+
233 "Value: {value:>10} "+
236 if self.optionflags & self.OPTIONFLAGS_BY_NAME[
"PRINT_TRANSACTION"]:
238 "transaction_time":time.ctime(transaction.GetDate()),
239 "transaction2":transaction.GetDescription()}
241 "Transaction: {transaction_time:30} "+
242 "- {transaction2:30} "+
244 fmt_dict.update(fmt_t_dict)
247 return fmt_str.format(**all_as_classwithcutting__format__keys(encoding,error,**fmt_dict))
251 infect(gnucash.Split,__split__str__,
"__str__")
252 gnucash.Split.register_optionflag(
"PRINT_TRANSACTION")
253 gnucash.Split.setflag(
"PRINT_TRANSACTION",
True)
255 def __transaction__str__(self):
256 """__str__ method for Transaction class""" 257 from gnucash
import Transaction
259 self=Transaction(instance=self)
261 fmt_tuple=(
'Date:',time.ctime(self.GetDate()),
262 'Description:',self.GetDescription(),
263 'Notes:',self.GetNotes())
265 transaction_str =
"{0:6}{1:25} {2:14}{3:40} {4:7}{5:40}".format(
266 *all_as_classwithcutting__format__(*fmt_tuple))
267 transaction_str +=
"\n" 270 for n,split
in enumerate(self.GetSplitList()):
271 if not (type(split)==gnucash.Split):
272 split=gnucash.Split(instance=split)
274 transaction_flag = split.getflag(
"PRINT_TRANSACTION")
275 split.setflag(
"PRINT_TRANSACTION",
False)
276 splits_str +=
"[{0:>2}] ".format(str(n))
277 splits_str += str(split)
279 split.setflag(
"PRINT_TRANSACTION",transaction_flag)
281 return transaction_str + splits_str
283 gnucash.gnucash_core_c.__transaction__str__=__transaction__str__
284 gnucash.Transaction.add_method(
"__transaction__str__",
"__str__")
286 def __invoice__str__(self):
287 """__str__ method for Invoice""" 289 from gnucash.gnucash_business
import Invoice
290 self=Invoice(instance=self)
296 "id_value":self.GetID(),
297 "notes_name":
"Notes:",
298 "notes_value":self.GetNotes(),
299 "active_name":
"Active:",
300 "active_value":str(self.GetActive()),
301 "owner_name":
"Owner Name:",
302 "owner_value":self.GetOwner().GetName(),
303 "total_name":
"Total:",
304 "total_value":str(self.GetTotal()),
305 "currency_mnemonic":self.GetCurrency().get_mnemonic()}
307 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}"+
308 "{total_name:8}{total_value:10}{currency_mnemonic:3}").\
309 format(**all_as_classwithcutting__format__keys(**fmt_dict))
312 entry_list = self.GetEntries()
313 for entry
in entry_list:
314 if not(type(entry)==Entry):
315 entry=Entry(instance=entry)
316 ret_entries +=
" "+str(entry)+
"\n" 318 return ret_invoice+
"\n"+ret_entries
321 from gnucash.gnucash_business
import Invoice
323 gnucash.gnucash_core_c.__invoice__str__=__invoice__str__
324 gnucash.gnucash_business.Invoice.add_method(
"__invoice__str__",
"__str__")
326 def __entry__str__(self):
327 """__str__ method for Entry""" 329 from gnucash.gnucash_business
import Entry
330 self=Entry(instance=self)
335 "date_value":str(self.GetDate()),
336 "description_name":
"Description:",
337 "description_value":self.GetDescription(),
338 "notes_name":
"Notes:",
339 "notes_value":self.GetNotes(),
340 "quant_name":
"Quantity:",
341 "quant_value":str(self.GetQuantity()),
342 "invprice_name":
"InvPrice:",
343 "invprice_value":str(self.GetInvPrice())}
345 return (
"{date_name:6}{date_value:15} {description_name:13}{description_value:20} {notes_name:7}{notes_value:20}"+
346 "{quant_name:12}{quant_value:7} {invprice_name:10}{invprice_value:7}").\
347 format(**all_as_classwithcutting__format__keys(**fmt_dict))
349 from gnucash.gnucash_business
import Entry
351 gnucash.gnucash_core_c.__entry__str__=__entry__str__
352 gnucash.gnucash_business.Entry.add_method(
"__entry__str__",
"__str__")