|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r62254 - in sandbox/python_extensions: . boost/python boost/python/const_aware libs/python/src libs/python/test
From: talljimbo_at_[hidden]
Date: 2010-05-26 21:53:05
Author: jbosch
Date: 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
New Revision: 62254
URL: http://svn.boost.org/trac/boost/changeset/62254
Log:
python_extensions - removed const_aware::registry, replaced with "__const_proxy__" special attribute.
Removed:
sandbox/python_extensions/boost/python/const_aware/registry.hpp
sandbox/python_extensions/libs/python/src/registry.cpp
Text files modified:
sandbox/python_extensions/TODO | 2
sandbox/python_extensions/boost/python/const_aware.hpp | 6 -
sandbox/python_extensions/boost/python/const_aware/const_shared_ptr_to_python.hpp | 3
sandbox/python_extensions/boost/python/const_aware/exposer.hpp | 41 ++++++++++--
sandbox/python_extensions/boost/python/const_aware/proxy_class.hpp | 24 ++-----
sandbox/python_extensions/boost/python/const_aware/proxy_method.hpp | 4 +
sandbox/python_extensions/libs/python/src/proxy_class.cpp | 126 ++++++++++++++++-----------------------
sandbox/python_extensions/libs/python/src/proxy_method.cpp | 12 +++
sandbox/python_extensions/libs/python/test/const_aware.cpp | 11 +-
sandbox/python_extensions/libs/python/test/const_aware.py | 20 +++++
10 files changed, 133 insertions(+), 116 deletions(-)
Modified: sandbox/python_extensions/TODO
==============================================================================
--- sandbox/python_extensions/TODO (original)
+++ sandbox/python_extensions/TODO 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -1,6 +1,4 @@
const_aware:
- - check pickle support
- - investigate standardized special names for proxy classes (remove registry?)
- smarter shared_ptr converter registration (take held_type into account)
- test subclasses and back-reference wrappers
- devise better workarounds to deal with lack of visitor support
Modified: sandbox/python_extensions/boost/python/const_aware.hpp
==============================================================================
--- sandbox/python_extensions/boost/python/const_aware.hpp (original)
+++ sandbox/python_extensions/boost/python/const_aware.hpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -11,11 +11,9 @@
template <typename W, typename X1, typename X2, typename X3>
inline const_aware::exposer<W,X1,X2,X3> make_const_aware(
- class_<W,X1,X2,X3> & class_ref,
- char const * proxy_name,
- char const * proxy_doc = 0
+ class_<W,X1,X2,X3> const & class_ref
) {
- return const_aware::exposer<W,X1,X2,X3>(class_ref, proxy_name, proxy_doc);
+ return const_aware::exposer<W,X1,X2,X3>(class_ref);
}
}} // namespace boost::python
Modified: sandbox/python_extensions/boost/python/const_aware/const_shared_ptr_to_python.hpp
==============================================================================
--- sandbox/python_extensions/boost/python/const_aware/const_shared_ptr_to_python.hpp (original)
+++ sandbox/python_extensions/boost/python/const_aware/const_shared_ptr_to_python.hpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -8,7 +8,6 @@
#include <boost/python.hpp>
#include <boost/python/const_aware/proxy_class.hpp>
-#include <boost/python/const_aware/registry.hpp>
namespace boost { namespace python { namespace const_aware {
@@ -27,7 +26,7 @@
static PyTypeObject const * get_pytype() {
Converter converter;
- return const_aware::registry::query(converter.get_pytype());
+ return converter.get_pytype();
}
const_shared_ptr_to_python() {
Modified: sandbox/python_extensions/boost/python/const_aware/exposer.hpp
==============================================================================
--- sandbox/python_extensions/boost/python/const_aware/exposer.hpp (original)
+++ sandbox/python_extensions/boost/python/const_aware/exposer.hpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -41,19 +41,37 @@
typedef exposer<W,X1,X2,X3> self;
typedef typename objects::class_metadata<W,X1,X2,X3> metadata;
typedef typename metadata::wrapped wrapped;
- class_t & m_class;
+ class_t m_class;
proxy_class m_proxy;
public: // constructors
- exposer(class_t & class_ref, char const * proxy_name, char const * proxy_doc=0) :
- m_class(class_ref), m_proxy(proxy_name, m_class, proxy_doc) {}
+ exposer(class_t const & class_ref) : m_class(class_ref), m_proxy(m_class) {}
+
+ // Construct with the class name, with or without docstring, and default __init__() function
+ exposer(char const* name, char const* doc = 0) : m_class(name, doc), m_proxy(m_class) {}
+
+ // Construct with class name, no docstring, and an uncallable __init__ function
+ exposer(char const* name, no_init_t n) : m_class(name, n), m_proxy(m_class) {}
+
+ // Construct with class name, docstring, and an uncallable __init__ function
+ exposer(char const* name, char const* doc, no_init_t n) : m_class(name, doc, n), m_proxy(m_class) {}
+
+ // Construct with class name and init<> function
+ template <class DerivedT>
+ exposer(char const* name, init_base<DerivedT> const& i) : m_class(name, i), m_proxy(m_class) {}
+
+ // Construct with class name, docstring and init<> function
+ template <class DerivedT>
+ exposer(char const* name, char const* doc, init_base<DerivedT> const& i)
+ : m_class(name, doc, i), m_proxy(m_class) {}
public: // miscellaneous
+ class_t & main_class() { return m_class; }
proxy_class & const_proxy() { return m_proxy; }
- self& enable_shared_ptr() {
+ self & enable_shared_ptr() {
register_ptr_to_python< boost::shared_ptr<wrapped> >();
const_aware::const_shared_ptr_to_python<wrapped>();
converter::shared_ptr_from_python<wrapped const>();
@@ -61,6 +79,16 @@
return *this;
}
+ self & enable_pickling() {
+ m_class.enable_pickling();
+ return *this;
+ }
+
+ self & copy_method_to_proxy(char const * name) {
+ m_proxy.use_method(name, m_class.attr(name));
+ return *this;
+ }
+
public: // member functions
// Wrap a member function or a non-member function which can take
@@ -153,11 +181,6 @@
m_proxy.use_property(name, m_class.attr(name));
return *this;
}
-
- self & enable_pickling() {
- m_class.enable_pickling();
- return *this;
- }
self & staticmethod(char const* name) {
m_class.staticmethod(name);
Modified: sandbox/python_extensions/boost/python/const_aware/proxy_class.hpp
==============================================================================
--- sandbox/python_extensions/boost/python/const_aware/proxy_class.hpp (original)
+++ sandbox/python_extensions/boost/python/const_aware/proxy_class.hpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -17,19 +17,11 @@
// constructor
proxy_class_base(
- char const* name, // The name of the class
-
std::size_t num_types, // A list of class_ids. The first is the type
- type_info const * const types, // this is wrapping. The rest are the types of
+ type_info const * const types // this is wrapping. The rest are the types of
// any bases.
-
- char const * doc = 0 // Docstring, if any.
);
-
- // Implementation detail. Hiding this in the private section would
- // require use of template friend declarations.
- void enable_pickling_(bool getstate_manages_dict);
protected:
@@ -64,13 +56,8 @@
public:
template <typename W, typename X1, typename X2, typename X3>
- proxy_class(char const * name, class_<W,X1,X2,X3> & target, char const* doc=0)
- : proxy_class_base(
- name,
- target_metadata<W,X1,X2,X3>::size,
- target_metadata<W,X1,X2,X3>().ids,
- doc
- )
+ proxy_class(class_<W,X1,X2,X3> & target)
+ : proxy_class_base(target_metadata<W,X1,X2,X3>::size, target_metadata<W,X1,X2,X3>().ids)
{
rvalue_from_proxy<typename target_metadata<W,X1,X2,X3>::wrapped>();
}
@@ -92,6 +79,11 @@
return *this;
}
+ proxy_class & add_property(char const * name, object const & fget, char const * doc=0) {
+ proxy_class_base::setattr(name, make_new_proxy_property(fget));
+ return *this;
+ }
+
};
}}} // namespace boost::python::const_aware
Modified: sandbox/python_extensions/boost/python/const_aware/proxy_method.hpp
==============================================================================
--- sandbox/python_extensions/boost/python/const_aware/proxy_method.hpp (original)
+++ sandbox/python_extensions/boost/python/const_aware/proxy_method.hpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -17,6 +17,10 @@
// a proxy method and removing fset.
object make_proxy_property(object const & target);
+// Construct a new property object by making a proxy method from the given
+// getter.
+object make_new_proxy_property(object const & fget, char const * doc=0);
+
}}} // namespace boost::python::const_aware
#endif // !BOOST_PYTHON_CONST_AWARE_PROXY_METHOD_HPP
Deleted: sandbox/python_extensions/boost/python/const_aware/registry.hpp
==============================================================================
--- sandbox/python_extensions/boost/python/const_aware/registry.hpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
+++ (empty file)
@@ -1,19 +0,0 @@
-// Copyright 2010 Jim Bosch.
-// 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)
-
-#ifndef BOOST_PYTHON_CONST_AWARE_REGISTRY_HPP
-#define BOOST_PYTHON_CONST_AWARE_REGISTRY_HPP
-
-#include <boost/python.hpp>
-
-namespace boost { namespace python { namespace const_aware { namespace registry {
-
-BOOST_PYTHON_DECL PyTypeObject * query(PyTypeObject const * non_const);
-
-BOOST_PYTHON_DECL void insert(PyTypeObject * non_const, PyTypeObject * const_);
-
-}}}} // namespace boost::python::const_aware::registry
-
-#endif // !BOOST_PYTHON_CONST_AWARE_REGISTRY_HPP
Modified: sandbox/python_extensions/libs/python/src/proxy_class.cpp
==============================================================================
--- sandbox/python_extensions/libs/python/src/proxy_class.cpp (original)
+++ sandbox/python_extensions/libs/python/src/proxy_class.cpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -74,6 +74,20 @@
return 0;
}
+ static PyObject * proxy_instance_reduce_ex(proxy_instance * self, PyObject * args, PyObject * kwds) {
+ PyObject * method = PyObject_GetAttrString(self->target, "__reduce_ex__");
+ if (method == 0) return 0;
+ return PyObject_Call(method, args, kwds);
+ }
+
+ static PyObject * proxy_instance_repr(proxy_instance * self) {
+ return PyObject_Repr(self->target);
+ }
+
+ static PyObject * proxy_instance_str(proxy_instance * self) {
+ return PyObject_Str(self->target);
+ }
+
} // extern "C"
// Mostly copied from class_metatype_object from object/class.cpp in the main Boost.Python library.
@@ -129,6 +143,11 @@
#endif
};
+static PyMethodDef proxy_instance_methods[] = {
+ {const_cast<char*>("__reduce_ex__"), (PyCFunction)&proxy_instance_reduce_ex, METH_KEYWORDS, 0},
+ {0, 0, 0, 0}
+};
+
static PyGetSetDef proxy_instance_getsets[] = {
{const_cast<char*>("__dict__"), proxy_instance_get_dict, proxy_instance_set_dict, NULL, 0},
{0, 0, 0, 0, 0}
@@ -150,13 +169,13 @@
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
- 0, /* tp_repr */
+ (reprfunc)proxy_instance_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
- 0, /* tp_str */
+ (reprfunc)proxy_instance_str, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
@@ -169,7 +188,7 @@
offsetof(proxy_instance,weakrefs), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ proxy_instance_methods, /* tp_methods */
proxy_instance_members, /* tp_members */
proxy_instance_getsets, /* tp_getset */
0, //&PyBaseObject_Type, /* tp_base */
@@ -222,53 +241,22 @@
);
}
-// Find a registered extension class object corresponding to id. Return a
-// null handle if no such class is registered.
-inline type_handle query_target_class(type_info id) {
- converter::registration const* p = converter::registry::query(id);
- return type_handle(
- python::borrowed(
- python::allow_null(p ? p->m_class_object : 0))
- );
-}
-
// Find a registered extension corresponding to id. If not found,
// throw an appropriate exception.
type_handle get_target_class(type_info id) {
- type_handle result(query_target_class(id));
-
- if (result.get() == 0)
- {
- object report("extension class wrapper for proxy target class ");
- report = report + id.name() + " has not been created yet";
- PyErr_SetObject(PyExc_RuntimeError, report.ptr());
- throw_error_already_set();
- }
+ converter::registration const* reg = converter::registry::query(id);
+ type_handle result(python::borrowed(python::allow_null(reg ? reg->m_class_object : 0)));
+ if (result.get() == 0) {
+ object report("extension class wrapper for proxy target class or base class ");
+ report = report + id.name() + " has not been created yet";
+ PyErr_SetObject(PyExc_RuntimeError, report.ptr());
+ throw_error_already_set();
+ }
return result;
}
-// Find a registered proxy class object corresponding to id. Return a
-// null handle if no such class is registered.
-inline type_handle query_proxy_class(type_info id) {
- converter::registration const* p = converter::registry::query(id);
- return type_handle(
- python::borrowed(
- python::allow_null(p ? const_aware::registry::query(p->m_class_object) : 0))
- );
-}
-
-// Find a registered proxy class corresponding to id. If not found,
-// throw an appropriate exception.
-type_handle get_proxy_class(type_info id) {
- type_handle result(query_proxy_class(id));
-
- if (result.get() == 0)
- {
- object report("proxy class wrapper for base class ");
- report = report + id.name() + " has not been created yet";
- PyErr_SetObject(PyExc_RuntimeError, report.ptr());
- throw_error_already_set();
- }
+type_handle get_proxy_class(type_handle const & target) {
+ type_handle result(PyObject_GetAttrString(upcast<PyObject>(target.get()), "__const_proxy__"));
return result;
}
@@ -283,7 +271,7 @@
// rest corresponding to its declared bases.
//
inline object
-new_proxy_class(char const* name, std::size_t num_types, type_info const* const types, char const* doc) {
+new_proxy_class(std::size_t num_types, type_info const* const types) {
assert(num_types >= 1);
// Build a tuple of the base Python type objects. If no bases
@@ -294,46 +282,38 @@
for (ssize_t i = 1; i <= num_bases; ++i) {
type_handle c = (i >= static_cast<ssize_t>(num_types))
- ? proxy_class_type() : get_proxy_class(types[i]);
+ ? proxy_class_type() : get_proxy_class(get_target_class(types[i]));
// PyTuple_SET_ITEM steals this reference
PyTuple_SET_ITEM(bases.get(), static_cast<ssize_t>(i - 1), upcast<PyObject>(c.release()));
}
// Call the class metatype to create a new class
+
+ object target(get_target_class(types[0]));
+
dict d;
-
+ d["__proxy_target__"] = target;
+ d["__doc__"] = target.attr("__doc__");
+
+ object name = "%s.__const_proxy__" % make_tuple(target.attr("__name__"));
+
object m = module_prefix();
if (m) d["__module__"] = m;
-
- if (doc != 0)
- d["__doc__"] = doc;
-
- type_handle target = get_target_class(types[0]);
- d["__proxy_target__"] = object(target);
object result = object(proxy_class_metatype())(name, bases, d);
assert(PyType_IsSubtype(Py_TYPE(result.ptr()), &PyType_Type));
-
- if (scope().ptr() != Py_None)
- scope().attr(name) = result;
-
+
+ target.attr("__const_proxy__") = result;
+
return result;
}
} // <unnamed>
proxy_class_base::proxy_class_base(
- char const* name, std::size_t num_types, type_info const* const types, char const* doc)
- : object(new_proxy_class(name, num_types, types, doc))
-{
- // Insert the new class object in the const_registry
- // Class object is leaked, for now
- object target = this->attr("__proxy_target__");
- const_aware::registry::insert(
- (PyTypeObject*)target.ptr(),
- (PyTypeObject*)incref(this->ptr())
- );
-}
+ std::size_t num_types, type_info const* const types)
+ : object(new_proxy_class(num_types, types))
+{}
void proxy_class_base::setattr(char const* name, object const& x) {
if (PyObject_SetAttrString(this->ptr(), const_cast<char*>(name), x.ptr()) < 0)
@@ -343,13 +323,9 @@
PyObject * construct_proxy_class(PyObject * target_arg) {
handle<> target(target_arg);
PyTypeObject * target_type = Py_TYPE(target.get());
- PyTypeObject * proxy_type = const_aware::registry::query(target_type);
- if (proxy_type == 0) {
- object report("no const proxy class registered for objects of type ");
- report = report + str(object(type_handle(borrowed(target_type))));
- PyErr_SetObject(PyExc_RuntimeError, report.ptr());
- throw_error_already_set();
- }
+ PyTypeObject * proxy_type =
+ (PyTypeObject*)PyObject_GetAttrString((PyObject*)target_type, "__const_proxy__");
+ if (proxy_type == 0) return 0;
PyObject * raw_proxy = proxy_type->tp_alloc(proxy_type, 0);
if (raw_proxy != 0) {
proxy_instance * proxy = (proxy_instance*)raw_proxy;
Modified: sandbox/python_extensions/libs/python/src/proxy_method.cpp
==============================================================================
--- sandbox/python_extensions/libs/python/src/proxy_method.cpp (original)
+++ sandbox/python_extensions/libs/python/src/proxy_method.cpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -191,7 +191,17 @@
object result(
(python::detail::new_reference)
PyObject_CallFunction((PyObject*)&PyProperty_Type,
- const_cast<char*>("Osss"), new_fget.ptr(), 0, 0, doc.ptr())
+ const_cast<char*>("OssO"), new_fget.ptr(), 0, 0, doc.ptr())
+ );
+ return result;
+}
+
+object make_new_proxy_property(object const & fget, char const * doc) {
+ object new_fget = make_proxy_method(fget);
+ object result(
+ (python::detail::new_reference)
+ PyObject_CallFunction((PyObject*)&PyProperty_Type,
+ const_cast<char*>("Osss"), new_fget.ptr(), 0, 0, doc)
);
return result;
}
Deleted: sandbox/python_extensions/libs/python/src/registry.cpp
==============================================================================
--- sandbox/python_extensions/libs/python/src/registry.cpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
+++ (empty file)
@@ -1,35 +0,0 @@
-// Copyright 2010 Jim Bosch
-// 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 <boost/python.hpp>
-#include <boost/python/const_aware/registry.hpp>
-#include <boost/python/const_aware/proxy_class.hpp>
-#include <boost/python/const_aware/as_const.hpp>
-
-#include <map>
-
-namespace boost { namespace python { namespace const_aware { namespace registry {
-
-namespace {
-
-typedef std::map<PyTypeObject*,PyTypeObject*> registry_t;
-registry_t & entries() {
- static registry_t result;
- return result;
-}
-
-}
-
-PyTypeObject * query(PyTypeObject const * non_const) {
- registry_t::const_iterator iter = entries().find(const_cast<PyTypeObject*>(non_const));
- if (iter != entries().end()) return iter->second;
- return 0;
-}
-
-void insert(PyTypeObject * non_const, PyTypeObject * const_) {
- entries().insert(registry_t::value_type(non_const, const_));
-}
-
-}}}} // namespace boost::python::const_aware::registry
Modified: sandbox/python_extensions/libs/python/test/const_aware.cpp
==============================================================================
--- sandbox/python_extensions/libs/python/test/const_aware.cpp (original)
+++ sandbox/python_extensions/libs/python/test/const_aware.cpp 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -8,6 +8,8 @@
public:
Example() : value(0) {}
+ Example(int v) : value(v) {}
+
std::size_t get_address() const { return std::size_t(this); }
bool non_const_method() { return true; }
@@ -42,17 +44,16 @@
static void export_module() {
- bp::class_<Example> pyExample("Example");
- pyExample.def(bp::init<Example const &>());
-
- bp::make_const_aware(pyExample, "FrozenExample")
+ bp::const_aware::exposer<Example>("Example", bp::init<Example const &>())
.add_property("address", &Example::get_address)
.def("non_const_method", &Example::non_const_method)
.def("const_method", &Example::const_method)
.add_property("value_prop", &Example::get_value, &Example::set_value)
.def_readonly("value_ro", &Example::value)
.def_readwrite("value_rw", &Example::value)
- .enable_shared_ptr();
+ .enable_shared_ptr()
+ .enable_pickling()
+ .main_class().def(bp::init<int>((bp::arg("value")=0)))
;
bp::class_<Owner>("Owner")
Modified: sandbox/python_extensions/libs/python/test/const_aware.py
==============================================================================
--- sandbox/python_extensions/libs/python/test/const_aware.py (original)
+++ sandbox/python_extensions/libs/python/test/const_aware.py 2010-05-26 21:53:03 EDT (Wed, 26 May 2010)
@@ -1,5 +1,8 @@
import const_aware
import unittest
+import pickle
+
+const_aware.Example.__reduce__ = lambda self: (const_aware.Example, (self.value_prop,))
class TestConstAware(unittest.TestCase):
@@ -16,6 +19,7 @@
self.assert_(self.owner.accept_by_const_reference(x))
self.assert_(self.owner.accept_by_shared_ptr(x))
self.assert_(self.owner.accept_by_const_shared_ptr(x))
+ x.value_prop = 0
self.assertEqual(x.value_prop, 0)
self.assertEqual(x.value_ro, 0)
self.assertEqual(x.value_rw, 0)
@@ -32,7 +36,7 @@
self.assertRaises(AttributeError, set_value_ro, 1)
def checkConst(self, x):
- self.assertEqual(type(x), const_aware.FrozenExample)
+ self.assertEqual(type(x), const_aware.Example.__const_proxy__)
self.assert_(x.const_method())
self.assertFalse(hasattr(x,"non_const_method"))
self.assert_(self.owner.accept_by_value(x))
@@ -77,7 +81,7 @@
def testConstruction(self):
original = self.owner.by_value()
- proxy = const_aware.FrozenExample(original)
+ proxy = const_aware.Example.__const_proxy__(original)
self.assertEqual(original.address, original.address)
self.checkConst(proxy)
original_copy = const_aware.Example(original)
@@ -87,5 +91,17 @@
self.checkNonConst(original_copy)
self.checkNonConst(proxy_copy)
+ def testPickle(self):
+ original = self.owner.by_value()
+ original.value_prop = 3
+ original_pickled = pickle.dumps(original)
+ original_loaded = pickle.loads(original_pickled)
+ self.assertEqual(original_loaded.value_prop, original.value_prop)
+ proxy = const_aware.Example.__const_proxy__(original)
+ proxy_pickled = pickle.dumps(proxy)
+ proxy_loaded = pickle.loads(proxy_pickled)
+ self.assertEqual(proxy_loaded.value_prop, proxy.value_prop)
+ self.checkNonConst(proxy_loaded)
+
if __name__=="__main__":
unittest.main()
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk