diff --git a/doc/news.html b/doc/news.html index 19b00ecb..571788ae 100644 --- a/doc/news.html +++ b/doc/news.html @@ -31,23 +31,33 @@
11 Sept 2003
-
Changed the response to multiple to-python converters being - registered for the same type from a hard error into warning; - Boost.Python now reports the offending type in the message. +
+ +
9 Sept 2003
-
Added new str
constructors - which take a range of characters, allowing strings containing - nul ('\0') characters. +
Added new str
+ +
constructors which take a range of characters, allowing strings + containing nul ('\0') characters.
8 Sept 2003
-
Added the ability to create methods from function - objects (with an operator()); see the make_function - docs for more info.
+
Added the ability to create methods from function objects (with an + operator()); see the make_function docs for + more info.
10 August 2003
@@ -170,7 +180,8 @@ BOOST_PYTHON_MODULE(test)

Revised - 11 September 2003 + 11 September 2003 +

© Copyright Dave diff --git a/include/boost/python/converter/builtin_converters.hpp b/include/boost/python/converter/builtin_converters.hpp index e78eee9a..9d780282 100644 --- a/include/boost/python/converter/builtin_converters.hpp +++ b/include/boost/python/converter/builtin_converters.hpp @@ -82,16 +82,16 @@ namespace detail // Specialize converters for signed and unsigned T to Python Int # define BOOST_PYTHON_TO_INT(T) \ - BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, PyInt_FromLong(x)) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, ::PyInt_FromLong(x)) \ BOOST_PYTHON_TO_PYTHON_BY_VALUE( \ unsigned T \ , static_cast(x) > static_cast( \ std::numeric_limits::max()) \ - ? PyLong_FromUnsignedLong(x) \ - : PyInt_FromLong(x)) + ? ::PyLong_FromUnsignedLong(x) \ + : ::PyInt_FromLong(x)) // Bool is not signed. -BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, PyInt_FromLong(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, ::PyInt_FromLong(x)) // note: handles signed char and unsigned char, but not char (see below) BOOST_PYTHON_TO_INT(char) @@ -103,23 +103,29 @@ BOOST_PYTHON_TO_INT(long) // using Python's macro instead of Boost's - we don't seem to get the // config right all the time. # ifdef HAVE_LONG_LONG -BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed BOOST_PYTHON_LONG_LONG, PyLong_FromLongLong(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned BOOST_PYTHON_LONG_LONG, PyLong_FromUnsignedLongLong(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed BOOST_PYTHON_LONG_LONG, ::PyLong_FromLongLong(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned BOOST_PYTHON_LONG_LONG, ::PyLong_FromUnsignedLongLong(x)) # endif # undef BOOST_TO_PYTHON_INT BOOST_PYTHON_TO_PYTHON_BY_VALUE(char, converter::do_return_to_python(x)) BOOST_PYTHON_TO_PYTHON_BY_VALUE(char const*, converter::do_return_to_python(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, PyString_FromStringAndSize(x.c_str(),x.size())) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, PyFloat_FromDouble(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, PyFloat_FromDouble(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, PyFloat_FromDouble(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, ::PyString_FromStringAndSize(x.data(),x.size())) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::wstring, ::PyUnicode_FromWideChar(x.data(),x.size())) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, ::PyFloat_FromDouble(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, ::PyFloat_FromDouble(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, ::PyFloat_FromDouble(x)) BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(PyObject*, converter::do_return_to_python(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, PyComplex_FromDoubles(x.real(), x.imag())) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, PyComplex_FromDoubles(x.real(), x.imag())) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, PyComplex_FromDoubles(x.real(), x.imag())) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag())) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag())) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag())) +# undef BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE +# undef BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE +# undef BOOST_PYTHON_TO_PYTHON_BY_VALUE +# undef BOOST_PYTHON_TO_INT + namespace converter { diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index bd49c832..40413192 100644 --- a/src/converter/builtin_converters.cpp +++ b/src/converter/builtin_converters.cpp @@ -272,6 +272,42 @@ namespace } }; + // encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc + // "slot" which encodes a Python string using the default encoding + extern "C" PyObject* encode_string_unaryfunc(PyObject* x) + { + return PyUnicode_FromEncodedObject( x, 0, 0 ); + } + unaryfunc py_encode_string = encode_string_unaryfunc; + + // A SlotPolicy for extracting C++ strings from Python objects. + struct wstring_rvalue_from_python + { + // If the underlying object is "string-able" this will succeed + static unaryfunc* get_slot(PyObject* obj) + { + return PyUnicode_Check(obj) + ? &py_object_identity + : PyString_Check(obj) + ? &py_encode_string + : 0; + }; + + // Remember that this will be used to construct the result object + static std::wstring extract(PyObject* intermediate) + { + std::wstring result(::PyObject_Length(intermediate), L' '); + int err = PyUnicode_AsWideChar( + (PyUnicodeObject *)intermediate + , result.size() ? &result[0] : 0 + , result.size()); + + if (err == -1) + throw_error_already_set(); + return result; + } + }; + struct complex_rvalue_from_python { static unaryfunc* get_slot(PyObject* obj) @@ -366,7 +402,8 @@ void initialize_builtin_converters() // Add an lvalue converter for char which gets us char const* registry::insert(convert_to_cstring,type_id()); - // Register by-value converters to std::string + // Register by-value converters to std::string, std::wstring + slot_rvalue_from_python(); slot_rvalue_from_python(); } diff --git a/src/errors.cpp b/src/errors.cpp index 6a23fc9a..a2ab071e 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -38,6 +38,10 @@ BOOST_PYTHON_DECL bool handle_exception_impl(function0 f) { PyErr_SetString(PyExc_OverflowError, x.what()); } + catch(const std::out_of_range& x) + { + PyErr_SetString(PyExc_IndexError, x.what()); + } catch(const std::exception& x) { PyErr_SetString(PyExc_RuntimeError, x.what()); diff --git a/test/test_builtin_converters.cpp b/test/test_builtin_converters.cpp index 6301a6d0..853ae942 100644 --- a/test/test_builtin_converters.cpp +++ b/test/test_builtin_converters.cpp @@ -83,6 +83,8 @@ BOOST_PYTHON_MODULE(builtin_converters) def("rewrap_value_complex_float", by_value >::rewrap); def("rewrap_value_complex_double", by_value >::rewrap); def("rewrap_value_complex_long_double", by_value >::rewrap); + def("rewrap_value_wstring", by_value::rewrap); + def("rewrap_value_string", by_value::rewrap); def("rewrap_value_string", by_value::rewrap); def("rewrap_value_cstring", by_value::rewrap); def("rewrap_value_handle", by_value >::rewrap); diff --git a/test/test_builtin_converters.py b/test/test_builtin_converters.py index 1304ea32..345f2669 100644 --- a/test/test_builtin_converters.py +++ b/test/test_builtin_converters.py @@ -75,6 +75,13 @@ r""" 'hello, world' >>> rewrap_value_string('yo, wassup?') 'yo, wassup?' +>>> rewrap_value_wstring(u'yo, wassup?') +u'yo, wassup?' + + test that overloading on unicode works: + +>>> rewrap_value_string(u'yo, wassup?') +u'yo, wassup?' wrap strings with embedded nulls: