Skip to content

Commit f920dc8

Browse files
committed
Added std::wstring conversion support
Added std::out_of_range => Python IndexError exception conversion, thanks to Raoul Gough [SVN r20027]
1 parent 8b97caa commit f920dc8

File tree

6 files changed

+94
-27
lines changed

6 files changed

+94
-27
lines changed

doc/news.html

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,33 @@ <h2 align="center">News/Change Log</h2>
3131
<dl class="page-index">
3232
<dt>11 Sept 2003</dt>
3333

34-
<dd>Changed the response to multiple to-python converters being
35-
registered for the same type from a hard error into warning;
36-
Boost.Python now reports the offending type in the message.
34+
<dd>
35+
<ul>
36+
<li>Changed the response to multiple to-python converters being
37+
registered for the same type from a hard error into warning;
38+
Boost.Python now reports the offending type in the message.</li>
39+
40+
<li>Added builtin <code>std::wstring</code> conversions</li>
41+
42+
<li>Added <code>std::out_of_range</code> =&gt; Python
43+
<code>IndexError</code> exception conversion, thanks to <a href=
44+
"mailto:RaoulGough-at-yahoo.co.uk">Raoul Gough</a></li>
45+
</ul>
46+
</dd>
3747

3848
<dt>9 Sept 2003</dt>
3949

40-
<dd>Added new <code><a
41-
href="v2/str.html#str-spec">str</a></code></dd> constructors
42-
which take a range of characters, allowing strings containing
43-
nul (<code>'\0'</code>) characters.
50+
<dd>Added new <code><a href="v2/str.html#str-spec">str</a></code></dd>
51+
52+
<dt>constructors which take a range of characters, allowing strings
53+
containing nul (<code>'\0'</code>) characters.</dt>
4454

4555
<dt>8 Sept 2003</dt>
4656

47-
<dd>Added the ability to create methods from function
48-
objects (with an <code>operator()</code>); see the <a
49-
href="v2/make_function.html#make_function-spec">make_function</a>
50-
docs for more info.</dd>
57+
<dd>Added the ability to create methods from function objects (with an
58+
<code>operator()</code>); see the <a href=
59+
"v2/make_function.html#make_function-spec">make_function</a> docs for
60+
more info.</dd>
5161

5262
<dt>10 August 2003</dt>
5363

@@ -170,7 +180,8 @@ <h2 align="center">News/Change Log</h2>
170180

171181
<p>Revised
172182
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
173-
11 September 2003 <!--webbot bot="Timestamp" endspan i-checksum="39359" -->
183+
11 September 2003
184+
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
174185
</p>
175186

176187
<p><i>&copy; Copyright <a href="../../../people/dave_abrahams.htm">Dave

include/boost/python/converter/builtin_converters.hpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,16 @@ namespace detail
8282

8383
// Specialize converters for signed and unsigned T to Python Int
8484
# define BOOST_PYTHON_TO_INT(T) \
85-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, PyInt_FromLong(x)) \
85+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, ::PyInt_FromLong(x)) \
8686
BOOST_PYTHON_TO_PYTHON_BY_VALUE( \
8787
unsigned T \
8888
, static_cast<unsigned long>(x) > static_cast<unsigned long>( \
8989
std::numeric_limits<long>::max()) \
90-
? PyLong_FromUnsignedLong(x) \
91-
: PyInt_FromLong(x))
90+
? ::PyLong_FromUnsignedLong(x) \
91+
: ::PyInt_FromLong(x))
9292

9393
// Bool is not signed.
94-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, PyInt_FromLong(x))
94+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, ::PyInt_FromLong(x))
9595

9696
// note: handles signed char and unsigned char, but not char (see below)
9797
BOOST_PYTHON_TO_INT(char)
@@ -103,23 +103,29 @@ BOOST_PYTHON_TO_INT(long)
103103
// using Python's macro instead of Boost's - we don't seem to get the
104104
// config right all the time.
105105
# ifdef HAVE_LONG_LONG
106-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed BOOST_PYTHON_LONG_LONG, PyLong_FromLongLong(x))
107-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned BOOST_PYTHON_LONG_LONG, PyLong_FromUnsignedLongLong(x))
106+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed BOOST_PYTHON_LONG_LONG, ::PyLong_FromLongLong(x))
107+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned BOOST_PYTHON_LONG_LONG, ::PyLong_FromUnsignedLongLong(x))
108108
# endif
109109

110110
# undef BOOST_TO_PYTHON_INT
111111

112112
BOOST_PYTHON_TO_PYTHON_BY_VALUE(char, converter::do_return_to_python(x))
113113
BOOST_PYTHON_TO_PYTHON_BY_VALUE(char const*, converter::do_return_to_python(x))
114-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, PyString_FromStringAndSize(x.c_str(),x.size()))
115-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, PyFloat_FromDouble(x))
116-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, PyFloat_FromDouble(x))
117-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, PyFloat_FromDouble(x))
114+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, ::PyString_FromStringAndSize(x.data(),x.size()))
115+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::wstring, ::PyUnicode_FromWideChar(x.data(),x.size()))
116+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, ::PyFloat_FromDouble(x))
117+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, ::PyFloat_FromDouble(x))
118+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, ::PyFloat_FromDouble(x))
118119
BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(PyObject*, converter::do_return_to_python(x))
119-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<float>, PyComplex_FromDoubles(x.real(), x.imag()))
120-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<double>, PyComplex_FromDoubles(x.real(), x.imag()))
121-
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<long double>, PyComplex_FromDoubles(x.real(), x.imag()))
122-
120+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<float>, ::PyComplex_FromDoubles(x.real(), x.imag()))
121+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<double>, ::PyComplex_FromDoubles(x.real(), x.imag()))
122+
BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<long double>, ::PyComplex_FromDoubles(x.real(), x.imag()))
123+
124+
# undef BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE
125+
# undef BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE
126+
# undef BOOST_PYTHON_TO_PYTHON_BY_VALUE
127+
# undef BOOST_PYTHON_TO_INT
128+
123129
namespace converter
124130
{
125131

src/converter/builtin_converters.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,42 @@ namespace
272272
}
273273
};
274274

275+
// encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc
276+
// "slot" which encodes a Python string using the default encoding
277+
extern "C" PyObject* encode_string_unaryfunc(PyObject* x)
278+
{
279+
return PyUnicode_FromEncodedObject( x, 0, 0 );
280+
}
281+
unaryfunc py_encode_string = encode_string_unaryfunc;
282+
283+
// A SlotPolicy for extracting C++ strings from Python objects.
284+
struct wstring_rvalue_from_python
285+
{
286+
// If the underlying object is "string-able" this will succeed
287+
static unaryfunc* get_slot(PyObject* obj)
288+
{
289+
return PyUnicode_Check(obj)
290+
? &py_object_identity
291+
: PyString_Check(obj)
292+
? &py_encode_string
293+
: 0;
294+
};
295+
296+
// Remember that this will be used to construct the result object
297+
static std::wstring extract(PyObject* intermediate)
298+
{
299+
std::wstring result(::PyObject_Length(intermediate), L' ');
300+
int err = PyUnicode_AsWideChar(
301+
(PyUnicodeObject *)intermediate
302+
, result.size() ? &result[0] : 0
303+
, result.size());
304+
305+
if (err == -1)
306+
throw_error_already_set();
307+
return result;
308+
}
309+
};
310+
275311
struct complex_rvalue_from_python
276312
{
277313
static unaryfunc* get_slot(PyObject* obj)
@@ -366,7 +402,8 @@ void initialize_builtin_converters()
366402
// Add an lvalue converter for char which gets us char const*
367403
registry::insert(convert_to_cstring,type_id<char>());
368404

369-
// Register by-value converters to std::string
405+
// Register by-value converters to std::string, std::wstring
406+
slot_rvalue_from_python<std::wstring, wstring_rvalue_from_python>();
370407
slot_rvalue_from_python<std::string, string_rvalue_from_python>();
371408
}
372409

src/errors.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ BOOST_PYTHON_DECL bool handle_exception_impl(function0<void> f)
3838
{
3939
PyErr_SetString(PyExc_OverflowError, x.what());
4040
}
41+
catch(const std::out_of_range& x)
42+
{
43+
PyErr_SetString(PyExc_IndexError, x.what());
44+
}
4145
catch(const std::exception& x)
4246
{
4347
PyErr_SetString(PyExc_RuntimeError, x.what());

test/test_builtin_converters.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ BOOST_PYTHON_MODULE(builtin_converters)
8383
def("rewrap_value_complex_float", by_value<std::complex<float> >::rewrap);
8484
def("rewrap_value_complex_double", by_value<std::complex<double> >::rewrap);
8585
def("rewrap_value_complex_long_double", by_value<std::complex<long double> >::rewrap);
86+
def("rewrap_value_wstring", by_value<std::wstring>::rewrap);
87+
def("rewrap_value_string", by_value<std::wstring>::rewrap);
8688
def("rewrap_value_string", by_value<std::string>::rewrap);
8789
def("rewrap_value_cstring", by_value<char const*>::rewrap);
8890
def("rewrap_value_handle", by_value<handle<> >::rewrap);

test/test_builtin_converters.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@
7575
'hello, world'
7676
>>> rewrap_value_string('yo, wassup?')
7777
'yo, wassup?'
78+
>>> rewrap_value_wstring(u'yo, wassup?')
79+
u'yo, wassup?'
80+
81+
test that overloading on unicode works:
82+
83+
>>> rewrap_value_string(u'yo, wassup?')
84+
u'yo, wassup?'
7885
7986
wrap strings with embedded nulls:
8087

0 commit comments

Comments
 (0)