Removed Python integration support.
This commit is contained in:
parent
2eafddc91b
commit
ce3491c99f
38 changed files with 37 additions and 3648 deletions
52
Makefile.am
52
Makefile.am
|
|
@ -33,10 +33,6 @@ if HAVE_LIBOFX
|
|||
libledger_la_CXXFLAGS += -DHAVE_LIBOFX=1
|
||||
libledger_la_SOURCES += ofx.cc
|
||||
endif
|
||||
if HAVE_BOOST_PYTHON
|
||||
libledger_la_CXXFLAGS += -DUSE_BOOST_PYTHON=1
|
||||
libledger_la_SOURCES += py_eval.cc
|
||||
endif
|
||||
if DEBUG
|
||||
libledger_la_CXXFLAGS += -DDEBUG_LEVEL=4
|
||||
libledger_la_SOURCES += debug.cc
|
||||
|
|
@ -61,8 +57,6 @@ pkginclude_HEADERS = \
|
|||
mask.h \
|
||||
option.h \
|
||||
parser.h \
|
||||
py_eval.h \
|
||||
pyledger.h \
|
||||
qif.h \
|
||||
quotes.h \
|
||||
reconcile.h \
|
||||
|
|
@ -79,12 +73,7 @@ pkginclude_HEADERS = \
|
|||
bin_PROGRAMS = ledger
|
||||
ledger_CXXFLAGS =
|
||||
ledger_SOURCES = main.cc
|
||||
if HAVE_BOOST_PYTHON
|
||||
ledger_CXXFLAGS += -DUSE_BOOST_PYTHON=1
|
||||
ledger_LDADD = $(LIBOBJS) libledger.la -lboost_python -lpython$(PYTHON_VERSION)
|
||||
else
|
||||
ledger_LDADD = $(LIBOBJS) libledger.la
|
||||
endif
|
||||
if HAVE_EXPAT
|
||||
ledger_CXXFLAGS += -DHAVE_EXPAT=1
|
||||
ledger_LDADD += -lexpat
|
||||
|
|
@ -106,48 +95,11 @@ info_TEXINFOS = ledger.texi
|
|||
|
||||
######################################################################
|
||||
|
||||
if HAVE_BOOST_PYTHON
|
||||
|
||||
noinst_PROGRAMS = ledger.so
|
||||
|
||||
if HAVE_EXPAT
|
||||
HAVE_EXPAT_VALUE = true
|
||||
else
|
||||
HAVE_EXPAT_VALUE = false
|
||||
endif
|
||||
if HAVE_XMLPARSE
|
||||
HAVE_XMLPARSE_VALUE = true
|
||||
else
|
||||
HAVE_XMLPARSE_VALUE = false
|
||||
endif
|
||||
if HAVE_LIBOFX
|
||||
HAVE_LIBOFX_VALUE = true
|
||||
else
|
||||
HAVE_LIBOFX_VALUE = false
|
||||
endif
|
||||
|
||||
ledger.so: py_eval.cc libledger.la
|
||||
CFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS) -L. -L.libs" \
|
||||
HAVE_EXPAT="$(HAVE_EXPAT_VALUE)" \
|
||||
HAVE_XMLPARSE="$(HAVE_XMLPARSE_VALUE)" \
|
||||
HAVE_LIBOFX="$(HAVE_LIBOFX_VALUE)" \
|
||||
python setup.py build --build-lib=.
|
||||
|
||||
install-exec-hook:
|
||||
CFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS) -L. -L.libs" \
|
||||
HAVE_EXPAT="$(HAVE_EXPAT_VALUE)" \
|
||||
HAVE_XMLPARSE="$(HAVE_XMLPARSE_VALUE)" \
|
||||
HAVE_LIBOFX="$(HAVE_LIBOFX_VALUE)" \
|
||||
python setup.py install --prefix=$(prefix)
|
||||
|
||||
endif
|
||||
|
||||
all-clean: maintainer-clean
|
||||
rm -fr *~ .*~ .\#* *.html *.info *.pdf *.a *.so *.o *.lo *.la \
|
||||
*.elc *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.pyc \
|
||||
*.elc *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr \
|
||||
.gdb_history gmon.out h out TAGS ledger valexpr .deps \
|
||||
.libs build AUTHORS COPYING INSTALL Makefile acconf.h \
|
||||
acconf.h.in aclocal.m4 autom4te config.guess config.sub \
|
||||
configure depcomp install-sh libtool ltconfig ltmain.sh \
|
||||
missing stamp texinfo.tex Makefile.in mkinstalldirs \
|
||||
py-compile
|
||||
missing stamp texinfo.tex Makefile.in mkinstalldirs
|
||||
|
|
|
|||
4
NEWS
4
NEWS
|
|
@ -84,6 +84,10 @@
|
|||
- Added a new value expression regexp command:
|
||||
C// compare against transaction amount's commodity symbol
|
||||
|
||||
- Added a new "csv" command, for outputting results in CSV format.
|
||||
|
||||
- Completely removed Python integration.
|
||||
|
||||
* 2.4
|
||||
|
||||
- Both "-$100.00" and "$-100.00" are now equivalent amounts.
|
||||
|
|
|
|||
12
README
12
README
|
|
@ -71,15 +71,3 @@ join the Ledger mailing list at the following Web address:
|
|||
|
||||
You can also find help at the #ledger channel on the IRC server
|
||||
irc.freenode.net.
|
||||
|
||||
|
||||
Building Ledger as a Python Module
|
||||
==================================
|
||||
|
||||
If you have Python 2.2 or higher installed, and Boost.Python, then
|
||||
Ledger can also be built as a Python module if --enable-python is
|
||||
passed to the configure script. This means you can interact with your
|
||||
Ledger data from Python, making it easier to write custom reports.
|
||||
|
||||
This feature is mostly undocumented in version 2.0, although main.py
|
||||
gives a working example.
|
||||
|
|
|
|||
10
acprep
10
acprep
|
|
@ -12,17 +12,14 @@ else
|
|||
fi
|
||||
autoconf
|
||||
|
||||
INCDIRS="-I/sw/include -I/usr/local/include/boost-1_33 -I/usr/include/httpd/xml -I/usr/include/python2.3"
|
||||
INCDIRS="-I/sw/include -I/usr/local/include/boost-1_33 -I/usr/include/httpd/xml"
|
||||
#INCDIRS="$INCDIRS -I/sw/include/libofx"
|
||||
INCDIRS="$INCDIRS -Wno-long-double"
|
||||
LIBDIRS="-L/sw/lib -L/usr/local/lib -L/usr/lib/python2.3/config"
|
||||
LIBDIRS="-L/sw/lib -L/usr/local/lib"
|
||||
|
||||
if [ "$1" = "--debug" ]; then
|
||||
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g" \
|
||||
--enable-debug
|
||||
elif [ "$1" = "--debug-python" ]; then
|
||||
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g" \
|
||||
--enable-debug --enable-python
|
||||
elif [ "$1" = "--opt" ]; then
|
||||
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \
|
||||
CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC"
|
||||
|
|
@ -31,8 +28,7 @@ elif [ "$1" = "--flat-opt" ]; then
|
|||
CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450"
|
||||
elif [ "$1" = "--safe-opt" ]; then
|
||||
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" \
|
||||
CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC -DDEBUG_LEVEL=1" \
|
||||
--enable-python
|
||||
CXXFLAGS="-fomit-frame-pointer -O3 -mcpu=7450 -fPIC -DDEBUG_LEVEL=1"
|
||||
elif [ "$1" = "--perf" ]; then
|
||||
./configure CPPFLAGS="$INCDIRS" LDFLAGS="$LIBDIRS" CXXFLAGS="-g -pg"
|
||||
fi
|
||||
|
|
|
|||
165
amount.cc
165
amount.cc
|
|
@ -1245,168 +1245,3 @@ amount_t commodity_t::value(const std::time_t moment)
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <Python.h>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
void py_parse_1(amount_t& amount, const std::string& str,
|
||||
unsigned short flags) {
|
||||
amount.parse(str, flags);
|
||||
}
|
||||
void py_parse_2(amount_t& amount, const std::string& str) {
|
||||
amount.parse(str);
|
||||
}
|
||||
|
||||
struct commodity_updater_wrap : public commodity_t::updater_t
|
||||
{
|
||||
PyObject * self;
|
||||
commodity_updater_wrap(PyObject * self_) : self(self_) {}
|
||||
|
||||
virtual void operator()(commodity_t& commodity,
|
||||
const std::time_t moment,
|
||||
const std::time_t date,
|
||||
const std::time_t last,
|
||||
amount_t& price) {
|
||||
call_method<void>(self, "__call__", commodity, moment, date, last, price);
|
||||
}
|
||||
};
|
||||
|
||||
commodity_t * py_find_commodity_1(const std::string& symbol)
|
||||
{
|
||||
return commodity_t::find_commodity(symbol);
|
||||
}
|
||||
|
||||
commodity_t * py_find_commodity_2(const std::string& symbol, bool auto_create)
|
||||
{
|
||||
return commodity_t::find_commodity(symbol, auto_create);
|
||||
}
|
||||
|
||||
#define EXC_TRANSLATOR(type) \
|
||||
void exc_translate_ ## type(const type& err) { \
|
||||
PyErr_SetString(PyExc_RuntimeError, err.what()); \
|
||||
}
|
||||
|
||||
EXC_TRANSLATOR(amount_error)
|
||||
|
||||
void export_amount()
|
||||
{
|
||||
scope().attr("AMOUNT_PARSE_NO_MIGRATE") = AMOUNT_PARSE_NO_MIGRATE;
|
||||
scope().attr("AMOUNT_PARSE_NO_REDUCE") = AMOUNT_PARSE_NO_REDUCE;
|
||||
|
||||
class_< amount_t > ("Amount")
|
||||
.def(init<amount_t>())
|
||||
.def(init<std::string>())
|
||||
.def(init<char *>())
|
||||
.def(init<bool>())
|
||||
.def(init<long>())
|
||||
.def(init<unsigned long>())
|
||||
.def(init<double>())
|
||||
|
||||
.def("commodity", &amount_t::commodity,
|
||||
return_value_policy<reference_existing_object>())
|
||||
.def("set_commodity", &amount_t::set_commodity)
|
||||
.def("clear_commodity", &amount_t::clear_commodity)
|
||||
.def("quantity_string", &amount_t::quantity_string)
|
||||
|
||||
.def(self += self)
|
||||
.def(self += long())
|
||||
.def(self + self)
|
||||
.def(self + long())
|
||||
.def(self -= self)
|
||||
.def(self -= long())
|
||||
.def(self - self)
|
||||
.def(self - long())
|
||||
.def(self *= self)
|
||||
.def(self *= long())
|
||||
.def(self * self)
|
||||
.def(self * long())
|
||||
.def(self /= self)
|
||||
.def(self /= long())
|
||||
.def(self / self)
|
||||
.def(self / long())
|
||||
.def(- self)
|
||||
|
||||
.def(self < self)
|
||||
.def(self < long())
|
||||
.def(self <= self)
|
||||
.def(self <= long())
|
||||
.def(self > self)
|
||||
.def(self > long())
|
||||
.def(self >= self)
|
||||
.def(self >= long())
|
||||
.def(self == self)
|
||||
.def(self == long())
|
||||
.def(self != self)
|
||||
.def(self != long())
|
||||
.def(! self)
|
||||
|
||||
.def(self_ns::int_(self))
|
||||
.def(self_ns::float_(self))
|
||||
.def(self_ns::str(self))
|
||||
.def(abs(self))
|
||||
|
||||
.def("negate", &amount_t::negate)
|
||||
.def("parse", py_parse_1)
|
||||
.def("parse", py_parse_2)
|
||||
.def("reduce", &amount_t::reduce)
|
||||
.def("valid", &amount_t::valid)
|
||||
;
|
||||
|
||||
class_< commodity_t::updater_t, commodity_updater_wrap, boost::noncopyable >
|
||||
("Updater")
|
||||
;
|
||||
|
||||
scope().attr("COMMODITY_STYLE_DEFAULTS") = COMMODITY_STYLE_DEFAULTS;
|
||||
scope().attr("COMMODITY_STYLE_SUFFIXED") = COMMODITY_STYLE_SUFFIXED;
|
||||
scope().attr("COMMODITY_STYLE_SEPARATED") = COMMODITY_STYLE_SEPARATED;
|
||||
scope().attr("COMMODITY_STYLE_EUROPEAN") = COMMODITY_STYLE_EUROPEAN;
|
||||
scope().attr("COMMODITY_STYLE_THOUSANDS") = COMMODITY_STYLE_THOUSANDS;
|
||||
scope().attr("COMMODITY_STYLE_NOMARKET") = COMMODITY_STYLE_NOMARKET;
|
||||
scope().attr("COMMODITY_STYLE_VARIABLE") = COMMODITY_STYLE_VARIABLE;
|
||||
|
||||
class_< commodity_t > ("Commodity")
|
||||
.def(init<std::string, optional<unsigned int, unsigned int> >())
|
||||
|
||||
.def_readonly("symbol", &commodity_t::symbol)
|
||||
.def("set_symbol", &commodity_t::set_symbol)
|
||||
.def_readwrite("name", &commodity_t::name)
|
||||
.def_readwrite("note", &commodity_t::name)
|
||||
.def_readwrite("precision", &commodity_t::precision)
|
||||
.def_readwrite("flags", &commodity_t::flags)
|
||||
.def_readwrite("ident", &commodity_t::ident)
|
||||
.def_readwrite("updater", &commodity_t::updater)
|
||||
.add_property("smaller",
|
||||
make_getter(&commodity_t::smaller,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
.add_property("larger",
|
||||
make_getter(&commodity_t::larger,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
|
||||
.def(self_ns::str(self))
|
||||
|
||||
.def("add_price", &commodity_t::add_price)
|
||||
.def("remove_price", &commodity_t::remove_price)
|
||||
.def("value", &commodity_t::value)
|
||||
|
||||
.def("valid", &commodity_t::valid)
|
||||
;
|
||||
|
||||
def("add_commodity", &commodity_t::add_commodity);
|
||||
def("remove_commodity", &commodity_t::remove_commodity);
|
||||
def("find_commodity", py_find_commodity_1,
|
||||
return_value_policy<reference_existing_object>());
|
||||
def("find_commodity", py_find_commodity_2,
|
||||
return_value_policy<reference_existing_object>());
|
||||
|
||||
#define EXC_TRANSLATE(type) \
|
||||
register_exception_translator<type>(&exc_translate_ ## type);
|
||||
|
||||
EXC_TRANSLATE(amount_error);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
191
balance.cc
191
balance.cc
|
|
@ -86,194 +86,3 @@ void balance_t::write(std::ostream& out,
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
unsigned int balance_len(balance_t& bal)
|
||||
{
|
||||
return bal.amounts.size();
|
||||
}
|
||||
|
||||
amount_t balance_getitem(balance_t& bal, int i)
|
||||
{
|
||||
std::size_t len = bal.amounts.size();
|
||||
|
||||
if (abs(i) >= len) {
|
||||
PyErr_SetString(PyExc_IndexError, "Index out of range");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
int x = i < 0 ? len + i : i;
|
||||
amounts_map::iterator elem = bal.amounts.begin();
|
||||
while (--x >= 0)
|
||||
elem++;
|
||||
|
||||
return (*elem).second;
|
||||
}
|
||||
|
||||
unsigned int balance_pair_len(balance_pair_t& bal_pair)
|
||||
{
|
||||
return balance_len(bal_pair.quantity);
|
||||
}
|
||||
|
||||
amount_t balance_pair_getitem(balance_pair_t& bal_pair, int i)
|
||||
{
|
||||
return balance_getitem(bal_pair.quantity, i);
|
||||
}
|
||||
|
||||
void export_balance()
|
||||
{
|
||||
class_< balance_t > ("Balance")
|
||||
.def(init<balance_t>())
|
||||
.def(init<amount_t>())
|
||||
.def(init<long>())
|
||||
.def(init<unsigned long>())
|
||||
.def(init<double>())
|
||||
|
||||
.def(self += self)
|
||||
.def(self += other<amount_t>())
|
||||
.def(self += long())
|
||||
.def(self + self)
|
||||
.def(self + other<amount_t>())
|
||||
.def(self + long())
|
||||
.def(self -= self)
|
||||
.def(self -= other<amount_t>())
|
||||
.def(self -= long())
|
||||
.def(self - self)
|
||||
.def(self - other<amount_t>())
|
||||
.def(self - long())
|
||||
.def(self *= self)
|
||||
.def(self *= other<amount_t>())
|
||||
.def(self *= long())
|
||||
.def(self * self)
|
||||
.def(self * other<amount_t>())
|
||||
.def(self * long())
|
||||
.def(self /= self)
|
||||
.def(self /= other<amount_t>())
|
||||
.def(self /= long())
|
||||
.def(self / self)
|
||||
.def(self / other<amount_t>())
|
||||
.def(self / long())
|
||||
.def(- self)
|
||||
|
||||
.def(self < self)
|
||||
.def(self < other<amount_t>())
|
||||
.def(self < long())
|
||||
.def(self <= self)
|
||||
.def(self <= other<amount_t>())
|
||||
.def(self <= long())
|
||||
.def(self > self)
|
||||
.def(self > other<amount_t>())
|
||||
.def(self > long())
|
||||
.def(self >= self)
|
||||
.def(self >= other<amount_t>())
|
||||
.def(self >= long())
|
||||
.def(self == self)
|
||||
.def(self == other<amount_t>())
|
||||
.def(self == long())
|
||||
.def(self != self)
|
||||
.def(self != other<amount_t>())
|
||||
.def(self != long())
|
||||
.def(! self)
|
||||
|
||||
.def(abs(self))
|
||||
.def(self_ns::str(self))
|
||||
|
||||
.def("__len__", balance_len)
|
||||
.def("__getitem__", balance_getitem)
|
||||
|
||||
.def("negate", &balance_t::negate)
|
||||
.def("amount", &balance_t::amount)
|
||||
.def("value", &balance_t::value)
|
||||
.def("write", &balance_t::write)
|
||||
.def("valid", &balance_t::valid)
|
||||
;
|
||||
|
||||
class_< balance_pair_t > ("BalancePair")
|
||||
.def(init<balance_pair_t>())
|
||||
.def(init<balance_t>())
|
||||
.def(init<amount_t>())
|
||||
.def(init<long>())
|
||||
.def(init<unsigned long>())
|
||||
.def(init<double>())
|
||||
|
||||
.def(self += self)
|
||||
.def(self += other<balance_t>())
|
||||
.def(self += other<amount_t>())
|
||||
.def(self += long())
|
||||
.def(self + self)
|
||||
.def(self + other<balance_t>())
|
||||
.def(self + other<amount_t>())
|
||||
.def(self + long())
|
||||
.def(self -= self)
|
||||
.def(self -= other<balance_t>())
|
||||
.def(self -= other<amount_t>())
|
||||
.def(self -= long())
|
||||
.def(self - self)
|
||||
.def(self - other<balance_t>())
|
||||
.def(self - other<amount_t>())
|
||||
.def(self - long())
|
||||
.def(self *= self)
|
||||
.def(self *= other<balance_t>())
|
||||
.def(self *= other<amount_t>())
|
||||
.def(self *= long())
|
||||
.def(self * self)
|
||||
.def(self * other<balance_t>())
|
||||
.def(self * other<amount_t>())
|
||||
.def(self * long())
|
||||
.def(self /= self)
|
||||
.def(self /= other<balance_t>())
|
||||
.def(self /= other<amount_t>())
|
||||
.def(self /= long())
|
||||
.def(self / self)
|
||||
.def(self / other<balance_t>())
|
||||
.def(self / other<amount_t>())
|
||||
.def(self / long())
|
||||
.def(- self)
|
||||
|
||||
.def(self < self)
|
||||
.def(self < other<balance_t>())
|
||||
.def(self < other<amount_t>())
|
||||
.def(self < long())
|
||||
.def(self <= self)
|
||||
.def(self <= other<balance_t>())
|
||||
.def(self <= other<amount_t>())
|
||||
.def(self <= long())
|
||||
.def(self > self)
|
||||
.def(self > other<balance_t>())
|
||||
.def(self > other<amount_t>())
|
||||
.def(self > long())
|
||||
.def(self >= self)
|
||||
.def(self >= other<balance_t>())
|
||||
.def(self >= other<amount_t>())
|
||||
.def(self >= long())
|
||||
.def(self == self)
|
||||
.def(self == other<balance_t>())
|
||||
.def(self == other<amount_t>())
|
||||
.def(self == long())
|
||||
.def(self != self)
|
||||
.def(self != other<balance_t>())
|
||||
.def(self != other<amount_t>())
|
||||
.def(self != long())
|
||||
.def(! self)
|
||||
|
||||
.def(abs(self))
|
||||
.def(self_ns::str(self))
|
||||
|
||||
.def("__len__", balance_pair_len)
|
||||
.def("__getitem__", balance_pair_getitem)
|
||||
|
||||
.def("negate", &balance_pair_t::negate)
|
||||
.def("amount", &balance_pair_t::amount)
|
||||
.def("value", &balance_pair_t::value)
|
||||
.def("write", &balance_pair_t::write)
|
||||
.def("valid", &balance_pair_t::valid)
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
27
binary.cc
27
binary.cc
|
|
@ -795,30 +795,3 @@ void write_binary_journal(std::ostream& out, journal_t * journal)
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(binary_parse_overloads,
|
||||
binary_parser_t::parse, 2, 4)
|
||||
|
||||
void py_write_binary_journal(const std::string& path, journal_t * journal)
|
||||
{
|
||||
std::ofstream out(path.c_str());
|
||||
write_binary_journal(out, journal);
|
||||
}
|
||||
|
||||
void export_binary() {
|
||||
class_< binary_parser_t, bases<parser_t> > ("BinaryParser")
|
||||
.def("test", &binary_parser_t::test)
|
||||
.def("parse", &binary_parser_t::parse, binary_parse_overloads())
|
||||
;
|
||||
|
||||
def("write_binary_journal", py_write_binary_journal);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
150
config.cc
150
config.cc
|
|
@ -5,9 +5,6 @@
|
|||
#include "quotes.h"
|
||||
#include "valexpr.h"
|
||||
#include "walk.h"
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
#include "py_eval.h"
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <ctime>
|
||||
|
|
@ -43,12 +40,7 @@ void config_t::reset()
|
|||
write_hdr_format = "%d %Y%C%P\n";
|
||||
write_xact_format = " %-34W %12o%n\n";
|
||||
equity_format = "\n%D %Y%C%P\n%/ %-34W %12t\n";
|
||||
#ifndef USE_BOOST_PYTHON
|
||||
prices_format = "%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n";
|
||||
#else
|
||||
prices_format = ("%[%Y/%m/%d %H:%M:%S %Z] %-8A "
|
||||
"%10t %10(@vmin(t)) %10(@vmax(t)) %12T\n");
|
||||
#endif
|
||||
pricesdb_format = "P %[%Y/%m/%d %H:%M:%S] %A %t\n";
|
||||
|
||||
predicate = "";
|
||||
|
|
@ -444,9 +436,6 @@ static void show_version(std::ostream& out)
|
|||
This program is made available under the terms of the BSD Public License.\n\
|
||||
See LICENSE file included with the distribution for details and disclaimer.\n";
|
||||
out << "\n(modules: gmp, pcre";
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
out << ", python";
|
||||
#endif
|
||||
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
out << ", xml";
|
||||
#endif
|
||||
|
|
@ -523,12 +512,6 @@ Commodity reporting:\n\
|
|||
-V, --market report last known market value\n\
|
||||
-g, --performance report gain/loss for each displayed transaction\n\
|
||||
-G, --gain report net gain/loss\n\n";
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
out
|
||||
<< "Python support:\n\
|
||||
--import MODULE on startup, import the given Python MODULE\n\
|
||||
--import-stdin on start, read Python code from standard input\n\n";
|
||||
#endif
|
||||
out
|
||||
<< "Commands:\n\
|
||||
balance [REGEXP]... show balance totals for matching accounts\n\
|
||||
|
|
@ -547,9 +530,6 @@ Use -H to see all the help text on one page, or:\n\
|
|||
--help-calc calculation options\n\
|
||||
--help-disp display options\n\
|
||||
--help-comm commodity options\n";
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
out << " --help-python Python options\n";
|
||||
#endif
|
||||
out << "\nBasic options:\n\
|
||||
-h, --help display this help text\n\
|
||||
-v, --version show version information\n\
|
||||
|
|
@ -635,15 +615,6 @@ void option_comm_help(std::ostream& out)
|
|||
-G, --gain report net gain/loss\n";
|
||||
}
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
void option_python_help(std::ostream& out)
|
||||
{
|
||||
out << "Python support options:\n\
|
||||
--import MODULE on startup, import the given Python MODULE\n\
|
||||
--import-stdin on start, read Python code from standard input\n\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Basic options
|
||||
|
|
@ -673,13 +644,6 @@ OPT_BEGIN(help_comm, "") {
|
|||
throw 0;
|
||||
} OPT_END(help_comm);
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
OPT_BEGIN(help_python, "") {
|
||||
option_python_help(std::cout);
|
||||
throw 0;
|
||||
} OPT_END(help_python);
|
||||
#endif
|
||||
|
||||
OPT_BEGIN(version, "v") {
|
||||
show_version(std::cout);
|
||||
throw 0;
|
||||
|
|
@ -1076,118 +1040,4 @@ OPT_BEGIN(percentage, "%") {
|
|||
config->total_expr_template = "^#&{100.0%}*(#/^#)";
|
||||
} OPT_END(percentage);
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Python support
|
||||
|
||||
OPT_BEGIN(import, ":") {
|
||||
python_eval(std::string("import ") + optarg, PY_EVAL_STMT);
|
||||
} OPT_END(import);
|
||||
|
||||
OPT_BEGIN(import_stdin, "") {
|
||||
python_eval(std::cin, PY_EVAL_MULTI);
|
||||
} OPT_END(import_stdin);
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/detail/api_placeholder.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
void py_process_options(config_t& config, const std::string& command,
|
||||
list args)
|
||||
{
|
||||
strings_list strs;
|
||||
|
||||
int l = len(args);
|
||||
for (int i = 0; i < l; i++)
|
||||
strs.push_back(std::string(extract<char *>(args[i])));
|
||||
|
||||
config.process_options(command, strs.begin(), strs.end());
|
||||
}
|
||||
|
||||
void add_other_option_handlers(const std::list<option_t>& other);
|
||||
|
||||
void py_add_config_option_handlers()
|
||||
{
|
||||
add_other_option_handlers(config_options);
|
||||
}
|
||||
|
||||
void py_option_help()
|
||||
{
|
||||
option_help(std::cout);
|
||||
}
|
||||
|
||||
void export_config()
|
||||
{
|
||||
class_< config_t > ("Config")
|
||||
.def_readwrite("init_file", &config_t::init_file)
|
||||
.def_readwrite("data_file", &config_t::data_file)
|
||||
.def_readwrite("cache_file", &config_t::cache_file)
|
||||
.def_readwrite("price_db", &config_t::price_db)
|
||||
.def_readwrite("output_file", &config_t::output_file)
|
||||
.def_readwrite("account", &config_t::account)
|
||||
.def_readwrite("predicate", &config_t::predicate)
|
||||
.def_readwrite("display_predicate", &config_t::display_predicate)
|
||||
.def_readwrite("report_period", &config_t::report_period)
|
||||
.def_readwrite("report_period_sort", &config_t::report_period_sort)
|
||||
.def_readwrite("format_string", &config_t::format_string)
|
||||
.def_readwrite("balance_format", &config_t::balance_format)
|
||||
.def_readwrite("register_format", &config_t::register_format)
|
||||
.def_readwrite("wide_register_format", &config_t::wide_register_format)
|
||||
.def_readwrite("csv_register_format", &config_t::csv_register_format)
|
||||
.def_readwrite("plot_amount_format", &config_t::plot_amount_format)
|
||||
.def_readwrite("plot_total_format", &config_t::plot_total_format)
|
||||
.def_readwrite("print_format", &config_t::print_format)
|
||||
.def_readwrite("write_hdr_format", &config_t::write_hdr_format)
|
||||
.def_readwrite("write_xact_format", &config_t::write_xact_format)
|
||||
.def_readwrite("equity_format", &config_t::equity_format)
|
||||
.def_readwrite("prices_format", &config_t::prices_format)
|
||||
.def_readwrite("pricesdb_format", &config_t::pricesdb_format)
|
||||
.def_readwrite("date_format", &config_t::date_format)
|
||||
.def_readwrite("sort_string", &config_t::sort_string)
|
||||
.def_readwrite("amount_expr", &config_t::amount_expr)
|
||||
.def_readwrite("total_expr", &config_t::total_expr)
|
||||
.def_readwrite("total_expr_template", &config_t::total_expr_template)
|
||||
.def_readwrite("forecast_limit", &config_t::forecast_limit)
|
||||
.def_readwrite("reconcile_balance", &config_t::reconcile_balance)
|
||||
.def_readwrite("reconcile_date", &config_t::reconcile_date)
|
||||
.def_readwrite("budget_flags", &config_t::budget_flags)
|
||||
.def_readwrite("pricing_leeway", &config_t::pricing_leeway)
|
||||
.def_readwrite("show_collapsed", &config_t::show_collapsed)
|
||||
.def_readwrite("show_subtotal", &config_t::show_subtotal)
|
||||
.def_readwrite("show_totals", &config_t::show_totals)
|
||||
.def_readwrite("show_related", &config_t::show_related)
|
||||
.def_readwrite("show_all_related", &config_t::show_all_related)
|
||||
.def_readwrite("show_inverted", &config_t::show_inverted)
|
||||
.def_readwrite("show_empty", &config_t::show_empty)
|
||||
.def_readwrite("head_entries", &config_t::head_entries)
|
||||
.def_readwrite("tail_entries", &config_t::tail_entries)
|
||||
.def_readwrite("pager", &config_t::pager)
|
||||
.def_readwrite("days_of_the_week", &config_t::days_of_the_week)
|
||||
.def_readwrite("by_payee", &config_t::by_payee)
|
||||
.def_readwrite("comm_as_payee", &config_t::comm_as_payee)
|
||||
.def_readwrite("show_revalued", &config_t::show_revalued)
|
||||
.def_readwrite("show_revalued_only", &config_t::show_revalued_only)
|
||||
.def_readwrite("download_quotes", &config_t::download_quotes)
|
||||
.def_readwrite("use_cache", &config_t::use_cache)
|
||||
.def_readwrite("cache_dirty", &config_t::cache_dirty)
|
||||
|
||||
.def("process_options", py_process_options)
|
||||
;
|
||||
|
||||
scope().attr("config") = ptr(config);
|
||||
|
||||
def("option_help", py_option_help);
|
||||
def("add_config_option_handlers", py_add_config_option_handlers);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
40
configure.in
40
configure.in
|
|
@ -187,46 +187,6 @@ else
|
|||
AM_CONDITIONAL(HAVE_LIBOFX, false)
|
||||
fi
|
||||
|
||||
# check for Python
|
||||
AC_ARG_ENABLE(python,
|
||||
[ --enable-python Turn on Python support],
|
||||
[case "${enableval}" in
|
||||
yes) python=true ;;
|
||||
no) python=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-python) ;;
|
||||
esac],[python=false])
|
||||
AM_CONDITIONAL(USE_PYTHON, test x$python = xtrue)
|
||||
|
||||
if [test x$python = xtrue ]; then
|
||||
AM_PATH_PYTHON(2.2,, :)
|
||||
if [test "$PYTHON" != :]; then
|
||||
AC_CACHE_CHECK(
|
||||
[if boost_python is available],
|
||||
[boost_python_cpplib_avail],
|
||||
[boost_python_save_libs=$LIBS
|
||||
LIBS="-lboost_python -lpython$PYTHON_VERSION $LIBS"
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_TRY_LINK(
|
||||
[#include <boost/python.hpp>
|
||||
using namespace boost::python;
|
||||
class foo {};
|
||||
BOOST_PYTHON_MODULE(samp) {
|
||||
class_< foo > ("foo") ;
|
||||
}],
|
||||
[return 0],
|
||||
[boost_python_cpplib_avail=true],
|
||||
[boost_python_cpplib_avail=false])
|
||||
AC_LANG_POP
|
||||
LIBS=$boost_python_save_libs])
|
||||
AM_CONDITIONAL(HAVE_BOOST_PYTHON,
|
||||
test x$boost_python_cpplib_avail = xtrue)
|
||||
else
|
||||
AM_CONDITIONAL(HAVE_BOOST_PYTHON, false)
|
||||
fi
|
||||
else
|
||||
AM_CONDITIONAL(HAVE_BOOST_PYTHON, false)
|
||||
fi
|
||||
|
||||
# Check for options
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --enable-debug Turn on debugging],
|
||||
|
|
|
|||
79
datetime.cc
79
datetime.cc
|
|
@ -373,82 +373,3 @@ bool quick_parse_date(const char * date_str, std::time_t * result)
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
unsigned int interval_len(interval_t& interval)
|
||||
{
|
||||
int periods = 1;
|
||||
std::time_t when = interval.first();
|
||||
while (interval.end && when < interval.end) {
|
||||
when = interval.increment(when);
|
||||
if (when < interval.end)
|
||||
periods++;
|
||||
}
|
||||
return periods;
|
||||
}
|
||||
|
||||
std::time_t interval_getitem(interval_t& interval, int i)
|
||||
{
|
||||
static std::time_t last_index = 0;
|
||||
static std::time_t last_moment = 0;
|
||||
|
||||
if (i == 0) {
|
||||
last_index = 0;
|
||||
last_moment = interval.first();
|
||||
}
|
||||
else {
|
||||
last_moment = interval.increment(last_moment);
|
||||
if (interval.end && last_moment >= interval.end) {
|
||||
PyErr_SetString(PyExc_IndexError, "Index out of range");
|
||||
throw_error_already_set();
|
||||
}
|
||||
}
|
||||
return last_moment;
|
||||
}
|
||||
|
||||
std::time_t py_parse_date(const char * date_str)
|
||||
{
|
||||
std::time_t temp;
|
||||
if (parse_date(date_str, &temp))
|
||||
return temp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::time_t py_parse_date_yr(const char * date_str, const int year)
|
||||
{
|
||||
std::time_t temp;
|
||||
if (parse_date(date_str, &temp, year))
|
||||
return temp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void export_datetime()
|
||||
{
|
||||
class_< interval_t >
|
||||
("Interval", init<optional<int, int, int, std::time_t, std::time_t> >())
|
||||
.def(init<std::string>())
|
||||
.def(! self)
|
||||
|
||||
.def_readwrite("years", &interval_t::years)
|
||||
.def_readwrite("months", &interval_t::months)
|
||||
.def_readwrite("seconds", &interval_t::seconds)
|
||||
.def_readwrite("begin", &interval_t::begin)
|
||||
.def_readwrite("end", &interval_t::end)
|
||||
|
||||
.def("__len__", interval_len)
|
||||
.def("__getitem__", interval_getitem)
|
||||
|
||||
.def("increment", &interval_t::increment)
|
||||
;
|
||||
|
||||
def("parse_date", py_parse_date);
|
||||
def("parse_date", py_parse_date_yr);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
27
derive.cc
27
derive.cc
|
|
@ -132,30 +132,3 @@ entry_t * derive_new_entry(journal_t& journal,
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/detail/api_placeholder.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
entry_t * py_derive_new_entry(journal_t& journal, list args)
|
||||
{
|
||||
strings_list strs;
|
||||
|
||||
int l = len(args);
|
||||
for (int i = 0; i < l; i++)
|
||||
strs.push_back(extract<std::string>(args[i]));
|
||||
|
||||
return derive_new_entry(journal, strs.begin(), strs.end());
|
||||
}
|
||||
|
||||
void export_derive()
|
||||
{
|
||||
def("derive_new_entry", py_derive_new_entry,
|
||||
return_value_policy<manage_new_object>());
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
23
emacs.cc
23
emacs.cc
|
|
@ -77,26 +77,3 @@ void format_emacs_transactions::operator()(transaction_t& xact)
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
void export_emacs()
|
||||
{
|
||||
typedef
|
||||
pystream_handler_wrap<format_emacs_transactions, transaction_t>
|
||||
format_emacs_transactions_wrap;
|
||||
|
||||
class_< format_emacs_transactions_wrap, bases<item_handler<transaction_t> > >
|
||||
("FormatEmacsTransactions",
|
||||
init<PyObject *>()[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &format_emacs_transactions_wrap::flush)
|
||||
.def("__call__", &format_emacs_transactions_wrap::operator())
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
117
format.cc
117
format.cc
|
|
@ -1,9 +1,6 @@
|
|||
#include "format.h"
|
||||
#include "error.h"
|
||||
#include "util.h"
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
#include "py_eval.h"
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
|
@ -175,18 +172,6 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
|||
break;
|
||||
}
|
||||
|
||||
case '@': {
|
||||
const char * s = ++p;
|
||||
while (*p && *p != '(')
|
||||
p++;
|
||||
if (*p && *++p != ')')
|
||||
throw format_error("Missing ')'");
|
||||
|
||||
current->type = element_t::INTERP_FUNC;
|
||||
current->chars = std::string(s, (p - s) - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case '[': {
|
||||
++p;
|
||||
const char * b = p;
|
||||
|
|
@ -585,20 +570,6 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
|||
}
|
||||
break;
|
||||
|
||||
case element_t::INTERP_FUNC:
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
try {
|
||||
object func = python_eval(elem->chars);
|
||||
out << call<std::string>(func.ptr(), details);
|
||||
}
|
||||
catch(const boost::python::error_already_set&) {
|
||||
PyErr_Print();
|
||||
throw format_error(std::string("While calling Python function '") +
|
||||
elem->chars + "'");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
|
|
@ -842,91 +813,3 @@ void format_equity::operator()(account_t& account)
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
std::string py_format_1(format_t& format, const details_t& item)
|
||||
{
|
||||
std::ostringstream out;
|
||||
format.format(out, item);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string py_format(format_t& format, const T& item)
|
||||
{
|
||||
std::ostringstream out;
|
||||
format.format(out, details_t(item));
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void export_format()
|
||||
{
|
||||
typedef
|
||||
pystream_handler_wrap<format_transactions, transaction_t, std::string>
|
||||
format_transactions_wrap;
|
||||
|
||||
class_< format_transactions_wrap, bases<item_handler<transaction_t> > >
|
||||
("FormatTransactions",
|
||||
init<PyObject *, std::string>()[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &format_transactions_wrap::flush)
|
||||
.def("__call__", &format_transactions_wrap::operator())
|
||||
;
|
||||
|
||||
typedef
|
||||
pystream_handler_wrap<format_entries, transaction_t, std::string>
|
||||
format_entries_wrap;
|
||||
|
||||
class_< format_entries_wrap, bases<item_handler<transaction_t> > >
|
||||
("FormatEntries",
|
||||
init<PyObject *, std::string>()[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &format_entries_wrap::flush)
|
||||
.def("__call__", &format_entries_wrap::operator())
|
||||
;
|
||||
|
||||
typedef
|
||||
pystream_handler_wrap<format_account, account_t, std::string, std::string>
|
||||
format_account_wrap;
|
||||
|
||||
class_< format_account_wrap, bases<item_handler<transaction_t> > >
|
||||
("FormatAccount",
|
||||
init<PyObject *, std::string, std::string>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &format_account_wrap::flush)
|
||||
.def("__call__", &format_account_wrap::operator())
|
||||
;
|
||||
|
||||
typedef
|
||||
pystream_handler_wrap<format_equity, account_t, std::string, std::string>
|
||||
format_equity_wrap;
|
||||
|
||||
class_< format_equity_wrap, bases<item_handler<transaction_t> > >
|
||||
("FormatEquity",
|
||||
init<PyObject *, std::string, std::string>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &format_equity_wrap::flush)
|
||||
.def("__call__", &format_equity_wrap::operator())
|
||||
;
|
||||
|
||||
class_< format_t > ("Format")
|
||||
.def(init<std::string>())
|
||||
.def("reset", &format_t::reset)
|
||||
.def("format", py_format_1)
|
||||
.def("format", py_format<account_t>)
|
||||
.def("format", py_format<entry_t>)
|
||||
.def("format", py_format<transaction_t>)
|
||||
;
|
||||
|
||||
def("truncated", truncated);
|
||||
#if 0
|
||||
def("partial_account_name", partial_account_name);
|
||||
#endif
|
||||
def("display_account", display_account);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
41
format.h
41
format.h
|
|
@ -38,8 +38,7 @@ struct element_t
|
|||
NOTE,
|
||||
OPT_NOTE,
|
||||
SPACER,
|
||||
DEPTH_SPACER,
|
||||
INTERP_FUNC
|
||||
DEPTH_SPACER
|
||||
};
|
||||
|
||||
bool align_left;
|
||||
|
|
@ -189,40 +188,4 @@ class format_equity : public item_handler<account_t>
|
|||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include "pyfstream.h"
|
||||
|
||||
template <typename T, typename U, typename V = int, typename W = int>
|
||||
struct pystream_handler_wrap : public ledger::item_handler<U>
|
||||
{
|
||||
PyFileObject * file;
|
||||
pyofstream * output;
|
||||
|
||||
T handler;
|
||||
|
||||
pystream_handler_wrap(PyObject * file_)
|
||||
: file((PyFileObject *)file_), output(new pyofstream(file)),
|
||||
handler(*output) {}
|
||||
pystream_handler_wrap(PyObject * file_, const V& arg)
|
||||
: file((PyFileObject *)file_), output(new pyofstream(file)),
|
||||
handler(*output, arg) {}
|
||||
pystream_handler_wrap(PyObject * file_, const V& arg1, const W& arg2)
|
||||
: file((PyFileObject *)file_), output(new pyofstream(file)),
|
||||
handler(*output, arg1, arg2) {}
|
||||
|
||||
virtual ~pystream_handler_wrap() {
|
||||
delete output;
|
||||
}
|
||||
|
||||
virtual void flush() {
|
||||
handler.flush();
|
||||
}
|
||||
virtual void operator()(U& item) {
|
||||
handler.operator()(item);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
||||
#endif // _REPORT_H
|
||||
#endif // _FORMAT_H
|
||||
|
|
|
|||
19
gnucash.cc
19
gnucash.cc
|
|
@ -415,22 +415,3 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(gnucash_parse_overloads,
|
||||
gnucash_parser_t::parse, 2, 4)
|
||||
|
||||
void export_gnucash() {
|
||||
class_< gnucash_parser_t, bases<parser_t> > ("GnucashParser")
|
||||
.def("test", &gnucash_parser_t::test)
|
||||
.def("parse", &gnucash_parser_t::parse, gnucash_parse_overloads())
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
366
journal.cc
366
journal.cc
|
|
@ -3,9 +3,6 @@
|
|||
#include "valexpr.h"
|
||||
#include "mask.h"
|
||||
#include "error.h"
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
#include "py_eval.h"
|
||||
#endif
|
||||
#include "acconf.h"
|
||||
|
||||
#include <fstream>
|
||||
|
|
@ -290,14 +287,6 @@ void auto_entry_t::extend_entry(entry_base_t& entry)
|
|||
|
||||
if (fullname == "$account")
|
||||
account = (*i)->account;
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
else if (fullname[0] == '@') {
|
||||
value_expr_t * expr = parse_value_expr(fullname);
|
||||
if (expr->kind == value_expr_t::F_INTERP_FUNC)
|
||||
python_call(expr->constant_s, expr->right, details_t(**i),
|
||||
*(*t)->account);
|
||||
}
|
||||
#endif
|
||||
|
||||
transaction_t * xact
|
||||
= new transaction_t(account, amt, (*t)->flags | TRANSACTION_AUTO);
|
||||
|
|
@ -525,358 +514,3 @@ bool journal_t::valid() const
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/exception_translator.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
entry_t& transaction_entry(const transaction_t& xact)
|
||||
{
|
||||
return *xact.entry;
|
||||
}
|
||||
|
||||
unsigned int transactions_len(entry_base_t& entry)
|
||||
{
|
||||
return entry.transactions.size();
|
||||
}
|
||||
|
||||
transaction_t& transactions_getitem(entry_base_t& entry, int i)
|
||||
{
|
||||
static int last_index = 0;
|
||||
static entry_base_t * last_entry = NULL;
|
||||
static transactions_list::iterator elem;
|
||||
|
||||
std::size_t len = entry.transactions.size();
|
||||
|
||||
if (abs(i) >= len) {
|
||||
PyErr_SetString(PyExc_IndexError, "Index out of range");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
if (&entry == last_entry && i == last_index + 1) {
|
||||
last_index = i;
|
||||
return **++elem;
|
||||
}
|
||||
|
||||
int x = i < 0 ? len + i : i;
|
||||
elem = entry.transactions.begin();
|
||||
while (--x >= 0)
|
||||
elem++;
|
||||
|
||||
last_entry = &entry;
|
||||
last_index = i;
|
||||
|
||||
return **elem;
|
||||
}
|
||||
|
||||
unsigned int entries_len(journal_t& journal)
|
||||
{
|
||||
return journal.entries.size();
|
||||
}
|
||||
|
||||
entry_t& entries_getitem(journal_t& journal, int i)
|
||||
{
|
||||
static int last_index = 0;
|
||||
static journal_t * last_journal = NULL;
|
||||
static entries_list::iterator elem;
|
||||
|
||||
std::size_t len = journal.entries.size();
|
||||
|
||||
if (abs(i) >= len) {
|
||||
PyErr_SetString(PyExc_IndexError, "Index out of range");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
if (&journal == last_journal && i == last_index + 1) {
|
||||
last_index = i;
|
||||
return **++elem;
|
||||
}
|
||||
|
||||
int x = i < 0 ? len + i : i;
|
||||
elem = journal.entries.begin();
|
||||
while (--x >= 0)
|
||||
elem++;
|
||||
|
||||
last_journal = &journal;
|
||||
last_index = i;
|
||||
|
||||
return **elem;
|
||||
}
|
||||
|
||||
unsigned int accounts_len(account_t& account)
|
||||
{
|
||||
return account.accounts.size();
|
||||
}
|
||||
|
||||
account_t& accounts_getitem(account_t& account, int i)
|
||||
{
|
||||
static int last_index = 0;
|
||||
static account_t * last_account = NULL;
|
||||
static accounts_map::iterator elem;
|
||||
|
||||
std::size_t len = account.accounts.size();
|
||||
|
||||
if (abs(i) >= len) {
|
||||
PyErr_SetString(PyExc_IndexError, "Index out of range");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
if (&account == last_account && i == last_index + 1) {
|
||||
last_index = i;
|
||||
return *(*++elem).second;
|
||||
}
|
||||
|
||||
int x = i < 0 ? len + i : i;
|
||||
elem = account.accounts.begin();
|
||||
while (--x >= 0)
|
||||
elem++;
|
||||
|
||||
last_account = &account;
|
||||
last_index = i;
|
||||
|
||||
return *(*elem).second;
|
||||
}
|
||||
|
||||
PyObject * py_account_get_data(account_t& account)
|
||||
{
|
||||
return (PyObject *) account.data;
|
||||
}
|
||||
|
||||
void py_account_set_data(account_t& account, PyObject * obj)
|
||||
{
|
||||
account.data = obj;
|
||||
}
|
||||
|
||||
account_t * py_find_account_1(journal_t& journal, const std::string& name)
|
||||
{
|
||||
return journal.find_account(name);
|
||||
}
|
||||
|
||||
account_t * py_find_account_2(journal_t& journal, const std::string& name,
|
||||
const bool auto_create)
|
||||
{
|
||||
return journal.find_account(name, auto_create);
|
||||
}
|
||||
|
||||
bool py_add_entry(journal_t& journal, entry_t * entry) {
|
||||
return journal.add_entry(new entry_t(*entry));
|
||||
}
|
||||
|
||||
void py_add_transaction(entry_base_t& entry, transaction_t * xact) {
|
||||
return entry.add_transaction(new transaction_t(*xact));
|
||||
}
|
||||
|
||||
struct entry_base_wrap : public entry_base_t
|
||||
{
|
||||
PyObject * self;
|
||||
entry_base_wrap(PyObject * self_) : self(self_) {}
|
||||
|
||||
virtual bool valid() const {
|
||||
return call_method<bool>(self, "valid");
|
||||
}
|
||||
};
|
||||
|
||||
struct py_entry_finalizer_t : public entry_finalizer_t {
|
||||
object pyobj;
|
||||
py_entry_finalizer_t() {}
|
||||
py_entry_finalizer_t(object obj) : pyobj(obj) {}
|
||||
py_entry_finalizer_t(const py_entry_finalizer_t& other)
|
||||
: pyobj(other.pyobj) {}
|
||||
virtual bool operator()(entry_t& entry) {
|
||||
return call<bool>(pyobj.ptr(), entry);
|
||||
}
|
||||
};
|
||||
|
||||
std::list<py_entry_finalizer_t> py_finalizers;
|
||||
|
||||
void py_add_entry_finalizer(journal_t& journal, object x)
|
||||
{
|
||||
py_finalizers.push_back(py_entry_finalizer_t(x));
|
||||
journal.add_entry_finalizer(&py_finalizers.back());
|
||||
}
|
||||
|
||||
void py_remove_entry_finalizer(journal_t& journal, object x)
|
||||
{
|
||||
for (std::list<py_entry_finalizer_t>::iterator i = py_finalizers.begin();
|
||||
i != py_finalizers.end();
|
||||
i++)
|
||||
if ((*i).pyobj == x) {
|
||||
journal.remove_entry_finalizer(&(*i));
|
||||
py_finalizers.erase(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void py_run_entry_finalizers(journal_t& journal, entry_t& entry)
|
||||
{
|
||||
run_hooks(journal.entry_finalize_hooks, entry);
|
||||
}
|
||||
|
||||
#define EXC_TRANSLATOR(type) \
|
||||
void exc_translate_ ## type(const type& err) { \
|
||||
PyErr_SetString(PyExc_RuntimeError, err.what()); \
|
||||
}
|
||||
|
||||
EXC_TRANSLATOR(error)
|
||||
EXC_TRANSLATOR(interval_expr_error)
|
||||
EXC_TRANSLATOR(format_error)
|
||||
EXC_TRANSLATOR(parse_error)
|
||||
|
||||
void export_journal()
|
||||
{
|
||||
scope().attr("TRANSACTION_NORMAL") = TRANSACTION_NORMAL;
|
||||
scope().attr("TRANSACTION_VIRTUAL") = TRANSACTION_VIRTUAL;
|
||||
scope().attr("TRANSACTION_BALANCE") = TRANSACTION_BALANCE;
|
||||
scope().attr("TRANSACTION_AUTO") = TRANSACTION_AUTO;
|
||||
scope().attr("TRANSACTION_BULK_ALLOC") = TRANSACTION_BULK_ALLOC;
|
||||
|
||||
class_< transaction_t > ("Transaction")
|
||||
.def(init<account_t *, amount_t, optional<unsigned int, std::string> >())
|
||||
|
||||
.def(self == self)
|
||||
.def(self != self)
|
||||
|
||||
.add_property("entry",
|
||||
make_getter(&transaction_t::entry,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
.add_property("account",
|
||||
make_getter(&transaction_t::account,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
.def_readwrite("amount", &transaction_t::amount)
|
||||
.add_property("cost",
|
||||
make_getter(&transaction_t::cost,
|
||||
return_internal_reference<1>()))
|
||||
.def_readwrite("state", &transaction_t::state)
|
||||
.def_readwrite("flags", &transaction_t::flags)
|
||||
.def_readwrite("note", &transaction_t::note)
|
||||
#if 0
|
||||
.def_readwrite("data", &transaction_t::data)
|
||||
#endif
|
||||
|
||||
.def("valid", &transaction_t::valid)
|
||||
;
|
||||
|
||||
enum_< transaction_t::state_t > ("State")
|
||||
.value("UNCLEARED", transaction_t::UNCLEARED)
|
||||
.value("CLEARED", transaction_t::CLEARED)
|
||||
.value("PENDING", transaction_t::PENDING)
|
||||
;
|
||||
|
||||
class_< account_t >
|
||||
("Account",
|
||||
init<optional<account_t *, std::string, std::string> >()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def(self == self)
|
||||
.def(self != self)
|
||||
|
||||
.def_readonly("journal", &account_t::journal)
|
||||
.add_property("parent",
|
||||
make_getter(&account_t::parent,
|
||||
return_internal_reference<1>()))
|
||||
.def_readwrite("name", &account_t::name)
|
||||
.def_readwrite("note", &account_t::note)
|
||||
.def_readonly("depth", &account_t::depth)
|
||||
.add_property("data", py_account_get_data, py_account_set_data)
|
||||
.def_readonly("ident", &account_t::ident)
|
||||
|
||||
.def(self_ns::str(self))
|
||||
|
||||
.def("fullname", &account_t::fullname)
|
||||
.def("add_account", &account_t::add_account)
|
||||
.def("remove_account", &account_t::remove_account)
|
||||
.def("find_account", &account_t::find_account,
|
||||
return_value_policy<reference_existing_object>())
|
||||
|
||||
.def("valid", &account_t::valid)
|
||||
;
|
||||
|
||||
class_< journal_t > ("Journal")
|
||||
.def(self == self)
|
||||
.def(self != self)
|
||||
|
||||
.add_property("master",
|
||||
make_getter(&journal_t::master,
|
||||
return_internal_reference<1>()))
|
||||
.add_property("basket",
|
||||
make_getter(&journal_t::basket,
|
||||
return_internal_reference<1>()))
|
||||
.def_readwrite("price_db", &journal_t::price_db)
|
||||
.def_readonly("sources", &journal_t::sources)
|
||||
|
||||
.def("__len__", entries_len)
|
||||
.def("__getitem__", entries_getitem, return_internal_reference<1>())
|
||||
.def("add_account", &journal_t::add_account)
|
||||
.def("remove_account", &journal_t::remove_account)
|
||||
.def("find_account", py_find_account_1, return_internal_reference<1>())
|
||||
.def("find_account", py_find_account_2, return_internal_reference<1>())
|
||||
.def("find_account_re", &journal_t::find_account_re,
|
||||
return_internal_reference<1>())
|
||||
|
||||
.def("add_entry", py_add_entry)
|
||||
.def("remove_entry", &journal_t::remove_entry)
|
||||
.def("add_entry_finalizer", py_add_entry_finalizer)
|
||||
.def("remove_entry_finalizer", py_remove_entry_finalizer)
|
||||
.def("run_entry_finalizers", py_run_entry_finalizers)
|
||||
|
||||
.def("valid", &journal_t::valid)
|
||||
;
|
||||
|
||||
class_< entry_base_t, entry_base_wrap, boost::noncopyable > ("EntryBase")
|
||||
.def("__len__", transactions_len)
|
||||
.def("__getitem__", transactions_getitem,
|
||||
return_internal_reference<1>())
|
||||
|
||||
.def_readonly("journal", &entry_base_t::journal)
|
||||
.def_readonly("src_idx", &entry_base_t::src_idx)
|
||||
.def_readonly("beg_pos", &entry_base_t::beg_pos)
|
||||
.def_readonly("beg_line", &entry_base_t::beg_line)
|
||||
.def_readonly("end_pos", &entry_base_t::end_pos)
|
||||
.def_readonly("end_line", &entry_base_t::end_line)
|
||||
|
||||
.def("add_transaction", py_add_transaction)
|
||||
.def("remove_transaction", &entry_base_t::remove_transaction)
|
||||
|
||||
.def(self == self)
|
||||
.def(self != self)
|
||||
|
||||
.def("valid", &entry_base_t::valid)
|
||||
;
|
||||
|
||||
scope in_entry = class_< entry_t, bases<entry_base_t> > ("Entry")
|
||||
.def_readwrite("date", &entry_t::date)
|
||||
.def_readwrite("code", &entry_t::code)
|
||||
.def_readwrite("payee", &entry_t::payee)
|
||||
|
||||
.def("valid", &entry_t::valid)
|
||||
;
|
||||
|
||||
class_< auto_entry_t, bases<entry_base_t> > ("AutoEntry")
|
||||
.add_property("predicate",
|
||||
make_getter(&auto_entry_t::predicate,
|
||||
return_internal_reference<1>()))
|
||||
.def_readonly("predicate_string", &auto_entry_t::predicate_string)
|
||||
|
||||
.def("valid", &auto_entry_t::valid)
|
||||
;
|
||||
|
||||
class_< period_entry_t, bases<entry_base_t> > ("PeriodEntry")
|
||||
.def_readonly("period", &period_entry_t::period)
|
||||
.def_readonly("period_string", &period_entry_t::period_string)
|
||||
|
||||
.def("valid", &period_entry_t::valid)
|
||||
;
|
||||
|
||||
#define EXC_TRANSLATE(type) \
|
||||
register_exception_translator<type>(&exc_translate_ ## type);
|
||||
|
||||
EXC_TRANSLATE(error);
|
||||
EXC_TRANSLATE(interval_expr_error);
|
||||
EXC_TRANSLATE(format_error);
|
||||
EXC_TRANSLATE(parse_error);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
47
ledger.texi
47
ledger.texi
|
|
@ -64,7 +64,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* Running Ledger::
|
||||
* Keeping a ledger::
|
||||
* Using XML::
|
||||
* Extending with Python::
|
||||
@end menu
|
||||
|
||||
@node Introduction, Running Ledger, Top, Top
|
||||
|
|
@ -2260,14 +2259,6 @@ precedence order of operators.
|
|||
@item [DATE]
|
||||
Useful specifying a date in plain terms. For example, you could say
|
||||
@samp{[2004/06/01]}.
|
||||
|
||||
@item @@STR(ARGS,...)
|
||||
If Python support is compiled in, this calls the Python function
|
||||
@code{STR}. It is always be passed at least one argument, of type
|
||||
@var{ledger.Details}, representing the known account, entry, and
|
||||
transaction details at the time the value expression is computed.
|
||||
Other value expression arguments may also be passed by the user, all
|
||||
of type @var{Value}.
|
||||
@end table
|
||||
|
||||
@node Period expressions, File format, Value expressions, Running Ledger
|
||||
|
|
@ -2431,13 +2422,6 @@ transactions that follow, until @samp{!end} is seen.
|
|||
|
||||
@item !end
|
||||
Ends an account block.
|
||||
|
||||
@item !python
|
||||
If Python support is available, all of the lines following
|
||||
@samp{!python} will be passed to the Python interpretor. Any
|
||||
functions defined will be available to later Python blocks, and can be
|
||||
called from a value expression. The Python code block must be ended
|
||||
with @samp{!end}.
|
||||
@end table
|
||||
|
||||
@item ;
|
||||
|
|
@ -3699,8 +3683,8 @@ description is a ledger account name, these in/out pairs may be viewed
|
|||
as virtual transactions, adding time commodities (hours) to that
|
||||
account.
|
||||
|
||||
For example, the command-line version of the timeclock tool (which is
|
||||
written in Python) could be used to begin a timelog file like:
|
||||
For example, the command-line version of the timeclock tool could be
|
||||
used to begin a timelog file like:
|
||||
|
||||
@example
|
||||
export TIMELOG=$HOME/.timelog
|
||||
|
|
@ -3778,7 +3762,7 @@ accounting ledger, with the attached prefix @samp{Billable}:
|
|||
Receivable:ClientOne
|
||||
@end smallexample
|
||||
|
||||
@node Using XML, Extending with Python, Keeping a ledger, Top
|
||||
@node Using XML, , Keeping a ledger, Top
|
||||
@chapter Using XML
|
||||
|
||||
By default, Ledger uses a human-readable data format, and displays its
|
||||
|
|
@ -3930,29 +3914,4 @@ output such data if the @command{xml} command is used, and can read
|
|||
the same data as long as the @file{expat} library was available
|
||||
when Ledger was built.
|
||||
|
||||
@node Extending with Python, , Using XML, Top
|
||||
@chapter Extending with Python
|
||||
|
||||
Ledger fully supports Python as an extension language. It may be used
|
||||
in a few different forms, which fall into three basic categories:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Defining Python functions to use in value expressions
|
||||
@item
|
||||
Using the ledger library as a Python module
|
||||
@item
|
||||
Setting up custom initialization using Python
|
||||
@end enumerate
|
||||
|
||||
Note that this feature, while functional, is still under development.
|
||||
It will not be documented until it has been fully proven, probably in
|
||||
the next version of ledger. For now, if you wish to make this of this
|
||||
functionality and are willing to debug problems that come up, pass the
|
||||
option @samp{--enable-python} to configure, and contact the author via
|
||||
email.
|
||||
|
||||
One example of using Python to create a more complex report is in the
|
||||
script file @file{scripts/trend}.
|
||||
|
||||
@bye
|
||||
|
|
|
|||
30
main.cc
30
main.cc
|
|
@ -18,9 +18,6 @@
|
|||
#endif
|
||||
|
||||
#include "ledger.h"
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
#include "py_eval.h"
|
||||
#endif
|
||||
#include "timing.h"
|
||||
|
||||
using namespace ledger;
|
||||
|
|
@ -232,33 +229,6 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
|||
else
|
||||
format = &config.print_format;
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
// If Python support is compiled, we can easily report minimum and
|
||||
// maximum values for each commodity. There is a line in config.cc
|
||||
// which configures the prices report to call these two functions,
|
||||
// if Python is available.
|
||||
|
||||
if (command == "P")
|
||||
python_eval("\
|
||||
min_val = 0\n\
|
||||
def vmin(d, val):\n\
|
||||
global min_val\n\
|
||||
if not min_val or val < min_val:\n\
|
||||
min_val = val\n\
|
||||
return val\n\
|
||||
return min_val\n\
|
||||
\n\
|
||||
max_val = 0\n\
|
||||
def vmax(d, val):\n\
|
||||
global max_val\n\
|
||||
if not max_val or val > max_val:\n\
|
||||
max_val = val\n\
|
||||
return val\n\
|
||||
return max_val\n", PY_EVAL_MULTI);
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
||||
TIMER_STOP(process);
|
||||
|
||||
// Walk the entries based on the report type and the options
|
||||
|
|
|
|||
373
main.py
373
main.py
|
|
@ -1,373 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Ledger, the command-line accounting tool
|
||||
#
|
||||
# Copyright (c) 2003-2004, New Artisans LLC. All rights reserved.
|
||||
#
|
||||
# This program is made available under the terms of the BSD Public
|
||||
# License. See the LICENSE file included with the distribution for
|
||||
# details and disclaimer.
|
||||
#
|
||||
# This script provides a Python front-end to the ledger library, and
|
||||
# replicates the functionality of the C++ front-end, main.cc. It is
|
||||
# provided as an example, and as a starting point for creating custom
|
||||
# front-ends based on the Ledger module. See the documentation for an
|
||||
# API reference, and how to use this module.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import string
|
||||
import time
|
||||
|
||||
true, false = 1, 0
|
||||
|
||||
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 ()
|
||||
|
||||
# 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 ()
|
||||
|
||||
averages = {}
|
||||
compute_monthly_avg = false
|
||||
|
||||
def get_index (xact):
|
||||
return time.strftime ("%Y/%m", time.localtime (xact.entry.date))
|
||||
|
||||
class ComputeMonthlyAvg (TransactionHandler):
|
||||
def __call__ (self, xact):
|
||||
global averages
|
||||
index = get_index (xact)
|
||||
if not averages.has_key(index):
|
||||
averages[index] = [Value (), 0]
|
||||
add_transaction_to (xact, averages[index][0])
|
||||
averages[index][1] += 1
|
||||
TransactionHandler.__call__ (self, xact)
|
||||
|
||||
def monthly_avg (details):
|
||||
index = get_index (xact)
|
||||
return averages[index][0] / averages[index][1]
|
||||
|
||||
def show_monthly_averages (arg):
|
||||
global compute_monthly_avg
|
||||
compute_monthly_avg = true
|
||||
config.report_period = "monthly";
|
||||
config.total_expr = "@monthly_avg()"
|
||||
|
||||
add_option_handler ("monthly-avg", "", show_monthly_averages)
|
||||
|
||||
# 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:])
|
||||
config.use_cache = not config.data_file
|
||||
process_environment (os.environ, "LEDGER_")
|
||||
|
||||
if os.environ.has_key ("LEDGER"):
|
||||
process_option ("file", os.getenv ("LEDGER"))
|
||||
if os.environ.has_key ("PRICE_HIST"):
|
||||
process_option ("price-db", os.getenv ("PRICE_HIST"))
|
||||
if os.environ.has_key ("PRICE_EXP"):
|
||||
process_option ("price-exp", os.getenv ("PRICE_EXP"))
|
||||
|
||||
# If no argument remain, then no command word was given. Report the
|
||||
# default help text and exit.
|
||||
|
||||
if len (args) == 0:
|
||||
option_help ()
|
||||
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);
|
||||
|
||||
if command == "balance" or command == "bal" or command == "b":
|
||||
command = "b"
|
||||
elif command == "register" or command == "reg" or command == "r":
|
||||
command = "r"
|
||||
elif command == "print" or command == "p":
|
||||
command = "p"
|
||||
elif command == "output":
|
||||
command = "w"
|
||||
elif command == "emacs":
|
||||
command = "x"
|
||||
elif command == "xml":
|
||||
command = "X"
|
||||
elif command == "entry":
|
||||
command = "e"
|
||||
elif command == "equity":
|
||||
command = "E"
|
||||
elif command == "prices":
|
||||
command = "P"
|
||||
elif command == "pricesdb":
|
||||
command = "D";
|
||||
else:
|
||||
print "Unrecognized command:", command
|
||||
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 expat C
|
||||
# library).
|
||||
|
||||
bin_parser = BinaryParser ()
|
||||
gnucash_parser = None
|
||||
xml_parser = None
|
||||
try: xml_parser = GnucashParser ()
|
||||
except: pass
|
||||
try: gnucash_parser = GnucashParser ()
|
||||
except: pass
|
||||
try: ofx_parser = OfxParser ()
|
||||
except: pass
|
||||
qif_parser = QifParser ()
|
||||
text_parser = TextualParser ()
|
||||
|
||||
register_parser (bin_parser)
|
||||
if xml_parser:
|
||||
register_parser (xml_parser)
|
||||
if gnucash_parser:
|
||||
register_parser (gnucash_parser)
|
||||
if ofx_parser:
|
||||
register_parser (ofx_parser)
|
||||
register_parser (qif_parser)
|
||||
register_parser (text_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, 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);
|
||||
|
||||
# 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
|
||||
if command == "e":
|
||||
new_entry = derive_new_entry (journal, args)
|
||||
if new_entry is None:
|
||||
sys.exit (1)
|
||||
|
||||
# Determine the format string to used, based on the command.
|
||||
|
||||
if config.format_string:
|
||||
format = config.format_string
|
||||
elif command == "b":
|
||||
format = config.balance_format
|
||||
elif command == "r":
|
||||
format = config.register_format
|
||||
elif command == "E":
|
||||
format = config.equity_format
|
||||
elif command == "P":
|
||||
min_val = 0
|
||||
def vmin(d, val):
|
||||
global min_val
|
||||
if not min_val or val < min_val:
|
||||
min_val = val
|
||||
return val
|
||||
return min_val
|
||||
|
||||
max_val = 0
|
||||
def vmax(d, val):
|
||||
global max_val
|
||||
if not max_val or val > max_val:
|
||||
max_val = val
|
||||
return val
|
||||
return max_val
|
||||
|
||||
format = config.prices_format
|
||||
elif command == "D":
|
||||
format = config.pricesdb_format
|
||||
elif command == "w":
|
||||
format = config.write_xact_format
|
||||
else:
|
||||
format = config.print_format
|
||||
|
||||
# Configure the output file
|
||||
|
||||
if config.output_file:
|
||||
out = open (config.output_file, "w")
|
||||
else:
|
||||
out = sys.stdout
|
||||
|
||||
# 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":
|
||||
handler = SetAccountValue ()
|
||||
elif command == "p" or command == "e":
|
||||
handler = FormatEntries (out, format)
|
||||
elif command == "x":
|
||||
handler = FormatEmacsTransactions (out)
|
||||
elif command == "X":
|
||||
handler = FormatXmlEntries (out, config.show_totals)
|
||||
else:
|
||||
handler = FormatTransactions (out, format)
|
||||
|
||||
if command == "w":
|
||||
write_textual_journal(journal, args, handler, out);
|
||||
else:
|
||||
# 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 config.head_entries or config.tail_entries:
|
||||
handler = TruncateEntries (handler, config.head_entries,
|
||||
config.tail_entries)
|
||||
|
||||
if config.display_predicate:
|
||||
handler = FilterTransactions (handler, config.display_predicate)
|
||||
|
||||
handler = CalcTransactions (handler)
|
||||
|
||||
if config.reconcile_balance:
|
||||
reconcilable = False
|
||||
if config.reconcile_balance == "<all>":
|
||||
reconcilable = True
|
||||
else:
|
||||
target_balance = Value (config.reconcile_balance)
|
||||
|
||||
cutoff = time.time ()
|
||||
if config.reconcile_date:
|
||||
cutoff = parse_date (config.reconcile_date)
|
||||
|
||||
handler = ReconcileTransactions (handler, target_balance,
|
||||
cutoff, reconcilable)
|
||||
|
||||
if config.sort_string:
|
||||
handler = SortTransactions (handler, config.sort_string)
|
||||
|
||||
if config.show_revalued:
|
||||
handler = ChangedValueTransactions (handler,
|
||||
config.show_revalued_only)
|
||||
|
||||
if config.show_collapsed:
|
||||
handler = CollapseTransactions (handler);
|
||||
|
||||
if config.show_subtotal and not (command == "b" or command == "E"):
|
||||
handler = SubtotalTransactions (handler)
|
||||
|
||||
if config.days_of_the_week:
|
||||
handler = DowTransactions (handler)
|
||||
elif config.by_payee:
|
||||
handler = ByPayeeTransactions (handler)
|
||||
|
||||
if config.report_period:
|
||||
handler = IntervalTransactions (handler, config.report_period,
|
||||
config.report_period_sort)
|
||||
handler = SortTransactions (handler, "d")
|
||||
|
||||
if compute_monthly_avg:
|
||||
handler = ComputeMonthlyAvg (handler)
|
||||
|
||||
# The next set of transaction filters are used by all reports.
|
||||
|
||||
if config.show_inverted:
|
||||
handler = InvertTransactions (handler)
|
||||
|
||||
if config.show_related:
|
||||
handler = RelatedTransactions (handler, config.show_all_related)
|
||||
|
||||
if config.predicate:
|
||||
handler = FilterTransactions (handler, config.predicate)
|
||||
|
||||
if config.budget_flags:
|
||||
handler = BudgetTransactions (handler, config.budget_flags)
|
||||
handler.add_period_entries (journal)
|
||||
elif config.forecast_limit:
|
||||
handler = ForecastTransactions (handler, config.forecast_limit)
|
||||
handler.add_period_entries (journal)
|
||||
|
||||
if config.comm_as_payee:
|
||||
handler = SetCommAsPayee (handler)
|
||||
|
||||
# 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 command == "e":
|
||||
# for xact in new_entry:
|
||||
# handler (xact)
|
||||
# else:
|
||||
# for entry in journal:
|
||||
# for xact in entry:
|
||||
# handler (xact)
|
||||
|
||||
if command == "e":
|
||||
walk_transactions (new_entry, handler)
|
||||
elif command == "P" or command == "D":
|
||||
walk_commodities (handler)
|
||||
else:
|
||||
walk_entries (journal, handler)
|
||||
|
||||
# Flush the handlers, causing them to output whatever data is still
|
||||
# pending.
|
||||
|
||||
if command != "P" and command != "D":
|
||||
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":
|
||||
acct_formatter = FormatAccount (out, format, config.display_predicate)
|
||||
sum_accounts (journal.master)
|
||||
walk_accounts (journal.master, acct_formatter, config.sort_string)
|
||||
acct_formatter.final (journal.master)
|
||||
acct_formatter.flush ()
|
||||
|
||||
if account_has_xdata (journal.master):
|
||||
xdata = account_xdata (journal.master)
|
||||
if not config.show_collapsed and xdata.total:
|
||||
out.write("--------------------\n")
|
||||
xdata.value = xdata.total
|
||||
# jww (2005-02-15): yet to convert
|
||||
#acct_formatter.format.format (out, details_t (journal.master))
|
||||
|
||||
elif command == "E":
|
||||
acct_formatter = FormatEquity (out, format, config.display_predicate)
|
||||
sum_accounts (journal.master)
|
||||
walk_accounts (journal.master, acct_formatter, config.sort_string)
|
||||
acct_formatter.flush ()
|
||||
|
||||
# If it were important to clean things up, we would have to clear out
|
||||
# the accumulated xdata at this point:
|
||||
|
||||
#clear_all_xdata ()
|
||||
|
||||
# If the cache is being used, and is dirty, update it now.
|
||||
|
||||
if config.use_cache and config.cache_dirty and config.cache_file:
|
||||
write_binary_journal (config.cache_file, journal);
|
||||
|
||||
# We're done!
|
||||
19
ofx.cc
19
ofx.cc
|
|
@ -220,22 +220,3 @@ unsigned int ofx_parser_t::parse(std::istream& in,
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(ofx_parse_overloads,
|
||||
ofx_parser_t::parse, 2, 4)
|
||||
|
||||
void export_ofx() {
|
||||
class_< ofx_parser_t, bases<parser_t> > ("OfxParser")
|
||||
.def("test", &ofx_parser_t::test)
|
||||
.def("parse", &ofx_parser_t::parse, ofx_parse_overloads())
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
91
option.cc
91
option.cc
|
|
@ -168,94 +168,3 @@ void process_environment(std::list<option_t>& options,
|
|||
process_option(options, buf, q + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/detail/api_placeholder.hpp>
|
||||
#include <vector>
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
struct func_option_wrapper : public option_handler
|
||||
{
|
||||
object self;
|
||||
func_option_wrapper(object _self) : self(_self) {}
|
||||
|
||||
virtual void operator()(const char * arg) {
|
||||
call<void>(self.ptr(), arg);
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
std::list<func_option_wrapper> wrappers;
|
||||
std::list<option_t> options;
|
||||
}
|
||||
|
||||
void py_add_option_handler(const std::string& long_opt,
|
||||
const std::string& short_opt, object func)
|
||||
{
|
||||
wrappers.push_back(func_option_wrapper(func));
|
||||
add_option_handler(options, long_opt, short_opt, wrappers.back());
|
||||
}
|
||||
|
||||
void add_other_option_handlers(const std::list<option_t>& other)
|
||||
{
|
||||
options.insert(options.begin(), other.begin(), other.end());
|
||||
}
|
||||
|
||||
bool py_process_option(const std::string& opt, const char * arg)
|
||||
{
|
||||
return process_option(options, opt, arg);
|
||||
}
|
||||
|
||||
list py_process_arguments(list args, bool anywhere = false)
|
||||
{
|
||||
std::vector<char *> strs;
|
||||
|
||||
int l = len(args);
|
||||
for (int i = 0; i < l; i++)
|
||||
strs.push_back(extract<char *>(args[i]));
|
||||
|
||||
std::list<std::string> newargs;
|
||||
process_arguments(options, strs.size(), &strs.front(), anywhere, newargs);
|
||||
|
||||
list py_newargs;
|
||||
for (std::list<std::string>::iterator i = newargs.begin();
|
||||
i != newargs.end();
|
||||
i++)
|
||||
py_newargs.append(*i);
|
||||
return py_newargs;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_FUNCTION_OVERLOADS(py_proc_args_overloads,
|
||||
py_process_arguments, 1, 2)
|
||||
|
||||
void py_process_environment(object env, const std::string& tag)
|
||||
{
|
||||
std::vector<char *> strs;
|
||||
std::vector<std::string> storage;
|
||||
|
||||
list items = call_method<list>(env.ptr(), "items");
|
||||
int l = len(items);
|
||||
for (int i = 0; i < l; i++) {
|
||||
tuple pair = extract<tuple>(items[i]);
|
||||
std::string s = extract<std::string>(pair[0]);
|
||||
s += "=";
|
||||
s += extract<std::string>(pair[1]);
|
||||
storage.push_back(s);
|
||||
strs.push_back(const_cast<char *>(storage.back().c_str()));
|
||||
}
|
||||
|
||||
process_environment(options, &strs.front(), tag);
|
||||
}
|
||||
|
||||
void export_option()
|
||||
{
|
||||
def("add_option_handler", py_add_option_handler);
|
||||
def("process_option", py_process_option);
|
||||
def("process_arguments", py_process_arguments, py_proc_args_overloads());
|
||||
def("process_environment", py_process_environment);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
48
parser.cc
48
parser.cc
|
|
@ -191,51 +191,3 @@ unsigned int parse_ledger_data(journal_t * journal, config_t& config)
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <Python.h>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
struct parser_wrap : public parser_t
|
||||
{
|
||||
PyObject * self;
|
||||
parser_wrap(PyObject * self_) : self(self_) {}
|
||||
|
||||
virtual bool test(std::istream& in) const {
|
||||
return call_method<bool>(self, "test", in);
|
||||
}
|
||||
|
||||
virtual unsigned int parse(std::istream& in,
|
||||
journal_t * journal,
|
||||
account_t * master = NULL,
|
||||
const std::string * original_file = NULL) {
|
||||
return call_method<unsigned int>(self, "__call__", in, journal, master,
|
||||
original_file);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_PYTHON_FUNCTION_OVERLOADS(parse_journal_overloads, parse_journal, 2, 4)
|
||||
BOOST_PYTHON_FUNCTION_OVERLOADS(parse_journal_file_overloads,
|
||||
parse_journal_file, 2, 4)
|
||||
|
||||
BOOST_PYTHON_FUNCTION_OVERLOADS(parse_ledger_data_overloads,
|
||||
parse_ledger_data, 1, 2)
|
||||
|
||||
void export_parser() {
|
||||
class_< parser_t, parser_wrap, boost::noncopyable > ("Parser")
|
||||
;
|
||||
|
||||
def("register_parser", register_parser);
|
||||
def("unregister_parser", unregister_parser);
|
||||
def("parse_journal", parse_journal, parse_journal_overloads());
|
||||
def("parse_journal_file", parse_journal_file, parse_journal_file_overloads());
|
||||
#if 0
|
||||
def("parse_ledger_data", parse_ledger_data, parse_ledger_data_overloads());
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
163
py_eval.cc
163
py_eval.cc
|
|
@ -1,163 +0,0 @@
|
|||
#include "py_eval.h"
|
||||
#include "journal.h"
|
||||
#include "error.h"
|
||||
#include "acconf.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
namespace {
|
||||
bool python_initialized = false;
|
||||
bool module_initialized = false;
|
||||
}
|
||||
|
||||
void export_amount();
|
||||
void export_balance();
|
||||
void export_value();
|
||||
void export_journal();
|
||||
void export_parser();
|
||||
void export_textual();
|
||||
void export_binary();
|
||||
void export_qif();
|
||||
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
void export_xml();
|
||||
void export_gnucash();
|
||||
#endif
|
||||
#ifdef HAVE_LIBOFX
|
||||
void export_ofx();
|
||||
#endif
|
||||
void export_option();
|
||||
void export_config();
|
||||
void export_walk();
|
||||
void export_format();
|
||||
void export_valexpr();
|
||||
void export_datetime();
|
||||
void export_derive();
|
||||
void export_reconcile();
|
||||
void export_emacs();
|
||||
|
||||
void initialize_ledger_for_python()
|
||||
{
|
||||
export_amount();
|
||||
export_balance();
|
||||
export_value();
|
||||
export_journal();
|
||||
export_parser();
|
||||
export_textual();
|
||||
export_binary();
|
||||
export_qif();
|
||||
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
export_xml();
|
||||
export_gnucash();
|
||||
#endif
|
||||
#ifdef HAVE_LIBOFX
|
||||
export_ofx();
|
||||
#endif
|
||||
export_option();
|
||||
export_config();
|
||||
export_walk();
|
||||
export_format();
|
||||
export_valexpr();
|
||||
export_datetime();
|
||||
export_derive();
|
||||
export_reconcile();
|
||||
export_emacs();
|
||||
|
||||
module_initialized = true;
|
||||
}
|
||||
|
||||
namespace ledger {
|
||||
|
||||
static struct python_main_t
|
||||
{
|
||||
handle<> mmodule;
|
||||
dict nspace;
|
||||
python_main_t()
|
||||
: mmodule(borrowed(PyImport_AddModule("__main__"))),
|
||||
nspace(handle<>(borrowed(PyModule_GetDict(mmodule.get())))) {}
|
||||
}
|
||||
* python_main = NULL;
|
||||
|
||||
struct python_run
|
||||
{
|
||||
object result;
|
||||
python_run(const std::string& str, int input_mode)
|
||||
: result(handle<>(borrowed(PyRun_String(str.c_str(), input_mode,
|
||||
python_main->nspace.ptr(),
|
||||
python_main->nspace.ptr())))) {}
|
||||
operator object() {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
static struct cleanup_python {
|
||||
~cleanup_python() {
|
||||
if (python_main) {
|
||||
delete python_main;
|
||||
python_main = NULL;
|
||||
}
|
||||
if (python_initialized)
|
||||
Py_Finalize();
|
||||
}
|
||||
} _cleanup;
|
||||
|
||||
void init_python()
|
||||
{
|
||||
if (! module_initialized) {
|
||||
Py_Initialize();
|
||||
python_initialized = true;
|
||||
detail::init_module("ledger", &initialize_ledger_for_python);
|
||||
}
|
||||
python_main = new python_main_t;
|
||||
}
|
||||
|
||||
object python_eval(std::istream& in, py_eval_mode_t mode)
|
||||
{
|
||||
if (! python_initialized)
|
||||
init_python();
|
||||
|
||||
bool first = true;
|
||||
std::string buffer;
|
||||
buffer.reserve(4096);
|
||||
|
||||
while (! in.eof()) {
|
||||
char buf[256];
|
||||
in.getline(buf, 255);
|
||||
if (buf[0] == '!')
|
||||
break;
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
buffer += "\n";
|
||||
buffer += buf;
|
||||
}
|
||||
|
||||
try {
|
||||
int input_mode;
|
||||
switch (mode) {
|
||||
case PY_EVAL_EXPR: input_mode = Py_eval_input; break;
|
||||
case PY_EVAL_STMT: input_mode = Py_single_input; break;
|
||||
case PY_EVAL_MULTI: input_mode = Py_file_input; break;
|
||||
}
|
||||
assert(Py_IsInitialized());
|
||||
return python_run(buffer, input_mode);
|
||||
}
|
||||
catch(const boost::python::error_already_set&) {
|
||||
PyErr_Print();
|
||||
throw error("Evaluating Python code");
|
||||
}
|
||||
}
|
||||
|
||||
object python_eval(const std::string& str, py_eval_mode_t mode)
|
||||
{
|
||||
std::istringstream stream(str);
|
||||
return python_eval(stream, mode);
|
||||
}
|
||||
|
||||
object python_eval(const char * c_str, py_eval_mode_t mode)
|
||||
{
|
||||
std::string str(c_str);
|
||||
return python_eval(str, mode);
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
75
py_eval.h
75
py_eval.h
|
|
@ -1,75 +0,0 @@
|
|||
#ifndef _PYTHON_H
|
||||
#define _PYTHON_H
|
||||
|
||||
#include "valexpr.h"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
namespace ledger {
|
||||
|
||||
enum py_eval_mode_t {
|
||||
PY_EVAL_EXPR,
|
||||
PY_EVAL_STMT,
|
||||
PY_EVAL_MULTI
|
||||
};
|
||||
|
||||
object python_eval(std::istream& in, py_eval_mode_t mode = PY_EVAL_EXPR);
|
||||
object python_eval(const std::string& str, py_eval_mode_t mode = PY_EVAL_EXPR);
|
||||
object python_eval(const char * c_str, py_eval_mode_t mode = PY_EVAL_EXPR);
|
||||
|
||||
template <typename T>
|
||||
bool python_call(const std::string& func_name, value_expr_t * arg_expr,
|
||||
const details_t& details, T& result)
|
||||
{
|
||||
try {
|
||||
object func = python_eval(func_name);
|
||||
if (arg_expr) {
|
||||
if (arg_expr->right) {
|
||||
list args;
|
||||
args.append(details);
|
||||
for (value_expr_t * arg = arg_expr; arg; arg = arg->right) {
|
||||
assert(arg->kind == value_expr_t::O_ARG);
|
||||
value_t value;
|
||||
arg->left->compute(value, details);
|
||||
args.append(value);
|
||||
}
|
||||
|
||||
if (PyObject * val = PyObject_CallObject(func.ptr(),
|
||||
tuple(args).ptr())) {
|
||||
result = extract<T>(val)();
|
||||
Py_DECREF(val);
|
||||
}
|
||||
else if (PyObject * err = PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
throw value_expr_error(std::string("While calling Python function '") +
|
||||
func_name + "'");
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
assert(arg_expr->kind == value_expr_t::O_ARG);
|
||||
value_t value;
|
||||
arg_expr->left->compute(value, details);
|
||||
result = call<T>(func.ptr(), details, value);
|
||||
}
|
||||
} else {
|
||||
result = call<T>(func.ptr(), details);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch(const boost::python::error_already_set&) {
|
||||
PyErr_Print();
|
||||
throw value_expr_error(std::string("While calling Python function '") +
|
||||
func_name + "'");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#endif // _PYTHON_H
|
||||
146
pyfstream.h
146
pyfstream.h
|
|
@ -1,146 +0,0 @@
|
|||
#ifndef _PYFSTREAM_H
|
||||
#define _PYFSTREAM_H
|
||||
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
// pyofstream
|
||||
// - a stream that writes on a Python file object
|
||||
|
||||
class pyoutbuf : public std::streambuf {
|
||||
protected:
|
||||
PyFileObject * fo; // Python file object
|
||||
public:
|
||||
// constructor
|
||||
pyoutbuf (PyFileObject * _fo) : fo(_fo) {}
|
||||
|
||||
protected:
|
||||
// write one character
|
||||
virtual int_type overflow (int_type c) {
|
||||
if (c != EOF) {
|
||||
char z[2];
|
||||
z[0] = c;
|
||||
z[1] = '\0';
|
||||
if (PyFile_WriteString(z, (PyObject *)fo) < 0) {
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// write multiple characters
|
||||
virtual std::streamsize xsputn (const char* s, std::streamsize num) {
|
||||
char * buf = new char[num + 1];
|
||||
std::strncpy(buf, s, num);
|
||||
buf[num] = '\0';
|
||||
if (PyFile_WriteString(buf, (PyObject *)fo) < 0)
|
||||
num = 0;
|
||||
delete[] buf;
|
||||
return num;
|
||||
}
|
||||
};
|
||||
|
||||
class pyofstream : public std::ostream {
|
||||
protected:
|
||||
pyoutbuf buf;
|
||||
public:
|
||||
pyofstream (PyFileObject * fo) : std::ostream(0), buf(fo) {
|
||||
rdbuf(&buf);
|
||||
}
|
||||
};
|
||||
|
||||
// pyifstream
|
||||
// - a stream that reads on a file descriptor
|
||||
|
||||
class pyinbuf : public std::streambuf {
|
||||
protected:
|
||||
PyFileObject * fo; // Python file object
|
||||
protected:
|
||||
/* data buffer:
|
||||
* - at most, pbSize characters in putback area plus
|
||||
* - at most, bufSize characters in ordinary read buffer
|
||||
*/
|
||||
static const int pbSize = 4; // size of putback area
|
||||
static const int bufSize = 1024; // size of the data buffer
|
||||
char buffer[bufSize + pbSize]; // data buffer
|
||||
|
||||
public:
|
||||
/* constructor
|
||||
* - initialize file descriptor
|
||||
* - initialize empty data buffer
|
||||
* - no putback area
|
||||
* => force underflow()
|
||||
*/
|
||||
pyinbuf (PyFileObject * _fo) : fo(_fo) {
|
||||
setg (buffer+pbSize, // beginning of putback area
|
||||
buffer+pbSize, // read position
|
||||
buffer+pbSize); // end position
|
||||
}
|
||||
|
||||
protected:
|
||||
// insert new characters into the buffer
|
||||
virtual int_type underflow () {
|
||||
#ifndef _MSC_VER
|
||||
using std::memmove;
|
||||
#endif
|
||||
|
||||
// is read position before end of buffer?
|
||||
if (gptr() < egptr()) {
|
||||
return traits_type::to_int_type(*gptr());
|
||||
}
|
||||
|
||||
/* process size of putback area
|
||||
* - use number of characters read
|
||||
* - but at most size of putback area
|
||||
*/
|
||||
int numPutback;
|
||||
numPutback = gptr() - eback();
|
||||
if (numPutback > pbSize) {
|
||||
numPutback = pbSize;
|
||||
}
|
||||
|
||||
/* copy up to pbSize characters previously read into
|
||||
* the putback area
|
||||
*/
|
||||
memmove (buffer+(pbSize-numPutback), gptr()-numPutback,
|
||||
numPutback);
|
||||
|
||||
// read at most bufSize new characters
|
||||
int num;
|
||||
PyObject *line = PyFile_GetLine((PyObject *)fo, bufSize);
|
||||
if (! line || ! PyString_Check(line)) {
|
||||
// ERROR or EOF
|
||||
return EOF;
|
||||
}
|
||||
|
||||
num = PyString_Size(line);
|
||||
if (num == 0)
|
||||
return EOF;
|
||||
|
||||
memmove (buffer+pbSize, PyString_AsString(line), num);
|
||||
|
||||
// reset buffer pointers
|
||||
setg (buffer+(pbSize-numPutback), // beginning of putback area
|
||||
buffer+pbSize, // read position
|
||||
buffer+pbSize+num); // end of buffer
|
||||
|
||||
// return next character
|
||||
return traits_type::to_int_type(*gptr());
|
||||
}
|
||||
};
|
||||
|
||||
class pyifstream : public std::istream {
|
||||
protected:
|
||||
pyinbuf buf;
|
||||
public:
|
||||
pyifstream (PyFileObject * fo) : std::istream(0), buf(fo) {
|
||||
rdbuf(&buf);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _PYFSTREAM_H
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
void initialize_ledger_for_python();
|
||||
|
||||
BOOST_PYTHON_MODULE(ledger) {
|
||||
initialize_ledger_for_python();
|
||||
}
|
||||
16
pyledger.h
16
pyledger.h
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef _PYLEDGER_H
|
||||
#define _PYLEDGER_H
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Ledger Accounting Tool (with Python support via Boost.Python)
|
||||
//
|
||||
// A command-line tool for general double-entry accounting.
|
||||
//
|
||||
// Copyright (c) 2003,2004 John Wiegley <johnw@newartisans.com>
|
||||
//
|
||||
|
||||
#include <ledger.h>
|
||||
#include <py_eval.h>
|
||||
|
||||
#endif // _PYLEDGER_H
|
||||
19
qif.cc
19
qif.cc
|
|
@ -246,22 +246,3 @@ unsigned int qif_parser_t::parse(std::istream& in,
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(qif_parse_overloads,
|
||||
qif_parser_t::parse, 2, 4)
|
||||
|
||||
void export_qif() {
|
||||
class_< qif_parser_t, bases<parser_t> > ("QifParser")
|
||||
.def("test", &qif_parser_t::test)
|
||||
.def("parse", &qif_parser_t::parse, qif_parse_overloads())
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
20
reconcile.cc
20
reconcile.cc
|
|
@ -86,23 +86,3 @@ void reconcile_transactions::flush()
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
void export_reconcile()
|
||||
{
|
||||
class_< reconcile_transactions, bases<item_handler<transaction_t> > >
|
||||
("ReconcileTransactions",
|
||||
init<item_handler<transaction_t> *, const value_t&, time_t>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &reconcile_transactions::flush)
|
||||
.def("__call__", &reconcile_transactions::operator())
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
30
setup.py
30
setup.py
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
import os
|
||||
|
||||
libs = ["ledger", "boost_python", "gmp", "pcre"]
|
||||
|
||||
if os.environ.has_key ("HAVE_EXPAT") and\
|
||||
os.environ["HAVE_EXPAT"] == "true":
|
||||
libs.extend (["expat"])
|
||||
|
||||
if os.environ.has_key ("HAVE_XMLPARSE") and\
|
||||
os.environ["HAVE_XMLPARSE"] == "true":
|
||||
libs.extend (["xmlparse", "xmltok"])
|
||||
|
||||
if os.environ.has_key ("HAVE_LIBOFX") and\
|
||||
os.environ["HAVE_LIBOFX"] == "true":
|
||||
libs.extend (["ofx"])
|
||||
|
||||
setup(name = "Ledger",
|
||||
version = "2.5",
|
||||
description = "Ledger Accounting Tool",
|
||||
author = "John Wiegley",
|
||||
author_email = "johnw@newartisans.com",
|
||||
url = "http://www.newartisans.com/ledger.html",
|
||||
ext_modules = [
|
||||
Extension("ledger", ["pyledger.cc"],
|
||||
define_macros = [('PYTHON_MODULE', 1)],
|
||||
libraries = libs)])
|
||||
27
textual.cc
27
textual.cc
|
|
@ -12,9 +12,6 @@
|
|||
#include "timing.h"
|
||||
#include "util.h"
|
||||
#include "acconf.h"
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
#include "py_eval.h"
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
|
@ -733,11 +730,6 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
else if (word == "end") {
|
||||
account_stack.pop_front();
|
||||
}
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
else if (word == "python") {
|
||||
python_eval(in, PY_EVAL_MULTI);
|
||||
}
|
||||
#endif
|
||||
else if (word == "alias") {
|
||||
char * b = skip_ws(p);
|
||||
if (char * e = std::strchr(b, '=')) {
|
||||
|
|
@ -904,22 +896,3 @@ void write_textual_journal(journal_t& journal, std::string path,
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(textual_parse_overloads,
|
||||
textual_parser_t::parse, 2, 4)
|
||||
|
||||
void export_textual() {
|
||||
class_< textual_parser_t, bases<parser_t> > ("TextualParser")
|
||||
.def("test", &textual_parser_t::test)
|
||||
.def("parse", &textual_parser_t::parse, textual_parse_overloads())
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
461
timeclock
461
timeclock
|
|
@ -1,461 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# timeclock, a time-keeping program based on the Ledger library
|
||||
#
|
||||
# Copyright (c) 2003-2004, New Artisans LLC. All rights reserved.
|
||||
#
|
||||
# This program is made available under the terms of the BSD Public
|
||||
# License. See the LICENSE file included with the distribution for
|
||||
# details and disclaimer.
|
||||
#
|
||||
# This program implements a simple timeclock, using the identical
|
||||
# format as my timeclock.el module for Emacs (which is part of the
|
||||
# Emacs 21 distribution). This allows you to use either this script
|
||||
# or that module for creating time events.
|
||||
#
|
||||
# Usage is very simple: Set the environment variable TIMELOG to the
|
||||
# path to your timelog file (if this variable is unset, any events
|
||||
# created will simply be printed to stdout). Once this variable is
|
||||
# set:
|
||||
#
|
||||
# timeclock in "project" what aspect of the project will I do today
|
||||
# timeclock out what did I accomplish
|
||||
#
|
||||
# The description text is optional, but the project is required when
|
||||
# clocking in. This project should be a account name, which means it
|
||||
# can use ":" to separate the project from the task, for example:
|
||||
#
|
||||
# timeclock in Client:Meetings at the code review meeting
|
||||
#
|
||||
# To generate a balance report of time spent, use "timeclock" with no
|
||||
# arguments, or "timeclock balance". The options available are the
|
||||
# same as those used for ledger.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import string
|
||||
import time
|
||||
|
||||
true, false = 1, 0
|
||||
|
||||
from ledger import *
|
||||
|
||||
home = os.getenv ("HOME")
|
||||
config.init_file = home + "/.timeclockrc";
|
||||
config.cache_file = home + "/.timeclock-cache";
|
||||
|
||||
# Define some functions for reporting time quantities
|
||||
|
||||
workday = 8 * 60 * 60 # length of a nominal workday
|
||||
|
||||
def secstr (secs):
|
||||
return "%d:%02d" % (abs (secs) / 60 / 60, (abs (secs) / 60) % 60)
|
||||
|
||||
def daystr (amt):
|
||||
dy = int (amt) / int (workday)
|
||||
amt = amt - (dy * workday)
|
||||
if dy >= 5:
|
||||
wk = dy / 5
|
||||
dy = dy % 5
|
||||
if dy: amt = "%sw %sd %s" % (wk, dy, secstr (amt))
|
||||
else: amt = "%sw %s" % (wk, secstr (amt))
|
||||
else:
|
||||
if dy: amt = "%sd %s" % (dy, secstr (amt))
|
||||
else: amt = secstr (amt)
|
||||
return amt
|
||||
|
||||
def adaystr (details):
|
||||
result = ""
|
||||
for amt in account_xdata(details.account).total:
|
||||
if amt.commodity ().symbol == "s":
|
||||
result = daystr (float (amt))
|
||||
break
|
||||
return result
|
||||
|
||||
config.amount_expr = "{1.00h}*(a/{3600.00h})"
|
||||
config.total_expr = "{1.00h}*(O/{3600.00h})"
|
||||
config.balance_format = "%20@adaystr() %8T %2_%-a\n";
|
||||
|
||||
# Help text specific to timeclock
|
||||
|
||||
def show_version (arg):
|
||||
print """Timeclock, a command-line timekeeping tool
|
||||
|
||||
Copyright (c) 2003-2004, New Artisans LLC. All rights reserved.
|
||||
|
||||
This program is made available under the terms of the BSD Public
|
||||
License. See the LICENSE file included with the distribution for
|
||||
details and disclaimer."""
|
||||
sys.exit (0)
|
||||
|
||||
def option_help (arg):
|
||||
print """usage: timeclock [options] COMMAND [ACCT REGEX]...
|
||||
|
||||
Basic options:
|
||||
-h, --help display this help text
|
||||
-v, --version show version information
|
||||
-i, --init FILE initialize ledger by loading FILE (def: ~/.ledgerrc)
|
||||
--cache FILE use FILE as a binary cache when --file is not used
|
||||
-f, --file FILE read ledger data from FILE
|
||||
-o, --output FILE write output to FILE
|
||||
|
||||
Report filtering:
|
||||
-b, --begin DATE set report begin date
|
||||
-e, --end DATE set report end date
|
||||
-c, --current show only current and past entries (not future)
|
||||
-C, --cleared consider only cleared transactions
|
||||
-U, --uncleared consider only uncleared transactions
|
||||
-R, --real consider only real (non-virtual) transactions
|
||||
-Z, --actual consider only actual (non-automated) transactions
|
||||
-r, --related calculate report using related transactions
|
||||
|
||||
Output customization:
|
||||
-F, --format STR use STR as the format; for each report type, use:
|
||||
--balance-format --register-format
|
||||
--plot-amount-format --plot-total-format
|
||||
-y, --date-format STR use STR as the date format (def: %Y/%m/%d)
|
||||
--wide for the default register report, use 132 columns
|
||||
-E, --empty balance: show accounts with zero balance
|
||||
-n, --collapse register: collapse entries with multiple transactions
|
||||
-s, --subtotal balance: show sub-accounts; register: show subtotals
|
||||
-S, --sort EXPR sort report according to the value expression EXPR
|
||||
-p, --period STR report using the given period
|
||||
--period-sort EXPR sort each report period's entries by EXPR
|
||||
--dow show a days-of-the-week report
|
||||
-W, --weekly show weekly sub-totals
|
||||
-M, --monthly show monthly sub-totals
|
||||
-Y, --yearly show yearly sub-totals
|
||||
-l, --limit EXPR calculate only transactions matching EXPR
|
||||
-d, --display EXPR display only transactions matching EXPR
|
||||
-t, --amount EXPR use EXPR to calculate the displayed amount
|
||||
-T, --total EXPR use EXPR to calculate the displayed total
|
||||
-j, --amount-data print only raw amount data (useful for scripting)
|
||||
-J, --total-data print only raw total data
|
||||
|
||||
Commodity reporting:
|
||||
-A, --average report average transaction amount
|
||||
-D, --deviation report deviation from the average
|
||||
|
||||
Commands:
|
||||
balance [REGEXP]... show balance totals for matching accounts
|
||||
register [REGEXP]... show register of matching events"""
|
||||
sys.exit (0)
|
||||
|
||||
# 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_option_handler ("help", "h", option_help)
|
||||
add_option_handler ("version", "v", show_version)
|
||||
|
||||
# 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:])
|
||||
config.use_cache = not config.data_file
|
||||
process_environment (os.environ, "TIMECLOCK_")
|
||||
|
||||
if os.environ.has_key ("TIMELOG"):
|
||||
process_option ("file", os.getenv ("TIMELOG"))
|
||||
|
||||
# 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.
|
||||
|
||||
if len (args) == 0:
|
||||
args = ["balance"]
|
||||
|
||||
command = args.pop (0);
|
||||
|
||||
if command == "balance" or command == "bal" or command == "b":
|
||||
command = "b"
|
||||
elif command == "register" or command == "reg" or command == "r":
|
||||
command = "r"
|
||||
elif command == "entry":
|
||||
command = "e"
|
||||
elif command == "in" or command == "out":
|
||||
if config.data_file:
|
||||
log = open (config.data_file, "a")
|
||||
else:
|
||||
log = sys.stdout
|
||||
|
||||
if command == "in":
|
||||
if len (args) == 0:
|
||||
print "A project name is required when clocking in."
|
||||
sys.exit (1)
|
||||
log.write ("i %s %s" % (time.strftime ("%Y/%m/%d %H:%M:%S"),
|
||||
args.pop (0)))
|
||||
if len (args) > 0:
|
||||
log.write (" %s\n" % string.join (args, " "))
|
||||
else:
|
||||
log.write ("o %s" % time.strftime ("%Y/%m/%d %H:%M:%S"))
|
||||
if len (args) > 0:
|
||||
log.write (" %s" % string.join (args, " "))
|
||||
|
||||
log.write ("\n")
|
||||
log.close ()
|
||||
sys.exit (0)
|
||||
else:
|
||||
print "Unrecognized command:", command
|
||||
sys.exit (1)
|
||||
|
||||
# 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 ()
|
||||
|
||||
# This parser is intended only for timelog files.
|
||||
|
||||
class Event:
|
||||
def __init__(self, kind, when, desc):
|
||||
self.kind = kind
|
||||
self.when = when
|
||||
self.desc = desc
|
||||
|
||||
class Interval:
|
||||
def __init__(self, begin, end):
|
||||
self.begin = begin
|
||||
self.end = end
|
||||
|
||||
def length(self):
|
||||
"Return the length of the interval in seconds."
|
||||
return self.end.when - self.begin.when
|
||||
|
||||
def parse_timelog(path, journal):
|
||||
import re
|
||||
if not os.path.exists (path):
|
||||
print "Cannot read timelog file '%s'" % path
|
||||
sys.exit (1)
|
||||
file = open(path)
|
||||
history = []
|
||||
begin = None
|
||||
linenum = 0
|
||||
for line in file:
|
||||
linenum += 1
|
||||
match = re.match("([iIoO])\s+([0-9/]+\s+[0-9:]+)\s*(.+)", line)
|
||||
if match:
|
||||
(kind, when, desc) = match.groups()
|
||||
when = time.strptime(when, "%Y/%m/%d %H:%M:%S")
|
||||
when = time.mktime(when)
|
||||
event = Event(kind, when, desc)
|
||||
if kind == "i" or kind == "I":
|
||||
begin = event
|
||||
else:
|
||||
if begin.desc:
|
||||
match = re.match ("(.+?) (.+)", begin.desc)
|
||||
if match:
|
||||
acct = match.group (1)
|
||||
desc = match.group (2)
|
||||
else:
|
||||
acct = begin.desc
|
||||
desc = ""
|
||||
else:
|
||||
acct = "Misc"
|
||||
desc = event.desc
|
||||
|
||||
l = Interval(begin, event).length ()
|
||||
e = Entry ()
|
||||
e.date = int (begin.when)
|
||||
e.payee = desc
|
||||
|
||||
x = Transaction (journal.find_account (acct),
|
||||
Amount ("%ss" % l), TRANSACTION_VIRTUAL)
|
||||
e.add_transaction (x)
|
||||
|
||||
if not journal.add_entry (e):
|
||||
print "%s, %d: Failed to entry" % (path, linenum)
|
||||
sys.exit (1)
|
||||
|
||||
parse_timelog (config.data_file, journal)
|
||||
|
||||
# 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.
|
||||
|
||||
if command == "b" and \
|
||||
config.amount_expr == "{1.00h}*(a/{3600.00h})":
|
||||
config.amount_expr = "a"
|
||||
|
||||
config.process_options (command, args);
|
||||
|
||||
# Determine the format string to used, based on the command.
|
||||
|
||||
if config.format_string:
|
||||
format = config.format_string
|
||||
elif command == "b":
|
||||
format = config.balance_format
|
||||
elif command == "r":
|
||||
format = config.register_format
|
||||
else:
|
||||
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 FormatTransactions (TransactionHandler):
|
||||
last_entry = None
|
||||
output = None
|
||||
|
||||
def __init__ (self, fmt):
|
||||
try:
|
||||
i = string.index (fmt, '%/')
|
||||
self.formatter = Format (fmt[: i])
|
||||
self.nformatter = Format (fmt[i + 2 :])
|
||||
except ValueError:
|
||||
self.formatter = Format (fmt)
|
||||
self.nformatter = None
|
||||
|
||||
self.last_entry = None
|
||||
|
||||
if config.output_file:
|
||||
self.output = open (config.output_file, "w")
|
||||
else:
|
||||
self.output = sys.stdout
|
||||
|
||||
TransactionHandler.__init__ (self)
|
||||
|
||||
def __del__ (self):
|
||||
if config.output_file:
|
||||
self.output.close ()
|
||||
|
||||
def flush (self):
|
||||
self.output.flush ()
|
||||
|
||||
def __call__ (self, xact):
|
||||
if not transaction_has_xdata (xact) or \
|
||||
not transaction_xdata (xact).dflags & TRANSACTION_DISPLAYED:
|
||||
if self.nformatter is not None and \
|
||||
self.last_entry is not None and \
|
||||
xact.entry == self.last_entry:
|
||||
self.output.write (self.nformatter.format (xact))
|
||||
else:
|
||||
self.output.write (self.formatter.format (xact))
|
||||
self.last_entry = xact.entry
|
||||
transaction_xdata (xact).dflags |= TRANSACTION_DISPLAYED
|
||||
|
||||
class FormatAccounts (AccountHandler):
|
||||
output = None
|
||||
|
||||
def __init__ (self, fmt, pred):
|
||||
self.formatter = Format (fmt)
|
||||
self.predicate = AccountPredicate (pred)
|
||||
|
||||
if config.output_file:
|
||||
self.output = open (config.output_file, "w")
|
||||
else:
|
||||
self.output = sys.stdout
|
||||
|
||||
AccountHandler.__init__ (self)
|
||||
|
||||
def __del__ (self):
|
||||
if config.output_file:
|
||||
self.output.close ()
|
||||
|
||||
def final (self, account):
|
||||
if account_has_xdata (account):
|
||||
xdata = account_xdata (account)
|
||||
if xdata.dflags & ACCOUNT_TO_DISPLAY:
|
||||
print "-------------------- ---------"
|
||||
xdata.value = xdata.total
|
||||
self.output.write (self.formatter.format (account))
|
||||
|
||||
def flush (self):
|
||||
self.output.flush ()
|
||||
|
||||
def __call__ (self, account):
|
||||
if display_account (account, self.predicate):
|
||||
if not account.parent:
|
||||
account_xdata (account).dflags |= ACCOUNT_TO_DISPLAY
|
||||
else:
|
||||
self.output.write (self.formatter.format (account))
|
||||
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":
|
||||
handler = SetAccountValue ()
|
||||
else:
|
||||
handler = FormatTransactions (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 command != "b":
|
||||
if config.display_predicate:
|
||||
handler = FilterTransactions (handler, config.display_predicate)
|
||||
|
||||
handler = CalcTransactions (handler)
|
||||
|
||||
if config.sort_string:
|
||||
handler = SortTransactions (handler, config.sort_string)
|
||||
|
||||
if config.show_revalued:
|
||||
handler = ChangedValueTransactions (handler, config.show_revalued_only)
|
||||
|
||||
if config.show_collapsed:
|
||||
handler = CollapseTransactions (handler);
|
||||
|
||||
if config.show_subtotal and not (command == "b" or command == "E"):
|
||||
handler = SubtotalTransactions (handler)
|
||||
|
||||
if config.days_of_the_week:
|
||||
handler = DowTransactions (handler)
|
||||
elif config.by_payee:
|
||||
handler = ByPayeeTransactions (handler)
|
||||
|
||||
if config.report_period:
|
||||
handler = IntervalTransactions (handler, config.report_period,
|
||||
config.report_period_sort)
|
||||
handler = SortTransactions (handler, "d")
|
||||
|
||||
# The next two transaction filters are used by all reports.
|
||||
|
||||
if config.show_inverted:
|
||||
handler = InvertTransactions (handler)
|
||||
|
||||
if config.show_related:
|
||||
handler = RelatedTransactions (handler, config.show_all_related)
|
||||
|
||||
if config.predicate:
|
||||
handler = FilterTransactions (handler, config.predicate)
|
||||
|
||||
if config.comm_as_payee:
|
||||
handler = SetCommAsPayee (handler)
|
||||
|
||||
# Walk the journal's entries, and pass each entry's transaction to the
|
||||
# handler chain established above.
|
||||
|
||||
walk_entries (journal, handler)
|
||||
|
||||
# Flush the handlers, causing them to output whatever data is still
|
||||
# pending.
|
||||
|
||||
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":
|
||||
acct_formatter = FormatAccounts (format, config.display_predicate)
|
||||
sum_accounts (journal.master)
|
||||
walk_accounts (journal.master, acct_formatter, config.sort_string)
|
||||
acct_formatter.final (journal.master)
|
||||
acct_formatter.flush ()
|
||||
46
timeclock.el
46
timeclock.el
|
|
@ -284,10 +284,10 @@ display (non-nil means on)."
|
|||
(> (prefix-numeric-value arg) 0)
|
||||
(not timeclock-modeline-display))))
|
||||
(if on-p
|
||||
(progn
|
||||
(or (memq 'timeclock-mode-string global-mode-string)
|
||||
(setq global-mode-string
|
||||
(append global-mode-string '(timeclock-mode-string))))
|
||||
(progn
|
||||
(or (memq 'timeclock-mode-string global-mode-string)
|
||||
(setq global-mode-string
|
||||
(append global-mode-string '(timeclock-mode-string))))
|
||||
(unless (memq 'timeclock-update-modeline timeclock-event-hook)
|
||||
(add-hook 'timeclock-event-hook 'timeclock-update-modeline))
|
||||
(when timeclock-update-timer
|
||||
|
|
@ -296,13 +296,13 @@ display (non-nil means on)."
|
|||
(if (boundp 'display-time-hook)
|
||||
(remove-hook 'display-time-hook 'timeclock-update-modeline))
|
||||
(if timeclock-use-display-time
|
||||
(progn
|
||||
;; Update immediately so there is a visible change
|
||||
;; on calling this function.
|
||||
(if display-time-mode (timeclock-update-modeline)
|
||||
(message "Activate `display-time-mode' to see \
|
||||
(progn
|
||||
;; Update immediately so there is a visible change
|
||||
;; on calling this function.
|
||||
(if display-time-mode (timeclock-update-modeline)
|
||||
(message "Activate `display-time-mode' to see \
|
||||
timeclock information"))
|
||||
(add-hook 'display-time-hook 'timeclock-update-modeline))
|
||||
(add-hook 'display-time-hook 'timeclock-update-modeline))
|
||||
(setq timeclock-update-timer
|
||||
(run-at-time nil 60 'timeclock-update-modeline))))
|
||||
(setq global-mode-string
|
||||
|
|
@ -358,9 +358,9 @@ discover the name of the project."
|
|||
(timeclock-reread-log))
|
||||
;; Either no log file, or day has rolled over.
|
||||
(unless (and timeclock-last-event
|
||||
(equal (timeclock-time-to-date
|
||||
(cadr timeclock-last-event))
|
||||
(timeclock-time-to-date (current-time))))
|
||||
(equal (timeclock-time-to-date
|
||||
(cadr timeclock-last-event))
|
||||
(timeclock-time-to-date (current-time))))
|
||||
(let ((workday (or (and (numberp arg) arg)
|
||||
(and arg 0)
|
||||
(and timeclock-get-workday-function
|
||||
|
|
@ -412,8 +412,8 @@ If TODAY-ONLY is non-nil, the value returned will be relative only to
|
|||
the time worked today, and not to past time."
|
||||
(let ((discrep (timeclock-find-discrep)))
|
||||
(if discrep
|
||||
(- (if today-only (cadr discrep)
|
||||
(car discrep)))
|
||||
(- (if today-only (cadr discrep)
|
||||
(car discrep)))
|
||||
0.0)))
|
||||
|
||||
;;;###autoload
|
||||
|
|
@ -424,8 +424,8 @@ If TODAY-ONLY is non-nil, the display will be relative only to time
|
|||
worked today, ignoring the time worked on previous days."
|
||||
(interactive "P")
|
||||
(let ((remainder (timeclock-workday-remaining)) ; today-only?
|
||||
(last-in (equal (car timeclock-last-event) "i"))
|
||||
status)
|
||||
(last-in (equal (car timeclock-last-event) "i"))
|
||||
status)
|
||||
(setq status
|
||||
(format "Currently %s since %s (%s), %s %s, leave at %s"
|
||||
(if last-in "IN" "OUT")
|
||||
|
|
@ -619,7 +619,7 @@ The value of `timeclock-relative' affects the display as described in
|
|||
that variable's documentation."
|
||||
(interactive)
|
||||
(let ((remainder (timeclock-workday-remaining (not timeclock-relative)))
|
||||
(last-in (equal (car timeclock-last-event) "i")))
|
||||
(last-in (equal (car timeclock-last-event) "i")))
|
||||
(when (and (< remainder 0)
|
||||
(not (and timeclock-day-over
|
||||
(equal timeclock-day-over
|
||||
|
|
@ -629,12 +629,12 @@ that variable's documentation."
|
|||
(timeclock-time-to-date (current-time)))
|
||||
(run-hooks 'timeclock-day-over-hook))
|
||||
(setq timeclock-mode-string
|
||||
(propertize
|
||||
(format " %c%s%c "
|
||||
(if last-in ?< ?[)
|
||||
(timeclock-seconds-to-string remainder nil t)
|
||||
(propertize
|
||||
(format " %c%s%c "
|
||||
(if last-in ?< ?[)
|
||||
(timeclock-seconds-to-string remainder nil t)
|
||||
(if last-in ?> ?]))
|
||||
'help-echo "timeclock: time remaining"))))
|
||||
'help-echo "timeclock: time remaining"))))
|
||||
|
||||
(put 'timeclock-mode-string 'risky-local-variable t)
|
||||
|
||||
|
|
|
|||
136
valexpr.cc
136
valexpr.cc
|
|
@ -4,9 +4,6 @@
|
|||
#include "datetime.h"
|
||||
#include "debug.h"
|
||||
#include "util.h"
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
#include "py_eval.h"
|
||||
#endif
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
@ -325,16 +322,6 @@ void value_expr_t::compute(value_t& result, const details_t& details) const
|
|||
break;
|
||||
}
|
||||
|
||||
case F_INTERP_FUNC: {
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
if (! python_call(constant_s, right, details, result))
|
||||
result = 0L;
|
||||
#else
|
||||
result = 0L;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case O_NOT:
|
||||
left->compute(result, details);
|
||||
result.negate();
|
||||
|
|
@ -594,34 +581,6 @@ value_expr_t * parse_value_term(std::istream& in)
|
|||
break;
|
||||
}
|
||||
|
||||
case '@': {
|
||||
READ_INTO(in, buf, 255, c, c != '(');
|
||||
if (c != '(')
|
||||
unexpected(c, '(');
|
||||
|
||||
node.reset(new value_expr_t(value_expr_t::F_INTERP_FUNC));
|
||||
node->constant_s = buf;
|
||||
|
||||
in.get(c);
|
||||
if (peek_next_nonws(in) == ')') {
|
||||
in.get(c);
|
||||
} else {
|
||||
node->right = new value_expr_t(value_expr_t::O_ARG);
|
||||
value_expr_t * cur = node->right;
|
||||
cur->left = parse_value_expr(in, true);
|
||||
in.get(c);
|
||||
while (! in.eof() && c == ',') {
|
||||
cur->right = new value_expr_t(value_expr_t::O_ARG);
|
||||
cur = cur->right;
|
||||
cur->left = parse_value_expr(in, true);
|
||||
in.get(c);
|
||||
}
|
||||
if (c != ')')
|
||||
unexpected(c, ')');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case '(':
|
||||
node.reset(parse_value_expr(in, true));
|
||||
in.get(c);
|
||||
|
|
@ -935,12 +894,6 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node)
|
|||
out << ')';
|
||||
break;
|
||||
|
||||
case value_expr_t::F_INTERP_FUNC:
|
||||
out << "F_INTERP[" << node->constant_s << "](";
|
||||
dump_value_expr(out, node->right);
|
||||
out << ')';
|
||||
break;
|
||||
|
||||
case value_expr_t::O_NOT:
|
||||
out << '!';
|
||||
dump_value_expr(out, node->left);
|
||||
|
|
@ -1022,95 +975,6 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node)
|
|||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
value_t py_compute_1(value_expr_t& value_expr, const details_t& item)
|
||||
{
|
||||
value_t result;
|
||||
value_expr.compute(result, item);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
value_t py_compute(value_expr_t& value_expr, const T& item)
|
||||
{
|
||||
value_t result;
|
||||
value_expr.compute(result, details_t(item));
|
||||
return result;
|
||||
}
|
||||
|
||||
value_expr_t * py_parse_value_expr_1(const std::string& str)
|
||||
{
|
||||
return parse_value_expr(str);
|
||||
}
|
||||
|
||||
value_expr_t * py_parse_value_expr_2(const std::string& str, const bool partial)
|
||||
{
|
||||
return parse_value_expr(str, partial);
|
||||
}
|
||||
|
||||
#define EXC_TRANSLATOR(type) \
|
||||
void exc_translate_ ## type(const type& err) { \
|
||||
PyErr_SetString(PyExc_RuntimeError, err.what()); \
|
||||
}
|
||||
|
||||
EXC_TRANSLATOR(value_expr_error)
|
||||
EXC_TRANSLATOR(compute_error)
|
||||
EXC_TRANSLATOR(mask_error)
|
||||
|
||||
void export_valexpr()
|
||||
{
|
||||
class_< details_t > ("Details", init<const entry_t&>())
|
||||
.def(init<const transaction_t&>())
|
||||
.def(init<const account_t&>())
|
||||
.add_property("entry",
|
||||
make_getter(&details_t::entry,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
.add_property("xact",
|
||||
make_getter(&details_t::xact,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
.add_property("account",
|
||||
make_getter(&details_t::account,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
;
|
||||
|
||||
class_< value_expr_t > ("ValueExpr", init<value_expr_t::kind_t>())
|
||||
.def("compute", py_compute_1)
|
||||
.def("compute", py_compute<account_t>)
|
||||
.def("compute", py_compute<entry_t>)
|
||||
.def("compute", py_compute<transaction_t>)
|
||||
;
|
||||
|
||||
def("parse_value_expr", py_parse_value_expr_1,
|
||||
return_value_policy<manage_new_object>());
|
||||
def("parse_value_expr", py_parse_value_expr_2,
|
||||
return_value_policy<manage_new_object>());
|
||||
|
||||
class_< item_predicate<transaction_t> >
|
||||
("TransactionPredicate", init<std::string>())
|
||||
.def("__call__", &item_predicate<transaction_t>::operator())
|
||||
;
|
||||
|
||||
class_< item_predicate<account_t> >
|
||||
("AccountPredicate", init<std::string>())
|
||||
.def("__call__", &item_predicate<account_t>::operator())
|
||||
;
|
||||
|
||||
#define EXC_TRANSLATE(type) \
|
||||
register_exception_translator<type>(&exc_translate_ ## type);
|
||||
|
||||
EXC_TRANSLATE(value_expr_error);
|
||||
EXC_TRANSLATE(compute_error);
|
||||
EXC_TRANSLATE(mask_error);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ struct value_expr_t
|
|||
F_ACCOUNT_MASK,
|
||||
F_SHORT_ACCOUNT_MASK,
|
||||
F_COMMODITY_MASK,
|
||||
F_INTERP_FUNC,
|
||||
|
||||
// Binary operators
|
||||
O_ADD,
|
||||
|
|
|
|||
270
value.cc
270
value.cc
|
|
@ -790,273 +790,3 @@ value_t& value_t::add(const amount_t& amount, const amount_t * cost)
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
long balance_len(balance_t& bal);
|
||||
amount_t balance_getitem(balance_t& bal, int i);
|
||||
long balance_pair_len(balance_pair_t& bal_pair);
|
||||
amount_t balance_pair_getitem(balance_pair_t& bal_pair, int i);
|
||||
|
||||
long value_len(value_t& value)
|
||||
{
|
||||
switch (value.type) {
|
||||
case value_t::BOOLEAN:
|
||||
case value_t::INTEGER:
|
||||
case value_t::AMOUNT:
|
||||
return 1;
|
||||
|
||||
case value_t::BALANCE:
|
||||
return balance_len(*((balance_t *) value.data));
|
||||
|
||||
case value_t::BALANCE_PAIR:
|
||||
return balance_pair_len(*((balance_pair_t *) value.data));
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
amount_t value_getitem(value_t& value, int i)
|
||||
{
|
||||
std::size_t len = value_len(value);
|
||||
|
||||
if (abs(i) >= len) {
|
||||
PyErr_SetString(PyExc_IndexError, "Index out of range");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
switch (value.type) {
|
||||
case value_t::BOOLEAN:
|
||||
case value_t::INTEGER:
|
||||
return long(value);
|
||||
|
||||
case value_t::AMOUNT:
|
||||
return *((amount_t *) value.data);
|
||||
|
||||
case value_t::BALANCE:
|
||||
return balance_getitem(*((balance_t *) value.data), i);
|
||||
|
||||
case value_t::BALANCE_PAIR:
|
||||
return balance_pair_getitem(*((balance_pair_t *) value.data), i);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
assert(0);
|
||||
return 0L;
|
||||
}
|
||||
|
||||
double py_to_float(value_t& value)
|
||||
{
|
||||
return double(value);
|
||||
}
|
||||
|
||||
void export_value()
|
||||
{
|
||||
scope in_value = class_< value_t > ("Value")
|
||||
.def(init<value_t>())
|
||||
.def(init<balance_pair_t>())
|
||||
.def(init<balance_t>())
|
||||
.def(init<amount_t>())
|
||||
.def(init<std::string>())
|
||||
.def(init<double>())
|
||||
.def(init<long>())
|
||||
|
||||
.def(self + self)
|
||||
.def(self + other<balance_pair_t>())
|
||||
.def(self + other<balance_t>())
|
||||
.def(self + other<amount_t>())
|
||||
.def(self + long())
|
||||
.def(self + double())
|
||||
|
||||
.def(other<balance_pair_t>() + self)
|
||||
.def(other<balance_t>() + self)
|
||||
.def(other<amount_t>() + self)
|
||||
.def(long() + self)
|
||||
.def(double() + self)
|
||||
|
||||
.def(self - self)
|
||||
.def(self - other<balance_pair_t>())
|
||||
.def(self - other<balance_t>())
|
||||
.def(self - other<amount_t>())
|
||||
.def(self - long())
|
||||
.def(self - double())
|
||||
|
||||
.def(other<balance_pair_t>() - self)
|
||||
.def(other<balance_t>() - self)
|
||||
.def(other<amount_t>() - self)
|
||||
.def(long() - self)
|
||||
.def(double() - self)
|
||||
|
||||
.def(self * self)
|
||||
.def(self * other<balance_pair_t>())
|
||||
.def(self * other<balance_t>())
|
||||
.def(self * other<amount_t>())
|
||||
.def(self * long())
|
||||
.def(self * double())
|
||||
|
||||
.def(other<balance_pair_t>() * self)
|
||||
.def(other<balance_t>() * self)
|
||||
.def(other<amount_t>() * self)
|
||||
.def(long() * self)
|
||||
.def(double() * self)
|
||||
|
||||
.def(self / self)
|
||||
.def(self / other<balance_pair_t>())
|
||||
.def(self / other<balance_t>())
|
||||
.def(self / other<amount_t>())
|
||||
.def(self / long())
|
||||
.def(self / double())
|
||||
|
||||
.def(other<balance_pair_t>() / self)
|
||||
.def(other<balance_t>() / self)
|
||||
.def(other<amount_t>() / self)
|
||||
.def(long() / self)
|
||||
.def(double() / self)
|
||||
|
||||
.def(- self)
|
||||
|
||||
.def(self += self)
|
||||
.def(self += other<balance_pair_t>())
|
||||
.def(self += other<balance_t>())
|
||||
.def(self += other<amount_t>())
|
||||
.def(self += long())
|
||||
.def(self += double())
|
||||
|
||||
.def(self -= self)
|
||||
.def(self -= other<balance_pair_t>())
|
||||
.def(self -= other<balance_t>())
|
||||
.def(self -= other<amount_t>())
|
||||
.def(self -= long())
|
||||
.def(self -= double())
|
||||
|
||||
.def(self *= self)
|
||||
.def(self *= other<balance_pair_t>())
|
||||
.def(self *= other<balance_t>())
|
||||
.def(self *= other<amount_t>())
|
||||
.def(self *= long())
|
||||
.def(self *= double())
|
||||
|
||||
.def(self /= self)
|
||||
.def(self /= other<balance_pair_t>())
|
||||
.def(self /= other<balance_t>())
|
||||
.def(self /= other<amount_t>())
|
||||
.def(self /= long())
|
||||
.def(self /= double())
|
||||
|
||||
.def(self < self)
|
||||
.def(self < other<balance_pair_t>())
|
||||
.def(self < other<balance_t>())
|
||||
.def(self < other<amount_t>())
|
||||
.def(self < long())
|
||||
.def(self < double())
|
||||
|
||||
.def(other<balance_pair_t>() < self)
|
||||
.def(other<balance_t>() < self)
|
||||
.def(other<amount_t>() < self)
|
||||
.def(long() < self)
|
||||
.def(double() < self)
|
||||
|
||||
.def(self <= self)
|
||||
.def(self <= other<balance_pair_t>())
|
||||
.def(self <= other<balance_t>())
|
||||
.def(self <= other<amount_t>())
|
||||
.def(self <= long())
|
||||
.def(self <= double())
|
||||
|
||||
.def(other<balance_pair_t>() <= self)
|
||||
.def(other<balance_t>() <= self)
|
||||
.def(other<amount_t>() <= self)
|
||||
.def(long() <= self)
|
||||
.def(double() <= self)
|
||||
|
||||
.def(self > self)
|
||||
.def(self > other<balance_pair_t>())
|
||||
.def(self > other<balance_t>())
|
||||
.def(self > other<amount_t>())
|
||||
.def(self > long())
|
||||
.def(self > double())
|
||||
|
||||
.def(other<balance_pair_t>() > self)
|
||||
.def(other<balance_t>() > self)
|
||||
.def(other<amount_t>() > self)
|
||||
.def(long() > self)
|
||||
.def(double() > self)
|
||||
|
||||
.def(self >= self)
|
||||
.def(self >= other<balance_pair_t>())
|
||||
.def(self >= other<balance_t>())
|
||||
.def(self >= other<amount_t>())
|
||||
.def(self >= long())
|
||||
.def(self >= double())
|
||||
|
||||
.def(other<balance_pair_t>() >= self)
|
||||
.def(other<balance_t>() >= self)
|
||||
.def(other<amount_t>() >= self)
|
||||
.def(long() >= self)
|
||||
.def(double() >= self)
|
||||
|
||||
.def(self == self)
|
||||
.def(self == other<balance_pair_t>())
|
||||
.def(self == other<balance_t>())
|
||||
.def(self == other<amount_t>())
|
||||
.def(self == long())
|
||||
.def(self == double())
|
||||
|
||||
.def(other<balance_pair_t>() == self)
|
||||
.def(other<balance_t>() == self)
|
||||
.def(other<amount_t>() == self)
|
||||
.def(long() == self)
|
||||
.def(double() == self)
|
||||
|
||||
.def(self != self)
|
||||
.def(self != other<balance_pair_t>())
|
||||
.def(self != other<balance_t>())
|
||||
.def(self != other<amount_t>())
|
||||
.def(self != long())
|
||||
.def(self != double())
|
||||
|
||||
.def(other<balance_pair_t>() != self)
|
||||
.def(other<balance_t>() != self)
|
||||
.def(other<amount_t>() != self)
|
||||
.def(long() != self)
|
||||
.def(double() != self)
|
||||
|
||||
.def(! self)
|
||||
|
||||
.def(self_ns::int_(self))
|
||||
.def(self_ns::float_(self))
|
||||
.def(self_ns::str(self))
|
||||
.def(abs(self))
|
||||
|
||||
.def_readonly("type", &value_t::type)
|
||||
|
||||
.def("__len__", value_len)
|
||||
.def("__getitem__", value_getitem)
|
||||
|
||||
.def("cast", &value_t::cast)
|
||||
.def("negate", &value_t::negate)
|
||||
.def("cost", &value_t::cost)
|
||||
.def("add", &value_t::add, return_internal_reference<1>())
|
||||
;
|
||||
|
||||
enum_< value_t::type_t > ("ValueType")
|
||||
.value("BOOLEAN", value_t::BOOLEAN)
|
||||
.value("INTEGER", value_t::INTEGER)
|
||||
.value("AMOUNT", value_t::AMOUNT)
|
||||
.value("BALANCE", value_t::BALANCE)
|
||||
.value("BALANCE_PAIR", value_t::BALANCE_PAIR)
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
305
walk.cc
305
walk.cc
|
|
@ -843,308 +843,3 @@ void walk_commodities(commodities_map& commodities,
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
template <typename T>
|
||||
struct item_handler_wrap : public item_handler<T>
|
||||
{
|
||||
PyObject * self;
|
||||
|
||||
item_handler_wrap(PyObject * self_) : self(self_) {}
|
||||
item_handler_wrap(PyObject * self_, const item_handler<T>& _handler)
|
||||
: item_handler<T>(const_cast<item_handler<T> *>(&_handler)),
|
||||
self(self_) {}
|
||||
item_handler_wrap(PyObject * self_, item_handler<T> * _handler)
|
||||
: item_handler<T>(_handler), self(self_) {}
|
||||
|
||||
virtual void flush() {
|
||||
call_method<void>(self, "flush");
|
||||
}
|
||||
void default_flush() {
|
||||
item_handler<T>::flush();
|
||||
}
|
||||
|
||||
virtual void operator()(T& item) {
|
||||
call_method<void>(self, "__call__", ptr(&item));
|
||||
}
|
||||
void default_call(T& item) {
|
||||
item_handler<T>::operator()(item);
|
||||
}
|
||||
};
|
||||
|
||||
void (subtotal_transactions::*subtotal_transactions_flush)() =
|
||||
&subtotal_transactions::flush;
|
||||
|
||||
void py_walk_entries(journal_t& journal,
|
||||
item_handler<transaction_t>& handler) {
|
||||
walk_entries(journal.entries, handler);
|
||||
}
|
||||
|
||||
void py_walk_transactions(entry_t& entry,
|
||||
item_handler<transaction_t>& handler) {
|
||||
walk_transactions(entry.transactions, handler);
|
||||
}
|
||||
|
||||
void py_walk_accounts_1(account_t& account,
|
||||
item_handler<account_t>& handler) {
|
||||
walk_accounts(account, handler);
|
||||
}
|
||||
|
||||
void py_walk_accounts_2(account_t& account,
|
||||
item_handler<account_t>& handler,
|
||||
const value_expr_t * sort_order) {
|
||||
walk_accounts(account, handler, sort_order);
|
||||
}
|
||||
|
||||
void py_walk_accounts_3(account_t& account,
|
||||
item_handler<account_t>& handler,
|
||||
const std::string& sort_string) {
|
||||
walk_accounts(account, handler, sort_string);
|
||||
}
|
||||
|
||||
void py_walk_commodities(item_handler<transaction_t>& handler) {
|
||||
walk_commodities(commodity_t::commodities, handler);
|
||||
}
|
||||
|
||||
void py_add_period_entries(generate_transactions& handler,
|
||||
journal_t * journal) {
|
||||
handler.add_period_entries(journal->period_entries);
|
||||
}
|
||||
|
||||
void export_walk()
|
||||
{
|
||||
typedef item_handler<transaction_t> xact_handler_t;
|
||||
|
||||
scope().attr("TRANSACTION_RECEIVED") = TRANSACTION_RECEIVED;
|
||||
scope().attr("TRANSACTION_HANDLED") = TRANSACTION_HANDLED;
|
||||
scope().attr("TRANSACTION_TO_DISPLAY") = TRANSACTION_TO_DISPLAY;
|
||||
scope().attr("TRANSACTION_DISPLAYED") = TRANSACTION_DISPLAYED;
|
||||
scope().attr("TRANSACTION_NO_TOTAL") = TRANSACTION_NO_TOTAL;
|
||||
scope().attr("TRANSACTION_SORT_CALC") = TRANSACTION_SORT_CALC;
|
||||
scope().attr("TRANSACTION_COMPOSITE") = TRANSACTION_COMPOSITE;
|
||||
scope().attr("TRANSACTION_MATCHES") = TRANSACTION_MATCHES;
|
||||
|
||||
class_< transaction_xdata_t > ("TransactionXData")
|
||||
.def_readwrite("total", &transaction_xdata_t::total)
|
||||
.def_readwrite("sort_value", &transaction_xdata_t::sort_value)
|
||||
.def_readwrite("composite_amount", &transaction_xdata_t::composite_amount)
|
||||
.def_readwrite("index", &transaction_xdata_t::index)
|
||||
.def_readwrite("dflags", &transaction_xdata_t::dflags)
|
||||
;
|
||||
|
||||
def("transaction_has_xdata", transaction_has_xdata);
|
||||
def("transaction_xdata", transaction_xdata, return_internal_reference<1>());
|
||||
def("add_transaction_to", add_transaction_to);
|
||||
|
||||
class_< xact_handler_t, item_handler_wrap<transaction_t> >
|
||||
("TransactionHandler")
|
||||
.def(init<xact_handler_t *>()[with_custodian_and_ward<1, 2>()])
|
||||
|
||||
.def("flush", &xact_handler_t::flush,
|
||||
&item_handler_wrap<transaction_t>::default_flush)
|
||||
.def("__call__", &xact_handler_t::operator(),
|
||||
&item_handler_wrap<transaction_t>::default_call)
|
||||
;
|
||||
|
||||
class_< ignore_transactions, bases<xact_handler_t> >
|
||||
("IgnoreTransactions")
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &ignore_transactions::operator());
|
||||
;
|
||||
|
||||
class_< clear_transaction_xdata, bases<xact_handler_t> >
|
||||
("ClearTransactionXData")
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &clear_transaction_xdata::operator());
|
||||
;
|
||||
|
||||
class_< truncate_entries, bases<xact_handler_t> >
|
||||
("TruncateEntries", init<xact_handler_t *, int, int>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &truncate_entries::flush)
|
||||
.def("__call__", &truncate_entries::operator());
|
||||
;
|
||||
|
||||
class_< set_account_value, bases<xact_handler_t> > ("SetAccountValue")
|
||||
.def(init<xact_handler_t *>()[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &set_account_value::operator());
|
||||
;
|
||||
|
||||
class_< sort_transactions, bases<xact_handler_t> >
|
||||
("SortTransactions", init<xact_handler_t *, const value_expr_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def(init<xact_handler_t *, const std::string&>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &sort_transactions::flush)
|
||||
.def("__call__", &sort_transactions::operator());
|
||||
;
|
||||
|
||||
class_< filter_transactions, bases<xact_handler_t> >
|
||||
("FilterTransactions", init<xact_handler_t *, std::string>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def(init<xact_handler_t *, const std::string&>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &filter_transactions::operator());
|
||||
;
|
||||
|
||||
class_< calc_transactions, bases<xact_handler_t> >
|
||||
("CalcTransactions", init<xact_handler_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &calc_transactions::operator());
|
||||
;
|
||||
|
||||
class_< invert_transactions, bases<xact_handler_t> >
|
||||
("InvertTransactions", init<xact_handler_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &invert_transactions::operator());
|
||||
;
|
||||
|
||||
class_< collapse_transactions, bases<xact_handler_t> >
|
||||
("CollapseTransactions", init<xact_handler_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &collapse_transactions::flush)
|
||||
.def("__call__", &collapse_transactions::operator());
|
||||
;
|
||||
|
||||
class_< related_transactions, bases<xact_handler_t> >
|
||||
("RelatedTransactions", init<xact_handler_t *, optional<bool> >()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &related_transactions::operator());
|
||||
;
|
||||
|
||||
class_< changed_value_transactions, bases<xact_handler_t> >
|
||||
("ChangeValueTransactions", init<xact_handler_t *, bool>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &changed_value_transactions::flush)
|
||||
.def("__call__", &changed_value_transactions::operator());
|
||||
;
|
||||
|
||||
class_< subtotal_transactions, bases<xact_handler_t> >
|
||||
("SubtotalTransactions", init<xact_handler_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", subtotal_transactions_flush)
|
||||
.def("__call__", &subtotal_transactions::operator());
|
||||
;
|
||||
|
||||
class_< interval_transactions, bases<xact_handler_t> >
|
||||
("IntervalTransactions",
|
||||
init<xact_handler_t *, interval_t, optional<value_expr_t *> >()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def(init<xact_handler_t *, const std::string&,
|
||||
optional<const std::string&> >()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &interval_transactions::operator());
|
||||
;
|
||||
|
||||
class_< by_payee_transactions, bases<xact_handler_t> >
|
||||
("ByPayeeTransactions", init<xact_handler_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &by_payee_transactions::flush)
|
||||
.def("__call__", &by_payee_transactions::operator());
|
||||
;
|
||||
|
||||
class_< set_comm_as_payee, bases<xact_handler_t> >
|
||||
("SetCommAsPayee", init<xact_handler_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &xact_handler_t::operator());
|
||||
;
|
||||
|
||||
class_< dow_transactions, bases<xact_handler_t> >
|
||||
("DowTransactions", init<xact_handler_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &dow_transactions::flush)
|
||||
.def("__call__", &dow_transactions::operator());
|
||||
;
|
||||
|
||||
scope().attr("BUDGET_BUDGETED") = BUDGET_BUDGETED;
|
||||
scope().attr("BUDGET_UNBUDGETED") = BUDGET_UNBUDGETED;
|
||||
|
||||
class_< generate_transactions, bases<xact_handler_t> >
|
||||
("GenerateTransactions", init<xact_handler_t *>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("add_transaction", &generate_transactions::add_transaction)
|
||||
.def("add_period_entries", py_add_period_entries)
|
||||
.def("flush", &xact_handler_t::flush)
|
||||
.def("__call__", &xact_handler_t::operator());
|
||||
;
|
||||
|
||||
class_< budget_transactions, bases<generate_transactions> >
|
||||
("BudgetTransactions",
|
||||
init<xact_handler_t *, unsigned long>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("add_transaction", &generate_transactions::add_transaction)
|
||||
.def("add_period_entries", py_add_period_entries)
|
||||
.def("flush", &budget_transactions::flush)
|
||||
.def("__call__", &xact_handler_t::operator());
|
||||
;
|
||||
|
||||
class_< forecast_transactions, bases<generate_transactions> >
|
||||
("ForecastTransactions",
|
||||
init<xact_handler_t *, std::string>()
|
||||
[with_custodian_and_ward<1, 2>()])
|
||||
.def("add_transaction", &forecast_transactions::add_transaction)
|
||||
.def("add_period_entries", py_add_period_entries)
|
||||
.def("flush", &forecast_transactions::flush)
|
||||
.def("__call__", &xact_handler_t::operator());
|
||||
;
|
||||
|
||||
def("walk_entries", py_walk_entries);
|
||||
def("walk_transactions", py_walk_transactions);
|
||||
|
||||
typedef item_handler<account_t> account_handler_t;
|
||||
|
||||
scope().attr("ACCOUNT_TO_DISPLAY") = ACCOUNT_TO_DISPLAY;
|
||||
scope().attr("ACCOUNT_DISPLAYED") = ACCOUNT_DISPLAYED;
|
||||
scope().attr("ACCOUNT_SORT_CALC") = ACCOUNT_SORT_CALC;
|
||||
|
||||
class_< account_xdata_t > ("AccountXData")
|
||||
.def_readwrite("value", &account_xdata_t::value)
|
||||
.def_readwrite("total", &account_xdata_t::total)
|
||||
.def_readwrite("sort_value", &account_xdata_t::sort_value)
|
||||
.def_readwrite("count", &account_xdata_t::count)
|
||||
.def_readwrite("total_count", &account_xdata_t::total_count)
|
||||
.def_readwrite("virtuals", &account_xdata_t::virtuals)
|
||||
.def_readwrite("dflags", &account_xdata_t::dflags)
|
||||
;
|
||||
|
||||
def("account_has_xdata", account_has_xdata);
|
||||
def("account_xdata", account_xdata, return_internal_reference<1>());
|
||||
|
||||
class_< account_handler_t, item_handler_wrap<account_t> >
|
||||
("AccountHandler")
|
||||
.def(init<account_handler_t *>()[with_custodian_and_ward<1, 2>()])
|
||||
|
||||
.def("flush", &account_handler_t::flush,
|
||||
&item_handler_wrap<account_t>::default_flush)
|
||||
.def("__call__", &account_handler_t::operator(),
|
||||
&item_handler_wrap<account_t>::default_call)
|
||||
;
|
||||
|
||||
class_< clear_account_xdata, bases<account_handler_t> >
|
||||
("ClearAccountXData")
|
||||
.def("flush", &account_handler_t::flush)
|
||||
.def("__call__", &clear_account_xdata::operator());
|
||||
;
|
||||
|
||||
def("sum_accounts", sum_accounts);
|
||||
def("walk_accounts", py_walk_accounts_1);
|
||||
def("walk_accounts", py_walk_accounts_2);
|
||||
def("walk_accounts", py_walk_accounts_3);
|
||||
|
||||
def("walk_commodities", py_walk_commodities);
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
30
xml.cc
30
xml.cc
|
|
@ -442,33 +442,3 @@ void format_xml_entries::format_last_entry()
|
|||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace ledger;
|
||||
|
||||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xml_parse_overloads,
|
||||
xml_parser_t::parse, 2, 4)
|
||||
|
||||
void export_xml() {
|
||||
class_< xml_parser_t, bases<parser_t> > ("XmlParser")
|
||||
.def("test", &xml_parser_t::test)
|
||||
.def("parse", &xml_parser_t::parse, xml_parse_overloads())
|
||||
;
|
||||
|
||||
typedef
|
||||
pystream_handler_wrap<format_xml_entries, transaction_t, bool>
|
||||
format_xml_entries_wrap;
|
||||
|
||||
class_< format_xml_entries_wrap, bases<item_handler<transaction_t> > >
|
||||
("FormatXmlEntries",
|
||||
init<PyObject *, bool>()[with_custodian_and_ward<1, 2>()])
|
||||
.def("flush", &format_xml_entries_wrap::flush)
|
||||
.def("__call__", &format_xml_entries_wrap::operator())
|
||||
;
|
||||
}
|
||||
|
||||
#endif // USE_BOOST_PYTHON
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue