diff --git a/include/boost/python/detail/api_placeholder.hpp b/include/boost/python/detail/api_placeholder.hpp index fd571d88..9a4672ab 100644 --- a/include/boost/python/detail/api_placeholder.hpp +++ b/include/boost/python/detail/api_placeholder.hpp @@ -9,16 +9,6 @@ namespace boost { namespace python { if (PyErr_Occurred()) throw_error_already_set(); return result; } - - inline object getattr(object const& a0, const char* a1, object const& a2) - { - handle<> result(allow_null(PyObject_GetAttrString( - a0.ptr(), const_cast(a1)))); - if (!PyErr_Occurred()) return object(result); - PyErr_Clear(); - return a2; - } - }} // namespace boost::python #endif // BOOST_PYTHON_API_PLACE_HOLDER_HPP diff --git a/include/boost/python/detail/module_base.hpp b/include/boost/python/detail/module_base.hpp index 218caccf..144c1d93 100644 --- a/include/boost/python/detail/module_base.hpp +++ b/include/boost/python/detail/module_base.hpp @@ -26,7 +26,6 @@ class BOOST_PYTHON_DECL module_base protected: void setattr_doc(const char* name, python::object const&, char const* doc); - void add_class(type_handle const& class_obj); private: handle<> m_module; diff --git a/include/boost/python/module.hpp b/include/boost/python/module.hpp index af6434ce..7ee7b188 100644 --- a/include/boost/python/module.hpp +++ b/include/boost/python/module.hpp @@ -38,7 +38,7 @@ class module : public detail::module_base template module& add(class_ const& c) { - this->add_class(type_handle(borrowed((PyTypeObject*)c.ptr()))); + // Soon to disappear... return *this; } diff --git a/include/boost/python/object_protocol.hpp b/include/boost/python/object_protocol.hpp index fe21be17..975c9379 100755 --- a/include/boost/python/object_protocol.hpp +++ b/include/boost/python/object_protocol.hpp @@ -19,6 +19,12 @@ object getattr(Target const& target, Key const& key) return getattr(object(target), object(key)); } +template +object getattr(Target const& target, Key const& key, Default const& default_) +{ + return getattr(object(target), object(key), object(default_)); +} + template void setattr(object const& target, Key const& key, Value const& value) diff --git a/include/boost/python/object_protocol_core.hpp b/include/boost/python/object_protocol_core.hpp index 548f9c7a..c5c41c6a 100755 --- a/include/boost/python/object_protocol_core.hpp +++ b/include/boost/python/object_protocol_core.hpp @@ -15,12 +15,14 @@ namespace api class object; BOOST_PYTHON_DECL object getattr(object const& target, object const& key); + BOOST_PYTHON_DECL object getattr(object const& target, object const& key, object const& default_); BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value); BOOST_PYTHON_DECL void delattr(object const& target, object const& key); // These are defined for efficiency, since attributes are commonly // accessed through literal strings. BOOST_PYTHON_DECL object getattr(object const& target, char const* key); + BOOST_PYTHON_DECL object getattr(object const& target, char const* key, object const& default_); BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value); BOOST_PYTHON_DECL void delattr(object const& target, char const* key); diff --git a/src/module.cpp b/src/module.cpp index 549ba782..088773fc 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -42,23 +42,6 @@ void module_base::add(type_handle const& x) this->setattr_doc(x->tp_name, python::object(x), 0); } -void module_base::add_class(type_handle const& class_obj) -{ - this->add(class_obj); - - handle<> module_name( - PyObject_GetAttrString( - m_module.get(), const_cast("__name__")) - ); - - int status = PyObject_SetAttrString( - python::upcast(class_obj.get()) - , const_cast("__module__"), module_name.get()); - - if (status == -1) - throw_error_already_set(); -} - PyMethodDef module_base::initial_methods[] = { { 0, 0, 0, 0 } }; namespace diff --git a/src/object/class.cpp b/src/object/class.cpp index c6420a76..c034b066 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -3,12 +3,14 @@ // 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. +#include #include #include #include #include #include #include +#include #include #include #include @@ -264,9 +266,17 @@ namespace objects PyTuple_SET_ITEM(bases.get(), i - 1, upcast(c.release())); } + object module_name = PyObject_IsInstance(scope().ptr(), upcast(&PyModule_Type)) + ? scope().attr("__name__") + : getattr(scope(), "__module__", object("")) + ; + + if (module_name) + module_name += '.'; + // Build the (name, bases, dict) tuple for creating the new class handle<> args(PyTuple_New(3)); - PyTuple_SET_ITEM(args.get(), 0, incref(python::object(name).ptr())); + PyTuple_SET_ITEM(args.get(), 0, incref((module_name + name).ptr())); PyTuple_SET_ITEM(args.get(), 1, bases.release()); handle<> d(PyDict_New()); PyTuple_SET_ITEM(args.get(), 2, d.release()); @@ -274,7 +284,12 @@ namespace objects // Call the class metatype to create a new class PyObject* c = PyObject_CallObject(upcast(class_metatype().get()), args.get()); assert(PyType_IsSubtype(c->ob_type, &PyType_Type)); - return object(python::detail::new_reference(c)); + object result = object(python::detail::new_reference(c)); + + if (scope().ptr() != Py_None) + scope().attr(name) = result; + + return result; } } diff --git a/src/object_protocol.cpp b/src/object_protocol.cpp index cafb70f3..11979f8f 100755 --- a/src/object_protocol.cpp +++ b/src/object_protocol.cpp @@ -15,6 +15,17 @@ BOOST_PYTHON_DECL object getattr(object const& target, object const& key) return object(detail::new_reference(PyObject_GetAttr(target.ptr(), key.ptr()))); } +BOOST_PYTHON_DECL object getattr(object const& target, object const& key, object const& default_) +{ + PyObject* result = PyObject_GetAttr(target.ptr(), key.ptr()); + if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + return default_; + } + return object(detail::new_reference(result)); +} + BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value) { if (PyObject_SetAttr(target.ptr(), key.ptr(), value.ptr()) == -1) @@ -35,6 +46,17 @@ BOOST_PYTHON_DECL object getattr(object const& target, char const* key) )); } +BOOST_PYTHON_DECL object getattr(object const& target, char const* key, object const& default_) +{ + PyObject* result = PyObject_GetAttrString(target.ptr(), const_cast(key)); + if (result == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + return default_; + } + return object(detail::new_reference(result)); + +} BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value) { if (PyObject_SetAttrString( diff --git a/test/m1.cpp b/test/m1.cpp index 71bc3af1..de76f64a 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -211,9 +211,7 @@ BOOST_PYTHON_MODULE_INIT(m1) lvalue_from_pytype,&SimpleType>(); - module m1("m1"); - - m1 + module("m1") // Insert the metaclass for all extension classes .setattr("xclass", boost::python::objects::class_metatype()) @@ -239,40 +237,30 @@ BOOST_PYTHON_MODULE_INIT(m1) .def("take_b", take_b) .def("take_c", take_c) .def("take_d", take_d) + ; - .add( - class_ >("A") - .def("name", &A::name) - ) - + class_ >("A") + .def("name", &A::name) ; // sequence points don't ensure that "A" is constructed before "B" // or "C" below if we make them part of the same chain - m1 - .add( - class_, shared_ptr >("B") - .def("name", &B::name) - ) + class_, shared_ptr >("B") + .def("name", &B::name) + ; - .add( - class_, shared_ptr >("C") - .def("name", &C::name) - ) + class_, shared_ptr >("C") + .def("name", &C::name) ; - m1 - .add( - class_, bases >("D") - .def("name", &D::name) - ) + class_, bases >("D") + .def("name", &D::name) + ; - .add( - class_("complicated", - args()) - .def_init(args()) - .def("get_n", &complicated::get_n) - ) + class_("complicated", + args()) + .def_init(args()) + .def("get_n", &complicated::get_n) ; } diff --git a/test/test_pointer_adoption.cpp b/test/test_pointer_adoption.cpp index cd039c9a..caefe4cb 100644 --- a/test/test_pointer_adoption.cpp +++ b/test/test_pointer_adoption.cpp @@ -88,29 +88,29 @@ A* as_A(Base* b) BOOST_PYTHON_MODULE_INIT(test_pointer_adoption_ext) { - boost::python::module m("test_pointer_adoption_ext"); - m.def("num_a_instances", num_a_instances) + boost::python::module("test_pointer_adoption_ext") + .def("num_a_instances", num_a_instances) // Specify the manage_new_object return policy to take // ownership of create's result .def("create", create, return_value_policy()) .def("as_A", as_A, return_internal_reference<>()) - .add( - + ; + class_("Base") - ); + ; - m.add(class_ >(no_init) + class_ >(no_init) .def("content", &A::content) .def("get_inner", &A::get_inner, return_internal_reference<>()) - ) + ; - .add(class_(no_init) + class_(no_init) .def("change", &inner::change) - ) + ; - .add(class_("B") + class_("B") .def_init(args(), with_custodian_and_ward_postcall<1,2>()) .def("adopt", &B::adopt @@ -120,7 +120,7 @@ BOOST_PYTHON_MODULE_INIT(test_pointer_adoption_ext) , with_custodian_and_ward<1,2> >() ) - .def("a_content", &B::a_content)) + .def("a_content", &B::a_content) ; }