2
0
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:
Dave Abrahams
2002-07-16 11:45:10 +00:00
parent fa779034b5
commit 2bfeb20550
10 changed files with 165 additions and 28 deletions

View File

@@ -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

View 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

View File

@@ -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)
);
}
}

View File

@@ -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));
}
};
}

View File

@@ -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));
}
};
}

View File

@@ -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 == &registered<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

View File

@@ -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)

View File

@@ -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>

View File

@@ -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)

View File

@@ -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