From 2a20884e78fa776c3b6624e153ce188f1fb12458 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 4 Mar 2011 17:32:41 +0000 Subject: [PATCH] libs/python/src/object/class.cpp: metaclass fixes by James Emerton: james at emdata dot net [SVN r69551] --- class.cpp | 28 ++++++++++++++++++++++++++++ src/object/class.cpp | 9 +++++---- test/Jamfile.v2 | 1 + test/class.cpp | 28 ++++++++++++++++++++++++++++ test/class.py | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 class.cpp create mode 100644 test/class.cpp create mode 100755 test/class.py diff --git a/class.cpp b/class.cpp new file mode 100644 index 00000000..078bebdf --- /dev/null +++ b/class.cpp @@ -0,0 +1,28 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include +#include + +using namespace boost::python; + +struct X +{ + int x; + X(int n) : x(n) { } +}; + +int x_function(X& x) +{ return x.x; +} + + +BOOST_PYTHON_MODULE(class_ext) +{ + class_("X", init()); + def("x_function", x_function); +} + +#include "module_tail.cpp" diff --git a/src/object/class.cpp b/src/object/class.cpp index 4d607075..3f818d82 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -303,7 +303,7 @@ static PyTypeObject class_metatype_object = { // object. void instance_holder::install(PyObject* self) throw() { - assert(Py_TYPE(Py_TYPE(self)) == &class_metatype_object); + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self)), &class_metatype_object)); m_next = ((objects::instance<>*)self)->objects; ((objects::instance<>*)self)->objects = this; } @@ -482,7 +482,8 @@ namespace objects BOOST_PYTHON_DECL void* find_instance_impl(PyObject* inst, type_info type, bool null_shared_ptr_only) { - if (Py_TYPE(Py_TYPE(inst)) != &class_metatype_object) + if (!Py_TYPE(Py_TYPE(inst)) || + !PyType_IsSubtype(Py_TYPE(Py_TYPE(inst)), &class_metatype_object)) return 0; instance<>* self = reinterpret_cast*>(inst); @@ -727,7 +728,7 @@ namespace objects void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size) { - assert(Py_TYPE(Py_TYPE(self_)) == &class_metatype_object); + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); objects::instance<>* self = (objects::instance<>*)self_; int total_size_needed = holder_offset + holder_size; @@ -752,7 +753,7 @@ void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std: void instance_holder::deallocate(PyObject* self_, void* storage) throw() { - assert(Py_TYPE(Py_TYPE(self_)) == &class_metatype_object); + assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object)); objects::instance<>* self = (objects::instance<>*)self_; if (storage != (char*)self + Py_SIZE(self)) { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 34f63b3c..876fde12 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -117,6 +117,7 @@ bpl-test crossmod_exception [ bpl-test defaults ] [ bpl-test object ] +[ bpl-test class ] [ bpl-test list ] [ bpl-test long ] [ bpl-test dict ] diff --git a/test/class.cpp b/test/class.cpp new file mode 100644 index 00000000..078bebdf --- /dev/null +++ b/test/class.cpp @@ -0,0 +1,28 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include +#include + +using namespace boost::python; + +struct X +{ + int x; + X(int n) : x(n) { } +}; + +int x_function(X& x) +{ return x.x; +} + + +BOOST_PYTHON_MODULE(class_ext) +{ + class_("X", init()); + def("x_function", x_function); +} + +#include "module_tail.cpp" diff --git a/test/class.py b/test/class.py new file mode 100755 index 00000000..d68ff437 --- /dev/null +++ b/test/class.py @@ -0,0 +1,40 @@ +# Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +''' +>>> from class_ext import * + +Ensure sanity: + + >>> x = X(42) + >>> x_function(x) + 42 + +Demonstrate extraction in the presence of metaclass changes: + + >>> class MetaX(X.__class__): + ... def __new__(cls, *args): + ... return super(MetaX, cls).__new__(cls, *args) + >>> class XPlusMetatype(X): + ... __metaclass__ = MetaX + >>> x = XPlusMetatype(42) + >>> x_function(x) + 42 + + +''' + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status)