Merge branch 'next'

This commit is contained in:
John Wiegley 2009-11-21 15:19:42 -05:00
commit f01fa1a513
33 changed files with 693 additions and 49 deletions

View file

@ -33,9 +33,21 @@ available for testing and more useful bug reports.
===============================================================================
F.A.Q.
IF YOU HAVE CONFIGURE OR BUILD PROBLEMS
----------------------------------------------------------------------
The first order of business if acprep update doesn't work is to find out where
things went wrong. So follow these steps to produce a bug report I can track
down easily:
$ ./acprep --debug update # shows what acprep was thinking
$ <edit config.log> # shows what configure was thinking
With the contents of config.log, and the output from acprep --debug update,
it's usually fairly obvious where things have gone astray.
===============================================================================
F.A.Q.
- Q: The build fails saying it can't find utf8.h
@ -65,6 +77,14 @@ available for testing and more useful bug reports.
----------------------------------------------------------------------
- Q: I'm seeing a segfault deep inside the boost_regex code!
A: Actually, the real segfault is in libstdc++'s facet code. It's being
caused by using a debug Boost with a non-debug build of Ledger, or
vice-versa.
----------------------------------------------------------------------
- Q: Something else fails, or Ledger crashes on startup
A: This, I am most interested in hearing about. Please e-mail me a copy of
@ -98,5 +118,3 @@ available for testing and more useful bug reports.
A: This can happen for the same reason as above. It can also happen if you
have ICU support enabled. This is a bug I'm still trying to track down.
----------------------------------------------------------------------

BIN
python/res/asc.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 B

BIN
python/res/bg.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

BIN
python/res/desc.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 B

BIN
python/res/icons/first.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

BIN
python/res/icons/last.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

BIN
python/res/icons/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

BIN
python/res/icons/prev.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 B

32
python/res/jquery-latest.js vendored Normal file

File diff suppressed because one or more lines are too long

12
python/res/jquery.dimensions.min.js vendored Normal file
View file

@ -0,0 +1,12 @@
/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* $LastChangedDate: 2007-12-20 08:43:48 -0600 (Thu, 20 Dec 2007) $
* $Rev: 4257 $
*
* Version: 1.2
*
* Requires: jQuery 1.2+
*/
(function($){$.dimensions={version:'1.2'};$.each(['Height','Width'],function(i,name){$.fn['inner'+name]=function(){if(!this[0])return;var torl=name=='Height'?'Top':'Left',borr=name=='Height'?'Bottom':'Right';return this.is(':visible')?this[0]['client'+name]:num(this,name.toLowerCase())+num(this,'padding'+torl)+num(this,'padding'+borr);};$.fn['outer'+name]=function(options){if(!this[0])return;var torl=name=='Height'?'Top':'Left',borr=name=='Height'?'Bottom':'Right';options=$.extend({margin:false},options||{});var val=this.is(':visible')?this[0]['offset'+name]:num(this,name.toLowerCase())+num(this,'border'+torl+'Width')+num(this,'border'+borr+'Width')+num(this,'padding'+torl)+num(this,'padding'+borr);return val+(options.margin?(num(this,'margin'+torl)+num(this,'margin'+borr)):0);};});$.each(['Left','Top'],function(i,name){$.fn['scroll'+name]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(name=='Left'?val:$(window)['scrollLeft'](),name=='Top'?val:$(window)['scrollTop']()):this['scroll'+name]=val;}):this[0]==window||this[0]==document?self[(name=='Left'?'pageXOffset':'pageYOffset')]||$.boxModel&&document.documentElement['scroll'+name]||document.body['scroll'+name]:this[0]['scroll'+name];};});$.fn.extend({position:function(){var left=0,top=0,elem=this[0],offset,parentOffset,offsetParent,results;if(elem){offsetParent=this.offsetParent();offset=this.offset();parentOffset=offsetParent.offset();offset.top-=num(elem,'marginTop');offset.left-=num(elem,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&$.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return $(offsetParent);}});function num(el,prop){return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;};})(jQuery);

