Check for const reference parameters in all from_python functions in py.h, including implementations. Better python and C++ exception handling/error reporting. long long support use Python generic numeric coercion in from_python() for C++ numeric types Rename PyPtr to Reference. Report Cygwin linker memory issues __init__ stuff Make abstract classes non-instantiable (?) Call default __init__ functions automatically where applicable (?) Support for Python LONG types in Objects.h Throw TypeError after asserting when objects from objects.cpp detect a type mismatch. Figure out how to package everything as a shared library. Unicode string support Add read-only wrapper for __dict__ attribute Objects.h support for generic objects, Sequence objects, etc. empty() member functions for objects.hpp Testing Python 2.0 object revival in __del__ More thorough tests of objects.h/cpp classes Better reference-count checking Optimizations Remove one level of indirection on type objects (no vtbl?). Specializations of Caller<> for commmon combinations of argument types (?) Replace uses of XXXable classes Don't allocate instance __dict__ unless used. Documentation: differences between Python classes and ExtensionClasses additional capabilities of ExtensionClasses slice adjustment Why special attributes other than __doc__ and __name__ are immutable. An example of the problems with the built-in Python classes. >>> class A: ... def __getattr__(self, name): ... return 'A.__getattr__' ... >>> class B(A): pass ... >>> class C(B): pass ... >>> C().x 'A.__getattr__' >>> B.__bases__ = () >>> C().x 'A.__getattr__' Smart pointers #ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE namespace py { #endif template struct VtkConverters { typedef py::PyExtensionClassConverters Converters; friend vtk_ptr& from_python(PyObject* p, py::Type&>) { return Converters::ptr_from_python(p, py::Type >()); } friend vtk_ptr& from_python(PyObject* p, py::Type >) { return Converters::ptr_from_python(p, py::Type >()); } friend const vtk_ptr& from_python(PyObject* p, py::Type&>) { return Converters::ptr_from_python(p, py::Type >()); } friend PyObject* to_python(vtk_ptr x) { return Converters::ptr_to_python(x); } }; #ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE } #endif template struct VtkWrapper : py::ClassWrapper, py::VtkConverters { typedef py::ClassWrapper Base; VtkWrapper(Module& module, const char* name) : Base(module, name) {} }; exception handling Advanced Topics: Advanced Type Conversion adding conversions for fundamental types generic conversions for template types (with partial spec). Interacting with built-in Python objects and types from C++ dealing with non-const reference/pointer parameters extending multiple-argument support using gen_all.py Fancy wrapping tricks templates Yes. If you look at the examples in extclass_demo.cpp you'll see that I have exposed several template instantiations (e.g. std::pair) in Python. Keep in mind, however, that you can only expose a template instantiation, not a template. In other words, MyTemplate can be exposed. MyTemplate itself cannot. Well, that's not strictly true. Wow, this is more complicated to explain than I thought. You can't make an ExtensionClass, since after all MyTemplate is not a type. You can only expose a concrete type to Python. What you *can* do (if your compiler supports partial ordering of function templates - MSVC is broken and does not) is to write appropriate from_python() and to_python() functions for converting a whole class of template instantiations to/from Python. That won't let you create an instance of MyTemplate from Python, but it will let you pass/return arbitrary MyTemplate instances to/from your wrapped C++ functions. template MyTemplate from_python(PyObject* x, py::Type >) { // code to convert x into a MyTemplate... that part is up to you } template PyObject* from_python(const MyTemplate&) { // code to convert MyTemplate into a PyObject*... that part is up to you } For example, you could use this to convert Python lists to/from std::vector automatically. Pointer return values Case 1: > I am now also able to wrap the problematic TextRecordIterator for Python. > However, one of its function compiles with this warning: > > d:\py_cpp/caller.h(33) : warning C4800: 'const class Record *const ' > : forcing value to bool 'true' or 'false' (performance warning) > d:\py_cpp/functions.h(54) : see reference to function template > instantiation 'struct _object *__cdecl py::Caller::call(const class Record > *const (__thiscall TextRecordIterator::*)(void),struct _object *,struct > _object *)' being compiled > > If you look at the offending code, you'll see that we really do need to > get back that pointer: > > const Record* const TextRecordIterator::Next() { > if (fStatus != RecordIterator::SUCCESS) { > return 0; > } else { > return &fData; > } > } > > The point of the TextRecordIterator is to hand over one reord after > another. A bool wouldn't do us much good here :-) > > Do you have any suggestions for fixing this? In general, py_cpp doesn't automatically convert pointer return values to_python because pointers have too many potential meanings. Is it an iterator? A pointer to a single element? An array? Is ownership being passed to Python or is the pointer really just a reference? If the latter, what happens when some C++ code deletes the referent. The only exception to this rule is const char*, since it has a generally accepted interpretation (could be trouble with some generic code, though!) If you have wrapped the Record class, you could add this to namespace py: PyObject* to_python(const Record* p) { return to_python(*p); } Of course, this will cause the Record class to be copied. If you can't live with that (Record would have to be /really/ heavyweight to make this worthwhile), you can follow one of these dangerous approaches: 1. Use the technique I described with dangerous_array in http://www.egroups.com/message/boost/6196. You do not have to expose Record explicitly in this case. Instead the class you expose will be more of a Record_proxy 2. Wrap Record in the usual way, then add the following to namespace py: PyObject* to_python(const Record* p) { return ExtensionClass::ptr_to_python(const_cast(p)); } This will cause the Record* to be treated as though it were an owning smart pointer, even though it's not. Be sure you don't use the reference for anything from Python once the pointer becomes invalid, though. Don't worry too much about the const-correctness issue: Const-correctness is completely lost to Python anyway! 3. As above, but instead wrap const Record rather than plain Record. Then you can avoid the const_cast, but you obviously can't def() any non-const member functions of Record. Case 2: > I have yet another question. This is more a general wrapper question. > Let me say that there is a function that returns a float* which most > probably is an array. Similarly if I have a function that takes a > float* as an argument, what is the best way of wrapping this? I think you have correctly perceived that it doesn't make sense for me to automatically convert all pointers, since the ownership semantics are so blurry. > 1) If the array is small it makes sense to convert it to either a > tuple or list. What is the easiest way to do this?? I am looking > for a way that makes one write the least code. :) How can you tell the length of the array from a single pointer? Once you've answered that question, you can expose a wrapper function which returns an instance of the py::Tuple or py::List class from objects.h. If you are using a List, for example, you could write something like this: py::List wrap_f() { T* start = f(); py::List x; for (T* p = start; p != start + length_constant; ++p) x.push_back(py::to_python(*p)); return x; } > 2) If the array is large it may not make sense to use a list/tuple > esp. if the values are used for computationally intense programs. In this case you can do one of several somewhat dangerous things. Why dangerous? Because python can not control the lifetime of the data, so the data in the array may be destroyed or become invalid before the last reference to it disappears. The basic approach is to make a small C++ class which contains the pointer, and expose that: // UNTESTED template struct dangerous_array { dangerous_array(T* start, T* end) : m_start(start), m_end(end) {} // exposed as "__len__" std::size_t length() { return m_end - m_start; } // exposed as "__getitem__" T get_item(std::size_t n) { check_range(n); return start[n]; } // exposed as "__setitem__" if the array is mutable void set_item(std::size_t n, const T& x) { check_range(n); start[n] = x; } private: void check_range(std::size_t n) { if (n >= m_end - m_start) { PyErr_SetString(PyExc_IndexError, "array index out of range"); throw py::ErrorAlreadySet; } } T* m_start; T* m_end; }; A reasonably safe approach would be to make a wrapper function for each function that returns a T*, and expose that instead. If you're too lazy and you really like to live on the edge, though, you can write to_python(T*) in terms of to_python(const dangerous_array&), and you'll automatically convert all T* return values to a wrapped dangerous_array. > 3) For an arbitrary class "class_A", say, can py_cpp handle > references to class_A &instance, or class_A *instance?? i.e. will it > wrap function calls to such objects? This question is obviously > related to the earlier questions. Yes, iff class_A has been exposed to python with a ClassWrapper. See http://people.ne.mediaone.net/abrahams/downloads/under-the-hood.html for a few details. raw C++ arrays You could expose a function like this one to get the desired effect: #include void set_len(UnitCell& x, py::Tuple tuple) { double len[3]; for (std::size_t i =0; i < 3; ++i) len[i] = py::from_python(tuple[i].get(), py::Type()); x.set_len(len); } Types that are already wrapped by other libraries It's not documented yet, but you should be able to use a raw PyObject* or a py::Ptr as one parameter to your C++ function. Then you can manipulate it as any other generic Python object. Alternatively, If the NTL gives you a C/C++ interface, you can also write your own converter function: some_ntl_type& from_python(PyObject* p, py::Type) { // an Example implementation. Basically, you need // to extract the NTL type from the PyObject*. if (p->ob_type != NTL_long_type) { PyErr_SetString(PyExc_TypeErr, "NTL long required"); throw py::ArgumentError(); } return *static_cast(p); } then the C++ functions you're wrapping can take a some_NTL_type& parameter directly. "Thin converting wrappers" for constructors hijack some of the functionality described in the section on Overridable Virtual Functions (even though you don't have any virtual functions). I suggest this workaround: struct UnitCellWrapper : UnitCell { UnitCellWrapper(PyObject* self, py::Tuple x, py::Tuple y) : UnitCell(from_python(x[1], py::Type()), from_python(x[2], py::Type()), from_python(x[3], py::Type()), from_python(y[1], py::Type()), from_python(y[2], py::Type()), from_python(y[3], py::Type())) {} } py::ClassWrapper unit_cell_class; unit_cell_class.def(py::Constructor()); ... returning references to wrapped objects the importance of declaration order of ClassWrappers/ExtensionInstances out parameters and non-const pointers Calling back into Python: // caveat: UNTESTED! #include #include #include #include int main() { try { py::Ptr module(PyImport_ImportModule("weapons")); const int strength = 10; const char* manufacturer = "Vordon Empire"; py::Ptr a_blaster(py::Callback::call_method( module.get(), "Blaster", strength, manufacturer)); py::Callback::call_method(a_blaster.get(), "Fire"); int old_strength = py::Callback::call_method(a_blaster.get(), "get_strength"); py::Callback::call_method(a_blaster.get(), "set_strength", 5); } catch(...) { } } Miscellaneous About the vc6 project and the debug build About doctest.py Boost remarks: > > One of us is completely nuts ;->. How can I move the test > > (is_prefix(enablers[i].name + 2, name + 2)) outside the loop if it depends > > on the loop index, i? > > > name += 2; > for() > { > if (is_prefix(enablers[i].name + 2, name)) > } I see now. I guess I should stop pussyfooting and either go for optimization or clarity here, eh? ------ > Re: Dict > Why abbreviate this? Code is read 5 or 6 times for every time its > written. The few extra characters don't affect compile time or program > speed. It's part of my personal goal of write what you mean, name them what > they are. I completely agree. Abbrevs rub me the wrong way, 2 ;-> ------- Later: keyword and varargs? Put explicit Type<> arguments at the beginnings of overloads, to make them look more like template instance specifications. Known bugs can't handle 'const void' return values Who returns 'const void'? I did it once, by mistake ;)