mirror of
https://github.com/boostorg/python.git
synced 2026-01-21 05:02:17 +00:00
Added type checking when converting some Python types from python as return values.
[SVN r14478]
This commit is contained in:
@@ -24,13 +24,13 @@ BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain(
|
||||
BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
|
||||
PyObject* source, registration const&);
|
||||
|
||||
BOOST_PYTHON_DECL void* rvalue_from_python_stage2(
|
||||
PyObject*, rvalue_from_python_stage1_data&, void* storage);
|
||||
BOOST_PYTHON_DECL void* rvalue_result_from_python(
|
||||
PyObject*, rvalue_from_python_stage1_data&);
|
||||
|
||||
BOOST_PYTHON_DECL void* reference_from_python(PyObject*, registration const&);
|
||||
BOOST_PYTHON_DECL void* pointer_from_python(PyObject*, registration const&);
|
||||
BOOST_PYTHON_DECL void* reference_result_from_python(PyObject*, registration const&);
|
||||
BOOST_PYTHON_DECL void* pointer_result_from_python(PyObject*, registration const&);
|
||||
|
||||
BOOST_PYTHON_DECL void void_from_python(PyObject*);
|
||||
BOOST_PYTHON_DECL void void_result_from_python(PyObject*);
|
||||
|
||||
|
||||
}}} // namespace boost::python::converter
|
||||
|
||||
18
include/boost/python/converter/pytype_result_from_python.hpp
Normal file
18
include/boost/python/converter/pytype_result_from_python.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright David Abrahams 2002. Permission to copy, use,
|
||||
// modify, sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
#ifndef PYTYPE_RESULT_FROM_PYTHON_DWA2002716_HPP
|
||||
# define PYTYPE_RESULT_FROM_PYTHON_DWA2002716_HPP
|
||||
|
||||
# include <boost/python/detail/raw_pyobject.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace converter {
|
||||
|
||||
BOOST_PYTHON_DECL python::detail::new_reference
|
||||
pytype_result_from_python(PyTypeObject* type, PyObject* source);
|
||||
|
||||
}}} // namespace boost::python::converter
|
||||
|
||||
#endif // PYTYPE_RESULT_FROM_PYTHON_DWA2002716_HPP
|
||||
@@ -77,7 +77,7 @@ struct return_from_python<void>
|
||||
|
||||
result_type operator()(PyObject* x) const
|
||||
{
|
||||
converter::void_from_python(x);
|
||||
(void_result_from_python)(x);
|
||||
# ifdef BOOST_NO_VOID_RETURNS
|
||||
return result_type();
|
||||
# endif
|
||||
@@ -101,21 +101,24 @@ namespace detail
|
||||
inline typename return_rvalue_from_python<T>::result_type
|
||||
return_rvalue_from_python<T>::operator()(PyObject* obj)
|
||||
{
|
||||
return *(T*)rvalue_from_python_stage2(obj, m_data.stage1, m_data.storage.bytes);
|
||||
return *(T*)
|
||||
(rvalue_result_from_python)(obj, m_data.stage1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T return_reference_from_python<T>::operator()(PyObject* obj) const
|
||||
{
|
||||
return python::detail::void_ptr_to_reference(
|
||||
reference_from_python(obj, registered<T>::converters)
|
||||
(reference_result_from_python)(obj, registered<T>::converters)
|
||||
, (T(*)())0);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T return_pointer_from_python<T>::operator()(PyObject* obj) const
|
||||
{
|
||||
return T(pointer_from_python(obj, registered_pointee<T>::converters));
|
||||
return T(
|
||||
(pointer_result_from_python)(obj, registered_pointee<T>::converters)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
# include <boost/python/object.hpp>
|
||||
# include <boost/python/converter/pytype_arg_from_python.hpp>
|
||||
# include <boost/python/converter/pytype_result_from_python.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
@@ -153,7 +154,7 @@ namespace converter
|
||||
|
||||
result_type operator()(PyObject* x) const
|
||||
{
|
||||
return list(python::detail::new_reference(x));
|
||||
return list((pytype_result_from_python)(&PyList_Type, x));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
# include <boost/python/object.hpp>
|
||||
# include <boost/python/converter/pytype_arg_from_python.hpp>
|
||||
# include <boost/python/converter/pytype_result_from_python.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
@@ -91,7 +92,7 @@ namespace converter
|
||||
|
||||
result_type operator()(PyObject* x) const
|
||||
{
|
||||
return long_(python::detail::new_reference(x));
|
||||
return long_((pytype_result_from_python)(&PyLong_Type, x));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,11 +8,28 @@
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
#include <boost/python/converter/rvalue_from_python_data.hpp>
|
||||
#include <boost/python/handle.hpp>
|
||||
#include <boost/python/detail/raw_pyobject.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace boost { namespace python { namespace converter {
|
||||
|
||||
// rvalue_from_python_stage1 -- do the first stage of a conversion
|
||||
// from a Python object to a C++ rvalue.
|
||||
//
|
||||
// source - the Python object to be converted
|
||||
// converters - the registry entry for the target type T
|
||||
//
|
||||
// Postcondition: where x is the result, one of:
|
||||
//
|
||||
// 1. x.convertible == 0, indicating failure
|
||||
//
|
||||
// 2. x.construct == 0, x.convertible is the address of an object of
|
||||
// type T. Indicates a successful lvalue conversion
|
||||
//
|
||||
// 3. where y is of type rvalue_from_python_data<T>,
|
||||
// x.construct(source, y) attempts to construct an object of type T
|
||||
// in y. Indicates an rvalue converter was found
|
||||
BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
|
||||
PyObject* source
|
||||
, registration const& converters)
|
||||
@@ -34,20 +51,36 @@ BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
|
||||
return data;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void* rvalue_from_python_stage2(
|
||||
PyObject* src, rvalue_from_python_stage1_data& data, void* storage)
|
||||
// rvalue_result_from_python -- return the address of a C++ object which
|
||||
// can be used as the result of calling a Python function.
|
||||
//
|
||||
// src - the Python object to be converted
|
||||
//
|
||||
// data - a reference to the base part of a
|
||||
// rvalue_from_python_data<T> object, where T is the
|
||||
// target type of the conversion.
|
||||
//
|
||||
// Requires: data.convertible == ®istered<T>::converters
|
||||
//
|
||||
BOOST_PYTHON_DECL void* rvalue_result_from_python(
|
||||
PyObject* src, rvalue_from_python_stage1_data& data)
|
||||
{
|
||||
// Take possession of the source object.
|
||||
handle<> holder(src);
|
||||
|
||||
// Retrieve the registration
|
||||
// Cast in two steps for less-capable compilers
|
||||
void const* converters_ = data.convertible;
|
||||
registration const& converters = *static_cast<registration const*>(converters_);
|
||||
|
||||
// Look for an eligible converter
|
||||
data = rvalue_from_python_stage1(src, converters);
|
||||
|
||||
if (!data.convertible)
|
||||
{
|
||||
handle<> msg(
|
||||
::PyString_FromFormat(
|
||||
"No registered converter was able to produce a C++ lvalue of type %s from this Python object of type %s"
|
||||
"No registered converter was able to produce a C++ rvalue of type %s from this Python object of type %s"
|
||||
, converters.target_type.name()
|
||||
, src->ob_type->tp_name
|
||||
));
|
||||
@@ -130,7 +163,7 @@ BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain(
|
||||
return chain;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void* reference_from_python(
|
||||
BOOST_PYTHON_DECL void* reference_result_from_python(
|
||||
PyObject* source
|
||||
, registration const& converters)
|
||||
{
|
||||
@@ -163,7 +196,7 @@ BOOST_PYTHON_DECL void* reference_from_python(
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void* pointer_from_python(
|
||||
BOOST_PYTHON_DECL void* pointer_result_from_python(
|
||||
PyObject* source
|
||||
, registration const& converters)
|
||||
{
|
||||
@@ -172,7 +205,7 @@ BOOST_PYTHON_DECL void* pointer_from_python(
|
||||
Py_DECREF(source);
|
||||
return 0;
|
||||
}
|
||||
return reference_from_python(source, converters);
|
||||
return reference_result_from_python(source, converters);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void throw_no_class_registered()
|
||||
@@ -183,9 +216,27 @@ BOOST_PYTHON_DECL void throw_no_class_registered()
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void void_from_python(PyObject* o)
|
||||
BOOST_PYTHON_DECL void void_result_from_python(PyObject* o)
|
||||
{
|
||||
Py_DECREF(expect_non_null(o));
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL python::detail::new_reference
|
||||
pytype_result_from_python(PyTypeObject* type, PyObject* source)
|
||||
{
|
||||
if (!PyType_IsSubtype(source->ob_type, type))
|
||||
{
|
||||
handle<> keeper(source);
|
||||
handle<> msg(
|
||||
::PyString_FromFormat(
|
||||
"Expecting a Python %s return type, but got an object of type %s instead"
|
||||
, type
|
||||
, source->ob_type->tp_name
|
||||
));
|
||||
PyErr_SetObject(PyExc_TypeError, msg.get());
|
||||
throw_error_already_set();
|
||||
}
|
||||
return python::detail::new_reference(source);
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::converter
|
||||
|
||||
44
src/list.cpp
44
src/list.cpp
@@ -24,8 +24,15 @@ BOOST_PYTHON_DECL list::list(object_cref sequence)
|
||||
|
||||
BOOST_PYTHON_DECL void list::append(object_cref x)
|
||||
{
|
||||
if (PyList_Append(this->ptr(), x.ptr()) == -1)
|
||||
throw_error_already_set();
|
||||
if (PyList_CheckExact(this->ptr()))
|
||||
{
|
||||
if (PyList_Append(this->ptr(), x.ptr()) == -1)
|
||||
throw_error_already_set();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->attr("append")(x);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL long list::count(object_cref value) const
|
||||
@@ -53,8 +60,15 @@ BOOST_PYTHON_DECL long list::index(object_cref value) const
|
||||
|
||||
BOOST_PYTHON_DECL void list::insert(int index, object_cref item)
|
||||
{
|
||||
if (PyList_Insert(this->ptr(), index, item.ptr()) == -1)
|
||||
throw_error_already_set();
|
||||
if (PyList_CheckExact(this->ptr()))
|
||||
{
|
||||
if (PyList_Insert(this->ptr(), index, item.ptr()) == -1)
|
||||
throw_error_already_set();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->attr("insert")(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void list::insert(object const& index, object_cref x)
|
||||
@@ -87,14 +101,28 @@ BOOST_PYTHON_DECL void list::remove(object_cref value)
|
||||
|
||||
BOOST_PYTHON_DECL void list::reverse()
|
||||
{
|
||||
if (PyList_Reverse(this->ptr()) == -1)
|
||||
throw_error_already_set();
|
||||
if (PyList_CheckExact(this->ptr()))
|
||||
{
|
||||
if (PyList_Reverse(this->ptr()) == -1)
|
||||
throw_error_already_set();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->attr("reverse")();
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void list::sort()
|
||||
{
|
||||
if (PyList_Sort(this->ptr()) == -1)
|
||||
throw_error_already_set();
|
||||
if (PyList_CheckExact(this->ptr()))
|
||||
{
|
||||
if (PyList_Sort(this->ptr()) == -1)
|
||||
throw_error_already_set();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->attr("sort")();
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL void list::sort(object_cref cmpfunc)
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <boost/python/object/inheritance.hpp>
|
||||
#include <boost/python/type_id.hpp>
|
||||
#include <boost/graph/breadth_first_search.hpp>
|
||||
#if defined(BOOST_MSVC) && _MSC_FULL_VER == 13102171
|
||||
# include <boost/graph/reverse_graph.hpp>
|
||||
#endif
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/reverse_graph.hpp>
|
||||
#include <boost/property_map.hpp>
|
||||
|
||||
@@ -38,6 +38,11 @@ object apply_object_list(object f, list x)
|
||||
return f(x);
|
||||
}
|
||||
|
||||
list apply_list_list(object f, list x)
|
||||
{
|
||||
return call<list>(f.ptr(), x);
|
||||
}
|
||||
|
||||
void append_object(list& x, object y)
|
||||
{
|
||||
x.append(y);
|
||||
@@ -126,6 +131,7 @@ BOOST_PYTHON_MODULE_INIT(list_ext)
|
||||
.def("listify", listify)
|
||||
.def("listify_string", listify_string)
|
||||
.def("apply_object_list", apply_object_list)
|
||||
.def("apply_list_list", apply_list_list)
|
||||
|
||||
.def("append_object", append_object)
|
||||
.def("append_list", append_list)
|
||||
|
||||
30
test/list.py
30
test/list.py
@@ -20,9 +20,17 @@ X(22)
|
||||
|
||||
5 is not convertible to a list
|
||||
|
||||
>>> try: apply_object_list(identity, 5)
|
||||
>>> try: result = apply_object_list(identity, 5)
|
||||
... except TypeError: pass
|
||||
... else: print 'expected an exception'
|
||||
... else: print 'expected an exception, got', result, 'instead'
|
||||
|
||||
>>> assert apply_list_list(identity, letters) is letters
|
||||
|
||||
5 is not convertible to a list as a return value
|
||||
|
||||
>>> try: result = apply_list_list(len, letters)
|
||||
... except TypeError: pass
|
||||
... else: print 'expected an exception, got', result, 'instead'
|
||||
|
||||
>>> append_object(letters, '.')
|
||||
>>> letters
|
||||
@@ -38,6 +46,24 @@ X(22)
|
||||
>>> letters
|
||||
['h', 'e', 'l', 'l', 'o', '.', [1, 2]]
|
||||
|
||||
Check that subclass functions are properly called
|
||||
|
||||
>>> class mylist(list):
|
||||
... def append(self, o):
|
||||
... list.append(self, o)
|
||||
... if not hasattr(self, 'nappends'):
|
||||
... self.nappends = 1
|
||||
... else:
|
||||
... self.nappends += 1
|
||||
...
|
||||
>>> l2 = mylist()
|
||||
>>> append_object(l2, 'hello')
|
||||
>>> append_object(l2, 'world')
|
||||
>>> l2
|
||||
['hello', 'world']
|
||||
>>> l2.nappends
|
||||
2
|
||||
|
||||
>>> def printer(*args):
|
||||
... for x in args: print x,
|
||||
... print
|
||||
|
||||
Reference in New Issue
Block a user