View file

@ -0,0 +1,122 @@
/*
* Metadata - jQuery plugin for parsing metadata from elements
*
* Copyright (c) 2006 John Resig, Yehuda Katz, J<EFBFBD>örn Zaefferer, Paul McLanahan
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Revision: $Id$
*
*/
/**
* Sets the type of metadata to use. Metadata is encoded in JSON, and each property
* in the JSON will become a property of the element itself.
*
* There are three supported types of metadata storage:
*
* attr: Inside an attribute. The name parameter indicates *which* attribute.
*
* class: Inside the class attribute, wrapped in curly braces: { }
*
* elem: Inside a child element (e.g. a script tag). The
* name parameter indicates *which* element.
*
* The metadata for an element is loaded the first time the element is accessed via jQuery.
*
* As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
* matched by expr, then redefine the metadata type and run another $(expr) for other elements.
*
* @name $.metadata.setType
*
* @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
* @before $.metadata.setType("class")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from the class attribute
*
* @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
* @before $.metadata.setType("attr", "data")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from a "data" attribute
*
* @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
* @before $.metadata.setType("elem", "script")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from a nested script element
*
* @param String type The encoding type
* @param String name The name of the attribute to be used to get metadata (optional)
* @cat Plugins/Metadata
* @descr Sets the type of encoding to be used when loading metadata for the first time
* @type undefined
* @see metadata()
*/
(function($) {
$.extend({
metadata : {
defaults : {
type: 'class',
name: 'metadata',
cre: /({.*})/,
single: 'metadata'
},
setType: function( type, name ){
this.defaults.type = type;
this.defaults.name = name;
},
get: function( elem, opts ){
var settings = $.extend({},this.defaults,opts);
// check for empty string in single property
if ( !settings.single.length ) settings.single = 'metadata';
var data = $.data(elem, settings.single);
// returned cached data if it already exists
if ( data ) return data;
data = "{}";
if ( settings.type == "class" ) {
var m = settings.cre.exec( elem.className );
if ( m )
data = m[1];
} else if ( settings.type == "elem" ) {
if( !elem.getElementsByTagName )
return undefined;
var e = elem.getElementsByTagName(settings.name);
if ( e.length )
data = $.trim(e[0].innerHTML);
} else if ( elem.getAttribute != undefined ) {
var attr = elem.getAttribute( settings.name );
if ( attr )
data = attr;
}
if ( data.indexOf( '{' ) <0 )
data = "{" + data + "}";
data = eval("(" + data + ")");
$.data( elem, settings.single, data );
return data;
}
}
});
/**
* Returns the metadata object for the first member of the jQuery object.
*
* @name metadata
* @descr Returns element's metadata object
* @param Object opts An object contianing settings to override the defaults
* @type jQuery
* @cat Plugins/Metadata
*/
$.fn.metadata = function( opts ){
return $.metadata.get( this[0], opts );
};
})(jQuery);

2
python/res/jquery.tablesorter.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,25 @@
div.tablesorterPager {
padding: 10px 0 10px 0;
background-color: #D6D2C2;
text-align: center;
}
div.tablesorterPager span {
padding: 0 5px 0 5px;
}
div.tablesorterPager input.prev {
width: auto;
margin-right: 10px;
}
div.tablesorterPager input.next {
width: auto;
margin-left: 10px;
}
div.tablesorterPager input {
font-size: 8px;
width: 50px;
border: 1px solid #330000;
text-align: center;
}

View file

@ -0,0 +1,184 @@
(function($) {
$.extend({
tablesorterPager: new function() {
function updatePageDisplay(c) {
var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);
}
function setPageSize(table,size) {
var c = table.config;
c.size = size;
c.totalPages = Math.ceil(c.totalRows / c.size);
c.pagerPositionSet = false;
moveToPage(table);
fixPosition(table);
}
function fixPosition(table) {
var c = table.config;
if(!c.pagerPositionSet && c.positionFixed) {
var c = table.config, o = $(table);
if(o.offset) {
c.container.css({
top: o.offset().top + o.height() + 'px',
position: 'absolute'
});
}
c.pagerPositionSet = true;
}
}
function moveToFirstPage(table) {
var c = table.config;
c.page = 0;
moveToPage(table);
}
function moveToLastPage(table) {
var c = table.config;
c.page = (c.totalPages-1);
moveToPage(table);
}
function moveToNextPage(table) {
var c = table.config;
c.page++;
if(c.page >= (c.totalPages-1)) {
c.page = (c.totalPages-1);
}
moveToPage(table);
}
function moveToPrevPage(table) {
var c = table.config;
c.page--;
if(c.page <= 0) {
c.page = 0;
}
moveToPage(table);
}
function moveToPage(table) {
var c = table.config;
if(c.page < 0 || c.page > (c.totalPages-1)) {
c.page = 0;
}
renderTable(table,c.rowsCopy);
}
function renderTable(table,rows) {
var c = table.config;
var l = rows.length;
var s = (c.page * c.size);
var e = (s + c.size);
if(e > rows.length ) {
e = rows.length;
}
var tableBody = $(table.tBodies[0]);
// clear the table body
$.tablesorter.clearTableBody(table);
for(var i = s; i < e; i++) {
//tableBody.append(rows[i]);
var o = rows[i];
var l = o.length;
for(var j=0; j < l; j++) {
tableBody[0].appendChild(o[j]);
}
}
fixPosition(table,tableBody);
$(table).trigger("applyWidgets");
if( c.page >= c.totalPages ) {
moveToLastPage(table);
}
updatePageDisplay(c);
}
this.appender = function(table,rows) {
var c = table.config;
c.rowsCopy = rows;
c.totalRows = rows.length;
c.totalPages = Math.ceil(c.totalRows / c.size);
renderTable(table,rows);
};
this.defaults = {
size: 10,
offset: 0,
page: 0,
totalRows: 0,
totalPages: 0,
container: null,
cssNext: '.next',
cssPrev: '.prev',
cssFirst: '.first',
cssLast: '.last',
cssPageDisplay: '.pagedisplay',
cssPageSize: '.pagesize',
seperator: "/",
positionFixed: true,
appender: this.appender
};
this.construct = function(settings) {
return this.each(function() {
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
var table = this, pager = config.container;
$(this).trigger("appendCache");
config.size = parseInt($(".pagesize",pager).val());
$(config.cssFirst,pager).click(function() {
moveToFirstPage(table);
return false;
});
$(config.cssNext,pager).click(function() {
moveToNextPage(table);
return false;
});
$(config.cssPrev,pager).click(function() {
moveToPrevPage(table);
return false;
});
$(config.cssLast,pager).click(function() {
moveToLastPage(table);
return false;
});
$(config.cssPageSize,pager).change(function() {
setPageSize(table,parseInt($(this).val()));
return false;
});
});
};
}
});
// extend plugin scope
$.fn.extend({
tablesorterPager: $.tablesorterPager.construct
});
})(jQuery);

39
python/res/style.css Normal file
View file

@ -0,0 +1,39 @@
/* tables */
table.tablesorter {
font-family:arial;
background-color: #CDCDCD;
margin:10px 0pt 15px;
font-size: 8pt;
width: 100%;
text-align: left;
}
table.tablesorter thead tr th, table.tablesorter tfoot tr th {
background-color: #e6EEEE;
border: 1px solid #FFF;
font-size: 8pt;
padding: 4px;
}
table.tablesorter thead tr .header {
background-image: url(bg.gif);
background-repeat: no-repeat;
background-position: center right;
cursor: pointer;
}
table.tablesorter tbody td {
color: #3D3D3D;
padding: 4px;
background-color: #FFF;
vertical-align: top;
}
table.tablesorter tbody tr.odd td {
background-color:#F0F0F6;
}
table.tablesorter thead tr .headerSortUp {
background-image: url(asc.gif);
}
table.tablesorter thead tr .headerSortDown {
background-image: url(desc.gif);
}
table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
background-color: #8dbdd8;
}

View file

@ -1,13 +1,132 @@
# -*- coding: utf-8 -*-
import ledger
import cgi
import sys
import types
import posixpath
import urllib
import shutil
import os
import re
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from os.path import exists, join, isfile
from Cheetah.Template import Template
from Cheetah.Filters import Filter, WebSafe
webroot = join(os.getcwd(), 'python', 'res')
class UnicodeFilter(Filter):
def filter(self, s, **kargs):
return Filter.filter(self, s, str=unicode, **kargs)
def strip(value):
#return re.sub('\n', '<br />', value.strip_annotations().to_string())
return value.strip_annotations().to_string()
templateDef = '''#encoding utf-8
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>$title</title>
<link rel="stylesheet" href="/style.css" type="text/css" media="print, projection, screen" />
<script type="text/javascript" src="/jquery-latest.js"></script>
<script type="text/javascript" src="/jquery.tablesorter.min.js"></script>
<script type="text/javascript" src="/jquery.tablesorter.pager.js"></script>
<script type="text/javascript" src="/jquery.dimensions.min.js"></script>
<script type="text/javascript">
\$(function() {
\$("table")
.tablesorter({textExtraction: 'complex',
widthFixed: true,
widgets: ['zebra']})
.tablesorterPager({size: 100,
container: \$("\#pager")});
});
</script>
</head>
<body>
<div id="main">
<h1>Register report</h1>
<table id="register" cellspacing="1" class="tablesorter">
<thead>
<tr>
<th>Date</th>
<th>Payee</th>
<th>Account</th>
<th>Amount</th>
<th>Total</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Date</th>
<th>Payee</th>
<th>Account</th>
<th>Amount</th>
<th>Total</th>
</tr>
</tfoot>
<tbody>
#for $post in $posts
#set $total = $total + $post.amount
<tr>
<!--<td>${$post.xact.date if $post.xact is not $last_xact else $empty}</td>
<td>${$post.xact.payee if $post.xact is not $last_xact else $empty}</td>-->
<td>$post.xact.date</td>
<td>$post.xact.payee</td>
<td>$post.account</td>
<td>${strip($post.amount)}</td>
<td>${strip($total)}</td>
</tr>
#set $last_xact = $post.xact
#end for
</tbody>
</table>
<div id="pager" class="pager">
<form>
<img src="/icons/first.png" class="first"/>
<img src="/icons/prev.png" class="prev"/>
<input type="text" class="pagedisplay"/>
<img src="/icons/next.png" class="next"/>
<img src="/icons/last.png" class="last"/>
<select class="pagesize">
<option selected="selected" value="40">40</option>
<option value="100">100</option>
<option value="200">200</option>
<option value="300">300</option>
</select>
</form>
</div>
</body>
</html>
'''
class LedgerHandler(BaseHTTPRequestHandler):
def __init__(self, *args):
self.journal = ledger.Journal(sys.argv[1])
BaseHTTPRequestHandler.__init__(self, *args)
def do_GET(self):
print "Saw a GET request!"
sys.exit(0)
path = self.translate_path(self.path)
if path and exists(path) and isfile(path):
self.copyfile(open(path), self.wfile)
else:
tmpl = Template(templateDef, filter=UnicodeFilter)
tmpl.title = 'Ledger Journal'
tmpl.posts = self.journal.collect(sys.argv[2])
tmpl.total = ledger.Value(0)
tmpl.strip = strip
tmpl.last_xact = None
tmpl.empty = ""
html = unicode(tmpl)
html = html.encode('utf-8')
self.wfile.write(html)
def do_POST(self):
print "Saw a POST request!"
@ -20,6 +139,45 @@ class LedgerHandler(BaseHTTPRequestHandler):
except Exception:
print "Saw exception in POST handler"
# This code is straight from SimpleHTTPServer.py
def copyfile(self, source, outputfile):
"""Copy all data between two file objects.
The SOURCE argument is a file object open for reading
(or anything with a read() method) and the DESTINATION
argument is a file object open for writing (or
anything with a write() method).
The only reason for overriding this would be to change
the block size or perhaps to replace newlines by CRLF
-- note however that this the default server uses this
to copy binary data as well.
"""
shutil.copyfileobj(source, outputfile)
def translate_path(self, path):
"""Translate a /-separated PATH to the local filename syntax.
Components that mean special things to the local file system
(e.g. drive or directory names) are ignored. (XXX They should
probably be diagnosed.)
"""
# abandon query parameters
path = path.split('?',1)[0]
path = path.split('#',1)[0]
path = posixpath.normpath(urllib.unquote(path))
words = path.split('/')
words = filter(None, words)
path = webroot
for word in words:
drive, word = os.path.splitdrive(word)
head, word = os.path.split(word)
if word in (os.curdir, os.pardir): continue
path = os.path.join(path, word)
return path
def main(*args):
try:
port = 9000
@ -31,6 +189,8 @@ def main(*args):
print "Shutting down server"
server.socket.close()
print __name__
if __name__ == '__main__':
if len(sys.argv) < 3:
print "usage: server.py <DATA-FILE> <REPORT-QUERY>"
sys.exit(1)
main()

View file

@ -496,6 +496,9 @@ public:
long to_long() const;
bool fits_in_long() const;
operator string() const {
return to_string();
}
string to_string() const;
string to_fullstring() const;
string quantity_string() const;

View file

@ -461,6 +461,15 @@ public:
* Conversion methods. A balance can be converted to an amount, but
* only if contains a single component amount.
*/
operator string() const {
return to_string();
}
string to_string() const {
std::ostringstream buf;
print(buf);
return buf.str();
}
amount_t to_amount() const {
if (is_empty())
throw_(balance_error, _("Cannot convert an empty balance to an amount"));
@ -532,8 +541,8 @@ public:
void print(std::ostream& out,
const int first_width = -1,
const int latter_width = -1,
const bool right_justify = true,
const bool colorize = true) const;
const bool right_justify = false,
const bool colorize = false) const;
/**
* Debugging methods. There are two methods defined to help with

View file

@ -86,7 +86,7 @@ public:
if (! args.empty())
parse_args(args);
}
~draft_t() {
virtual ~draft_t() {
TRACE_DTOR(draft_t);
}

View file

@ -87,7 +87,7 @@ public:
parse(in, flags);
}
~expr_t() throw() {
virtual ~expr_t() {
TRACE_DTOR(expr_t);
}

View file

@ -92,8 +92,7 @@ public:
{
TRACE_CTOR(expr_base_t, "scope_t *");
}
~expr_base_t() throw() {
virtual ~expr_base_t() {
TRACE_DTOR(expr_base_t);
}

View file

@ -132,7 +132,7 @@ public:
if (! _str.empty())
parse_format(_str);
}
~format_t() {
virtual ~format_t() {
TRACE_DTOR(format_t);
}

View file

@ -75,7 +75,7 @@ public:
: expr_t(in, flags), what_to_keep(_what_to_keep) {
TRACE_CTOR(predicate_t, "std::istream&, keep_details_t, parse_flags_t");
}
~predicate_t() throw() {
virtual ~predicate_t() {
TRACE_DTOR(predicate_t);
}

View file

@ -32,6 +32,7 @@
#include <system.hh>
#include "pyinterp.h"
#include "pyutils.h"
#include "account.h"
#include "post.h"
@ -90,6 +91,10 @@ namespace {
return account.xdata();
}
PyObject * py_account_unicode(account_t& account) {
return str_to_py_unicode(account.fullname());
}
} // unnamed namespace
void export_account()
@ -180,7 +185,8 @@ void export_account()
.def_readwrite("note", &account_t::note)
.def_readonly("depth", &account_t::depth)
.def(self_ns::str(self))
.def("__str__", &account_t::fullname)
.def("__unicode__", py_account_unicode)
.def("fullname", &account_t::fullname)
.def("partial_name", &account_t::partial_name)

View file

@ -98,6 +98,10 @@ namespace {
return amount.strip_annotations(keep);
}
PyObject * py_amount_unicode(amount_t& amount) {
return str_to_py_unicode(amount.to_string());
}
} // unnamed namespace
#define EXC_TRANSLATOR(type) \
@ -248,8 +252,9 @@ internal precision."))
.def("__int__", &amount_t::to_long)
.def("fits_in_long", &amount_t::fits_in_long)
.def("to_string", &amount_t::to_string)
.def("__str__", &amount_t::to_string)
.def("to_string", &amount_t::to_string)
.def("__unicode__", py_amount_unicode)
.def("to_fullstring", &amount_t::to_fullstring)
.def("__repr__", &amount_t::to_fullstring)
.def("quantity_string", &amount_t::quantity_string)

View file

@ -105,6 +105,10 @@ namespace {
return balance.strip_annotations(keep);
}
PyObject * py_balance_unicode(balance_t& balance) {
return str_to_py_unicode(balance.to_string());
}
} // unnamed namespace
#define EXC_TRANSLATOR(type) \
@ -152,7 +156,9 @@ void export_balance()
.def(self != long())
.def(! self)
.def(self_ns::str(self))
.def("__str__", &balance_t::to_string)
.def("to_string", &balance_t::to_string)
.def("__unicode__", py_balance_unicode)
.def("negated", &balance_t::negated)
.def("in_place_negate", &balance_t::in_place_negate,

View file

@ -232,6 +232,10 @@ namespace {
return ann.price = price;
}
PyObject * py_commodity_unicode(commodity_t& commodity) {
return str_to_py_unicode(commodity.symbol());
}
} // unnamed namespace
void export_commodity()
@ -331,6 +335,8 @@ void export_commodity()
make_getter(&commodity_t::european_by_default),
make_setter(&commodity_t::european_by_default))
.def("__str__", &commodity_t::symbol)
.def("__unicode__", py_commodity_unicode)
.def("__nonzero__", &commodity_t::operator bool)
.def(self == self)

View file

@ -79,15 +79,8 @@ struct string_to_python
{
static PyObject* convert(const string& str)
{
#if 1
// Return a Unicode object
PyObject * pstr = PyString_FromString(str.c_str());
PyObject * uni = PyUnicode_FromEncodedObject(pstr, "UTF-8", NULL);
return object(handle<>(borrowed(uni))).ptr();
#else
// Return a 7-bit ASCII string
// Return bytes, not characters; see __unicode__ methods for that
return incref(object(static_cast<const std::string&>(str)).ptr());
#endif
}
};

View file

@ -103,6 +103,11 @@ namespace {
value_t py_strip_annotations_1(value_t& value, const keep_details_t& keep) {
return value.strip_annotations(keep);
}
PyObject * py_value_unicode(value_t& value) {
return str_to_py_unicode(value.to_string());
}
} // unnamed namespace
#define EXC_TRANSLATOR(type) \
@ -115,16 +120,16 @@ EXC_TRANSLATOR(value_error)
void export_value()
{
enum_< value_t::type_t >("ValueType")
.value("VOID", value_t::VOID)
.value("BOOLEAN", value_t::BOOLEAN)
.value("DATETIME", value_t::DATETIME)
.value("DATE", value_t::DATE)
.value("INTEGER", value_t::INTEGER)
.value("AMOUNT", value_t::AMOUNT)
.value("BALANCE", value_t::BALANCE)
.value("STRING", value_t::STRING)
.value("SEQUENCE", value_t::SEQUENCE)
.value("SCOPE", value_t::SCOPE)
.value("Void", value_t::VOID)
.value("Boolean", value_t::BOOLEAN)
.value("DateTime", value_t::DATETIME)
.value("Date", value_t::DATE)
.value("Integer", value_t::INTEGER)
.value("Amount", value_t::AMOUNT)
.value("Balance", value_t::BALANCE)
.value("String", value_t::STRING)
.value("Sequence", value_t::SEQUENCE)
.value("Scope", value_t::SCOPE)
;
class_< value_t > ("Value")
@ -309,11 +314,13 @@ void export_value()
.def("to_date", &value_t::to_date)
.def("to_amount", &value_t::to_amount)
.def("to_balance", &value_t::to_balance)
.def("__str__", &value_t::to_string)
.def("__unicode__", py_value_unicode)
.def("to_string", &value_t::to_string)
.def("to_mask", &value_t::to_mask)
.def("to_sequence", &value_t::to_sequence)
.def("__str__", py_dump_relaxed)
.def("__unicode__", py_dump_relaxed)
.def("__repr__", py_dump)
.def("casted", &value_t::casted)

View file

@ -126,6 +126,15 @@ struct map_value_type_converter
}
};
template <typename T>
PyObject * str_to_py_unicode(const T& str)
{
using namespace boost::python;
PyObject * pstr = PyString_FromString(str.c_str());
PyObject * uni = PyUnicode_FromEncodedObject(pstr, "UTF-8", NULL);
return object(handle<>(borrowed(uni))).ptr();
}
namespace boost { namespace python {
// Use expr to create the PyObject corresponding to x

View file

@ -276,7 +276,7 @@ public:
if (! args.empty())
parse_args(args);
}
~query_t() throw() {
virtual ~query_t() {
TRACE_DTOR(query_t);
}

View file

@ -1114,18 +1114,18 @@ void value_t::in_place_cast(type_t cast_type)
break;
}
case BALANCE:
case BALANCE: {
const balance_t& bal(as_balance());
switch (cast_type) {
case AMOUNT: {
const balance_t& temp(as_balance());
if (temp.amounts.size() == 1) {
if (bal.amounts.size() == 1) {
// Because we are changing the current balance value to an amount
// value, and because set_amount takes a reference (and that memory is
// about to be repurposed), we must pass in a copy.
set_amount(amount_t((*temp.amounts.begin()).second));
set_amount(amount_t((*bal.amounts.begin()).second));
return;
}
else if (temp.amounts.size() == 0) {
else if (bal.amounts.size() == 0) {
set_amount(0L);
return;
}
@ -1135,10 +1135,17 @@ void value_t::in_place_cast(type_t cast_type)
}
break;
}
case STRING:
if (bal.is_empty())
set_string("");
else
set_string(as_balance().to_string());
return;
default:
break;
}
break;
}
case STRING:
switch (cast_type) {

View file

@ -4,16 +4,16 @@
>>>2
While parsing file "$sourcepath/src/amount.h", line 67:
Error: No quantity specified for amount
While parsing file "$sourcepath/src/amount.h", line 717:
While parsing file "$sourcepath/src/amount.h", line 720:
Error: Invalid date/time: line amount_t amoun
While parsing file "$sourcepath/src/amount.h", line 723:
While parsing file "$sourcepath/src/amount.h", line 726:
Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 729:
While parsing file "$sourcepath/src/amount.h", line 732:
Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 735:
While parsing file "$sourcepath/src/amount.h", line 738:
Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 741:
While parsing file "$sourcepath/src/amount.h", line 744:
Error: Invalid date/time: line std::ostream&
While parsing file "$sourcepath/src/amount.h", line 748:
While parsing file "$sourcepath/src/amount.h", line 751:
Error: Invalid date/time: line std::istream&
=== 7