@@ -363,14 +363,18 @@ namespace classdesc
363363 std::is_copy_assignable<typename pythonDetail::MemberType<X>::T>,
364364 Not<is_const<typename pythonDetail::MemberType<X>::T>>
365365 >,void >::T
366- addProperty (C& c,const string& d, X x) {c.def_readwrite (d.c_str (),x);}
366+ addProperty (C& c,const string& d, X x) {
367+ c.def_readwrite (d.c_str (),x);
368+ }
367369 template <class C ,class X >
368370 typename enable_if<
369371 Or<
370372 Not<std::is_copy_assignable<typename pythonDetail::MemberType<X>::T>>,
371373 is_const<typename pythonDetail::MemberType<X>::T>
372374 >,void >::T
373- addProperty (C& c,const string& d, X x) {c.def_readonly (d.c_str (),x);}
375+ addProperty (C& c,const string& d, X x) {
376+ c.def_readonly (d.c_str (),x);
377+ }
374378 };
375379
376380 template <class T , bool copiable> struct Class ;
@@ -449,24 +453,34 @@ namespace classdesc
449453 }
450454
451455 template <class T >
452- void addObject (const string& d, T& o) {
456+ typename enable_if<std::is_copy_assignable<T>,void >::T
457+ addObject (const string& d, T& o) {
458+ using namespace boost ::python;
453459 checkScope (d);
454460
455461 if (!scopeStack.empty ())
456462 scopeStack.back ().object .def_readwrite (tail (d).c_str (),o);
463+ else
464+ extract<dict>(scope ().attr (" __dict__" ))()[tail (d).c_str ()]=ptr (&o);
457465 }
458466 template <class T >
459- void addObject (const string& d, const T& o) {
467+ typename enable_if<Not<std::is_copy_assignable<T>>,void >::T
468+ addObject (const string& d, const T& o) {
469+ using namespace boost ::python;
460470 checkScope (d);
461- scopeStack.back ().object .def_readonly (tail (d).c_str (),o);
471+ if (!scopeStack.empty ())
472+ scopeStack.back ().object .def_readonly (tail (d).c_str (),o);
473+ else
474+ extract<dict>(scope ().attr (" __dict__" ))()[tail (d).c_str ()]=ptr (&o);
462475 }
463476
464477 template <class F >
465478 typename enable_if<Not<is_pointer<typename functional::Return<F>::T>>, void >::T
466479 addFunctional (const string& d, F f) {
467480 checkScope (d);
468481 boost::python::def (tail (d).c_str (),f);
469- scopeStack.back ().object .staticmethod (tail (d).c_str ());
482+ if (!scopeStack.empty ())
483+ scopeStack.back ().object .staticmethod (tail (d).c_str ());
470484 }
471485
472486 // ignore pointer returns, as we don't know anything about the object being pointed to.
@@ -736,6 +750,41 @@ namespace classdesc
736750 }
737751 }
738752 }
753+
754+ // / add a python reference to a C++ static object
755+ // / path is a '.' delimited name qualified by namespaces
756+ // / if no '.' present, object is inserted into global namespace
757+
758+ // / Lifetime of \a object should exceed that of any reference to it
759+ // / in Python, so best used for logn lived objects. You can
760+ // / programmatically delete the python reference by call "del
761+ // / objectname" using boost::python::exec
762+
763+ // / NB: this function has to be run after the requested module is
764+ // / created. That means in particular, it cannot be run in the
765+ // / initialiser of static variable, nor within the initialiser of
766+ // / the module in question. Please use python_t::addObject()
767+ // / instead. It can be used to insert an object into the global
768+ // / module, however within a module initialiser.
769+ template <class T >
770+ void addPythonObject (const std::string& path, T& object)
771+ {
772+ using namespace boost ::python;
773+ auto lastDot=path.rfind (' .' );
774+ string module , name;
775+ if (lastDot==std::string::npos)
776+ {
777+ module =" __main__" ;
778+ name=path;
779+ }
780+ else
781+ {
782+ module =path.substr (0 ,lastDot);
783+ name=path.substr (lastDot+1 );
784+ }
785+ dict the_dict=extract<dict>(import (module .c_str ()).attr (" __dict__" ));
786+ the_dict[name]=ptr (&object);
787+ }
739788}
740789
741790namespace classdesc_access
0 commit comments