4 """ @package str_methods.py -- Add __str__ and __unicode__ methods to financial objects
6 Import this module and str(Object) and unicode(Object) where Object is Transaction, Split,Invoice
7 or Entry leads to human readable results. That is handy when using @code print object @endcode
9 I chose to put these functions/methods in a seperate 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
33 import gnucash, function_class
36 DEFAULT_ENCODING =
"UTF-8"
37 DEFAULT_ERROR =
"ignore"
39 def setflag(self, name, value):
40 if not(name
in self.OPTIONFLAGS_BY_NAME):
41 self.register_optionflag(name)
43 self.optionflags |= self.OPTIONFLAGS_BY_NAME[name]
45 self.optionflags &= ~self.OPTIONFLAGS_BY_NAME[name]
47 def getflag(self, name):
48 if not(name
in self.OPTIONFLAGS_BY_NAME):
49 raise KeyError(str(name)+
" is not a registered key.")
50 return ((self.optionflags & self.OPTIONFLAGS_BY_NAME[name]) != 0)
52 def register_optionflag(self,name):
53 """Taken from doctest.py"""
55 return self.OPTIONFLAGS_BY_NAME.setdefault(name, 1 << len(self.OPTIONFLAGS_BY_NAME))
57 def ya_add_method(_class, function, method_name=None, clsmethod=False, noinstance=False):
58 """Calls add_method from function_methods.py but makes it
59 possible to use functions in this module. Also keeps the
62 if method_name ==
None:
63 method_name = function.__name__
65 setattr(gnucash.gnucash_core_c,function.__name__,function)
67 mf=_class.ya_add_classmethod(function.__name__,method_name)
69 mf=_class.add_method(function.__name__,method_name)
71 mf=_class.ya_add_method(function.__name__,method_name)
72 if function.__doc__ !=
None:
73 setattr(mf,
"__doc__", function.__doc__)
75 def infect(_class, function, method_name):
76 if not getattr(_class,
"OPTIONFLAGS_BY_NAME",
None):
77 _class.OPTIONFLAGS_BY_NAME={}
79 ya_add_method(_class,register_optionflag,clsmethod=
True)
80 ya_add_method(_class,setflag,clsmethod=
True)
81 ya_add_method(_class,getflag,clsmethod=
True)
82 ya_add_method(_class, function, method_name)
85 """This class provides a __format__ method which cuts values to a certain width.
87 If width is too big '...' will be put at the end of the resulting string."""
89 def __init__(self,value):
92 def __format__(self, fmt):
93 def get_width(fmt_spec):
94 """Parse fmt_spec to obtain width"""
96 def remove_alignment(fmt_spec):
97 if fmt_spec[1]
in [
"<",
"^",
">"]:
98 fmt_spec=fmt_spec[2:len(fmt_spec)]
101 def remove_sign(fmt_spec):
102 if fmt_spec[0]
in [
"-",
"+",
" "]:
103 fmt_spec=fmt_spec[1:len(fmt_spec)]
106 def remove_cross(fmt_spec):
107 if fmt_spec[0]
in [
"#"]:
108 fmt_spec=fmt_spec[1:len(fmt_spec)]
111 def do_width(fmt_spec):
114 while len(fmt_spec)>0:
115 if fmt_spec[0].isdigit():
117 fmt_spec=fmt_spec[1:len(fmt_spec)]
126 fmt_spec=remove_alignment(fmt_spec)
128 fmt_spec=remove_sign(fmt_spec)
130 fmt_spec=remove_cross(fmt_spec)
131 width=do_width(fmt_spec)
136 def cut(s, width, replace_string="..."):
137 """Cuts s to width and puts replace_string at it's end."""
142 if len(replace_string)>width:
143 replace_string=replace_string[0:width]
144 s=s[0:width-len(replace_string)]
153 if type(value)
in [types.StringType, types.UnicodeType]:
154 value=value.replace(
"\t",
"|")
155 value=value.replace(
"\n",
"|")
158 value=value.__format__(fmt)
163 value=cut(value, width,
"...")
167 def all_as_classwithcutting__format__(*args):
168 """Converts every argument to instance of ClassWithCutting__format__"""
173 if type(a)
in [types.StringType, types.UnicodeType]:
179 def all_as_classwithcutting__format__keys(encoding=None, error=None, **keys):
180 """Converts every argument to instance of ClassWithCutting__format__"""
185 encoding=DEFAULT_ENCODING
189 if type(keys[a])
in [types.StringType, types.UnicodeType]:
190 keys[a]=keys[a].decode(encoding,error)
198 def __split__unicode__(self, encoding=None, error=None):
199 """__unicode__(self, encoding=None, error=None) -> object
201 Serialize the Split object and return as a new Unicode object.
204 encoding -- defaults to str_methods.default_encoding
205 error -- defaults to str_methods.default_error
206 See help(unicode) for more details or http://docs.python.org/howto/unicode.html.
210 from gnucash
import Split
216 if type(lot).__name__ ==
'SwigPyObject':
217 lot=gnucash.GncLot(instance=lot)
218 lot_str=lot.get_title()
222 transaction=self.GetParent()
226 "account":self.GetAccount().name,
227 "value":self.GetValue(),
228 "memo":self.GetMemo(),
231 fmt_str= (
u"Account: {account:20} "+
232 u"Value: {value:>10} "+
235 if self.optionflags & self.OPTIONFLAGS_BY_NAME[
"PRINT_TRANSACTION"]:
237 "transaction_time":time.ctime(transaction.GetDate()),
238 "transaction2":transaction.GetDescription()}
240 u"Transaction: {transaction_time:30} "+
241 u"- {transaction2:30} "+
243 fmt_dict.update(fmt_t_dict)
246 return fmt_str.format(**all_as_classwithcutting__format__keys(encoding,error,**fmt_dict))
248 def __split__str__(self):
249 """Returns a bytestring representation of self.__unicode__"""
251 from gnucash
import Split
254 return unicode(self).encode(
'utf-8')
258 infect(gnucash.Split,__split__str__,
"__str__")
259 infect(gnucash.Split,__split__unicode__,
"__unicode__")
260 gnucash.Split.register_optionflag(
"PRINT_TRANSACTION")
261 gnucash.Split.setflag(
"PRINT_TRANSACTION",
True)
263 def __transaction__unicode__(self):
264 """__unicode__ method for Transaction class"""
265 from gnucash
import Transaction
269 fmt_tuple=(
'Date:',time.ctime(self.GetDate()),
270 'Description:',self.GetDescription(),
271 'Notes:',self.GetNotes())
273 transaction_str =
u"{0:6}{1:25} {2:14}{3:40} {4:7}{5:40}".format(
274 *all_as_classwithcutting__format__(*fmt_tuple))
275 transaction_str +=
"\n"
278 for n,split
in enumerate(self.GetSplitList()):
279 if not (type(split)==gnucash.Split):
280 split=gnucash.Split(instance=split)
282 transaction_flag = split.getflag(
"PRINT_TRANSACTION")
283 split.setflag(
"PRINT_TRANSACTION",
False)
284 splits_str +=
u"[{0:>2}] ".format(unicode(n))
285 splits_str += unicode(split)
287 split.setflag(
"PRINT_TRANSACTION",transaction_flag)
289 return transaction_str + splits_str
291 def __transaction__str__(self):
292 """__str__ method for Transaction class"""
293 from gnucash
import Transaction
296 return unicode(self).encode(
'utf-8')
299 gnucash.gnucash_core_c.__transaction__str__=__transaction__str__
300 gnucash.Transaction.add_method(
"__transaction__str__",
"__str__")
302 gnucash.gnucash_core_c.__transaction__unicode__=__transaction__unicode__
303 gnucash.Transaction.add_method(
"__transaction__unicode__",
"__unicode__")
305 def __invoice__unicode__(self):
306 """__unicode__ method for Invoice"""
308 from gnucash.gnucash_business
import Invoice
309 self=Invoice(instance=self)
315 "id_value":self.GetID(),
316 "notes_name":
"Notes:",
317 "notes_value":self.GetNotes(),
318 "active_name":
"Active:",
319 "active_value":str(self.GetActive()),
320 "owner_name":
"Owner Name:",
321 "owner_value":self.GetOwner().GetName(),
322 "total_name":
"Total:",
323 "total_value":str(self.GetTotal()),
324 "currency_mnemonic":self.GetCurrency().get_mnemonic()}
326 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}"+
327 u"{total_name:8}{total_value:10}{currency_mnemonic:3}").\
328 format(**all_as_classwithcutting__format__keys(**fmt_dict))
331 entry_list = self.GetEntries()
332 for entry
in entry_list:
333 if not(type(entry)==Entry):
334 entry=Entry(instance=entry)
335 ret_entries +=
" "+unicode(entry)+
"\n"
337 return ret_invoice+
"\n"+ret_entries
339 def __invoice__str__(self):
340 """__str__ method for invoice class"""
342 from gnucash.gnucash_business
import Invoice
343 self=Invoice(instance=self)
345 return unicode(self).encode(
'utf-8')
347 from gnucash.gnucash_business
import Invoice
349 gnucash.gnucash_core_c.__invoice__str__=__invoice__str__
350 gnucash.gnucash_business.Invoice.add_method(
"__invoice__str__",
"__str__")
352 gnucash.gnucash_core_c.__invoice__unicode__=__invoice__unicode__
353 gnucash.gnucash_business.Invoice.add_method(
"__invoice__unicode__",
"__unicode__")
355 def __entry__unicode__(self):
356 """__unicode__ method for Entry"""
358 from gnucash.gnucash_business
import Entry
359 self=Entry(instance=self)
364 "date_value":unicode(self.GetDate()),
365 "description_name":
"Description:",
366 "description_value":self.GetDescription(),
367 "notes_name":
"Notes:",
368 "notes_value":self.GetNotes(),
369 "quant_name":
"Quantity:",
370 "quant_value":unicode(self.GetQuantity()),
371 "invprice_name":
"InvPrice:",
372 "invprice_value":unicode(self.GetInvPrice())}
374 return (
u"{date_name:6}{date_value:15} {description_name:13}{description_value:20} {notes_name:7}{notes_value:20}"+
375 u"{quant_name:12}{quant_value:7} {invprice_name:10}{invprice_value:7}").\
376 format(**all_as_classwithcutting__format__keys(**fmt_dict))
378 def __entry__str__(self):
379 """__str__ method for Entry class"""
381 from gnucash.gnucash_business
import Entry
382 self=Entry(instance=self)
384 return unicode(self).encode(
'utf-8')
386 from gnucash.gnucash_business
import Entry
388 gnucash.gnucash_core_c.__entry__str__=__entry__str__
389 gnucash.gnucash_business.Entry.add_method(
"__entry__str__",
"__str__")
391 gnucash.gnucash_core_c.__entry__unicode__=__entry__unicode__
392 gnucash.gnucash_business.Entry.add_method(
"__entry__unicode__",
"__unicode__")