added lots of commenting to main.py
This commit is contained in:
parent
69c84c86b8
commit
e742633cf1
1 changed files with 92 additions and 9 deletions
101
main.py
101
main.py
|
|
@ -8,22 +8,37 @@
|
||||||
# License. See the LICENSE file included with the distribution for
|
# License. See the LICENSE file included with the distribution for
|
||||||
# details and disclaimer.
|
# details and disclaimer.
|
||||||
#
|
#
|
||||||
# This script provides a Python front-end to the ledger library, which
|
# This script provides a Python front-end to the ledger library, and
|
||||||
# replicates the functionality of the C++ front-end found in main.cc.
|
# replicates the functionality of the C++ front-end, main.cc. It is
|
||||||
# It is provided as an alternative to main.cc, or as a starting point
|
# provided as an example, and as a starting point for creating custom
|
||||||
# for creating custom front-ends based on the Ledger module. See the
|
# front-ends based on the Ledger module. See the documentation for an
|
||||||
# documentation for API references, and how to use that module.
|
# API reference, and how to use this module.
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import string
|
import string
|
||||||
|
|
||||||
from ledger import *
|
from ledger import *
|
||||||
|
|
||||||
|
# Create the main journal object, into which all entries will be
|
||||||
|
# recorded. Once done, the 'journal' may be iterated to yield those
|
||||||
|
# entries, in the same order as which they appeared in the journal
|
||||||
|
# file.
|
||||||
|
|
||||||
journal = Journal ()
|
journal = Journal ()
|
||||||
|
|
||||||
|
# This call registers all of the default command-line options that
|
||||||
|
# Ledger supports into the option handling mechanism. Skip this call
|
||||||
|
# if you wish to do all of your own processing -- in which case simply
|
||||||
|
# modify the 'config' object however you like.
|
||||||
|
|
||||||
add_config_option_handlers ()
|
add_config_option_handlers ()
|
||||||
|
|
||||||
|
# Process the command-line arguments, test whether caching should be
|
||||||
|
# enabled, and then process any option settings from the execution
|
||||||
|
# environment. Some historical environment variable names are also
|
||||||
|
# supported.
|
||||||
|
|
||||||
args = process_arguments (sys.argv[1:])
|
args = process_arguments (sys.argv[1:])
|
||||||
config.use_cache = not config.data_file
|
config.use_cache = not config.data_file
|
||||||
process_environment (os.environ, "LEDGER_")
|
process_environment (os.environ, "LEDGER_")
|
||||||
|
|
@ -35,10 +50,17 @@ if os.environ.has_key ("PRICE_HIST"):
|
||||||
if os.environ.has_key ("PRICE_EXP"):
|
if os.environ.has_key ("PRICE_EXP"):
|
||||||
process_option ("price-exp", os.environ["PRICE_EXP"])
|
process_option ("price-exp", os.environ["PRICE_EXP"])
|
||||||
|
|
||||||
|
# If no argument remain, then no command word was given. Report the
|
||||||
|
# default help text and exit.
|
||||||
|
|
||||||
if len (args) == 0:
|
if len (args) == 0:
|
||||||
option_help ()
|
option_help ()
|
||||||
sys.exit (0)
|
sys.exit (0)
|
||||||
|
|
||||||
|
# The command word is in the first argument. Canonicalize it to a
|
||||||
|
# unique, simple form that the remaining code can use to find out
|
||||||
|
# which command was specified.
|
||||||
|
|
||||||
command = args.pop (0);
|
command = args.pop (0);
|
||||||
|
|
||||||
if command == "balance" or command == "bal" or command == "b":
|
if command == "balance" or command == "bal" or command == "b":
|
||||||
|
|
@ -55,25 +77,52 @@ else:
|
||||||
print "Unrecognized command:", command
|
print "Unrecognized command:", command
|
||||||
sys.exit (1)
|
sys.exit (1)
|
||||||
|
|
||||||
|
# Create all the parser objects to be used. They are all registered,
|
||||||
|
# so that Ledger will try each one in turn whenever it is presented
|
||||||
|
# with a data file. They are attempted in reverse order to their
|
||||||
|
# registry. Note that Gnucash parsing is only available if the Ledger
|
||||||
|
# module was built with such support (which requires the xmlparse C
|
||||||
|
# library).
|
||||||
|
|
||||||
text_parser = TextualParser ()
|
text_parser = TextualParser ()
|
||||||
bin_parser = BinaryParser ()
|
bin_parser = BinaryParser ()
|
||||||
qif_parser = QifParser ()
|
qif_parser = QifParser ()
|
||||||
|
try:
|
||||||
|
gnucush_parser = GnucashParser ()
|
||||||
|
except:
|
||||||
|
gnucush_parser = None
|
||||||
|
|
||||||
register_parser (text_parser)
|
register_parser (text_parser)
|
||||||
register_parser (bin_parser)
|
register_parser (bin_parser)
|
||||||
|
if gnucash_parser:
|
||||||
|
register_parser (gnucash_parser)
|
||||||
register_parser (qif_parser)
|
register_parser (qif_parser)
|
||||||
|
|
||||||
|
# Parse all entries from the user specified locations (found in
|
||||||
|
# 'config') into the journal object we created. The two parsers given
|
||||||
|
# as explicit arguments indicate: the parser to be used for standard
|
||||||
|
# input, and the parser to be used for cache files.
|
||||||
|
|
||||||
parse_ledger_data (journal, text_parser, bin_parser)
|
parse_ledger_data (journal, text_parser, bin_parser)
|
||||||
|
|
||||||
|
# Now that everything has been correctly parsed (parse_ledger_data
|
||||||
|
# would have thrown an exception if not), we can take time to further
|
||||||
|
# process the configuration options. This changes the configuration a
|
||||||
|
# bit based on previous option settings, the command word, and the
|
||||||
|
# remaining arguments.
|
||||||
|
|
||||||
config.process_options(command, args);
|
config.process_options(command, args);
|
||||||
|
|
||||||
|
# If the command is "e", use the method journal.derive_entry to create
|
||||||
|
# a brand new entry based on the arguments given.
|
||||||
|
|
||||||
new_entry = None
|
new_entry = None
|
||||||
if command == "e":
|
if command == "e":
|
||||||
new_entry = journal.derive_entry (args)
|
new_entry = journal.derive_entry (args)
|
||||||
if new_entry is None:
|
if new_entry is None:
|
||||||
sys.exit (1)
|
sys.exit (1)
|
||||||
|
|
||||||
# Compile the format string
|
# Determine the format string to used, based on the command.
|
||||||
|
|
||||||
if config.format_string:
|
if config.format_string:
|
||||||
format = config.format_string
|
format = config.format_string
|
||||||
|
|
@ -86,6 +135,11 @@ elif command == "E":
|
||||||
else:
|
else:
|
||||||
format = config.print_format
|
format = config.print_format
|
||||||
|
|
||||||
|
# The following two classes are responsible for outputing transactions
|
||||||
|
# and accounts to the user. There are corresponding C++ versions to
|
||||||
|
# these, but they rely on I/O streams, which Boost.Python does not
|
||||||
|
# provide a conversion layer for.
|
||||||
|
|
||||||
class FormatTransaction (TransactionHandler):
|
class FormatTransaction (TransactionHandler):
|
||||||
last_entry = None
|
last_entry = None
|
||||||
output = None
|
output = None
|
||||||
|
|
@ -155,11 +209,21 @@ class FormatAccount (AccountHandler):
|
||||||
self.output.write(self.formatter.format(account))
|
self.output.write(self.formatter.format(account))
|
||||||
account_xdata (account).dflags |= ACCOUNT_DISPLAYED
|
account_xdata (account).dflags |= ACCOUNT_DISPLAYED
|
||||||
|
|
||||||
|
# Set the final transaction handler: for balances and equity reports,
|
||||||
|
# it will simply add the value of the transaction to the account's
|
||||||
|
# xdata, which is used a bit later to report those totals. For all
|
||||||
|
# other reports, the transaction data is sent to the configured output
|
||||||
|
# location (default is sys.stdout).
|
||||||
|
|
||||||
if command == "b" or command == "E":
|
if command == "b" or command == "E":
|
||||||
handler = SetAccountValue()
|
handler = SetAccountValue()
|
||||||
else:
|
else:
|
||||||
handler = FormatTransaction(format)
|
handler = FormatTransaction(format)
|
||||||
|
|
||||||
|
# Chain transaction filters on top of the base handler. Most of these
|
||||||
|
# filters customize the output for reporting. None of this is done
|
||||||
|
# for balance or equity reports, which don't need it.
|
||||||
|
|
||||||
if not (command == "b" or command == "E"):
|
if not (command == "b" or command == "E"):
|
||||||
if config.display_predicate:
|
if config.display_predicate:
|
||||||
handler = FilterTransactions(handler, config.display_predicate)
|
handler = FilterTransactions(handler, config.display_predicate)
|
||||||
|
|
@ -179,25 +243,40 @@ if not (command == "b" or command == "E"):
|
||||||
handler = SubtotalTransactions(handler)
|
handler = SubtotalTransactions(handler)
|
||||||
elif config.report_interval:
|
elif config.report_interval:
|
||||||
handler = IntervalTransactions(handler, config.report_interval)
|
handler = IntervalTransactions(handler, config.report_interval)
|
||||||
|
handler = SortTransactions(handler, "d")
|
||||||
elif config.days_of_the_week:
|
elif config.days_of_the_week:
|
||||||
handler = DowTransactions(handler)
|
handler = DowTransactions(handler)
|
||||||
|
|
||||||
|
# The next two transaction filters are used by all reports.
|
||||||
|
|
||||||
if config.show_related:
|
if config.show_related:
|
||||||
handler = RelatedTransactions(handler, config.show_all_related)
|
handler = RelatedTransactions(handler, config.show_all_related)
|
||||||
|
|
||||||
if config.predicate:
|
if config.predicate:
|
||||||
handler = FilterTransactions(handler, config.predicate)
|
handler = FilterTransactions(handler, config.predicate)
|
||||||
|
|
||||||
if 0:
|
# Walk the journal's entries, and pass each entry's transaction to the
|
||||||
|
# handler chain established above. And although a journal's entries
|
||||||
|
# can be walked using Python, it is significantly faster to do this
|
||||||
|
# simple walk in C++, using `walk_entries'.
|
||||||
|
|
||||||
|
if 1:
|
||||||
walk_entries (journal, handler)
|
walk_entries (journal, handler)
|
||||||
else:
|
else:
|
||||||
# These for loops are equivalent to `walk_entries', but far slower
|
|
||||||
for entry in journal:
|
for entry in journal:
|
||||||
for xact in entry:
|
for xact in entry:
|
||||||
handler (xact)
|
handler (xact)
|
||||||
|
|
||||||
|
# Flush the handlers, causing them to output whatever data is still
|
||||||
|
# pending.
|
||||||
|
|
||||||
handler.flush ()
|
handler.flush ()
|
||||||
|
|
||||||
|
# For the balance and equity reports, the account totals now need to
|
||||||
|
# be displayed. This is different from outputting transactions, in
|
||||||
|
# that we are now outputting account totals to display a summary of
|
||||||
|
# the transactions that were just walked.
|
||||||
|
|
||||||
if command == "b":
|
if command == "b":
|
||||||
acct_formatter = FormatAccount (format, config.display_predicate)
|
acct_formatter = FormatAccount (format, config.display_predicate)
|
||||||
sum_accounts (journal.master)
|
sum_accounts (journal.master)
|
||||||
|
|
@ -217,5 +296,9 @@ if command == "b":
|
||||||
# walk_accounts(*journal->master, acct_formatter, config.sort_string);
|
# walk_accounts(*journal->master, acct_formatter, config.sort_string);
|
||||||
# acct_formatter.flush();
|
# acct_formatter.flush();
|
||||||
|
|
||||||
|
# If the cache is being used, and is dirty, update it now.
|
||||||
|
|
||||||
if config.use_cache and config.cache_dirty and config.cache_file:
|
if config.use_cache and config.cache_dirty and config.cache_file:
|
||||||
write_binary_journal(config.cache_file, journal);
|
write_binary_journal(config.cache_file, journal);
|
||||||
|
|
||||||
|
# We're done!
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue