[C++-sig] Re: Using .add_property with make_getter.
Kirsebom Nikolai
nikolai.kirsebom at siemens.no
Tue Jun 24 14:37:37 CEST 2003
> -----Original Message-----
> From: David Abrahams [mailto:dave at boost-consulting.com]
> Sent: 24. juni 2003 13:23
> To: c++-sig at python.org
> Subject: ÆC++-sigÅ Re: Using .add_property with make_getter.
>
>
> Kirsebom Nikolai <nikolai.kirsebom at siemens.no> writes:
>
> > I have the following c++ class:
> > class PyDLEPRInterface : public DLEPRInterface
> > {
> > public:
> > PyDLEPRInterface();
> > PyDLEPRInterface(const PyDLEPRInterface& objectSrc);
> > };
> >
> > PyDLEPRInterface::PyDLEPRInterface(const PyDLEPRInterface&
> objectSrc)
> > {
> > }
> >
> > PyDLEPRInterface::PyDLEPRInterface()
> > {
> > }
> >
> > The class DLEPRInterface defines some public attributes, example
> > CString m_DocumentCategory;
> > int m_UserID;
> >
> >
> > I have a converter for converting CString <--> python string.
> > See code in thread "Exception second time loaded" 20th of June.
> >
> > The two attributes are exposed with the statements:
> > .def_readonly("UserID", &PyDLEPRInterface::m_UserID)
> > and
> > .add_property("DocumentCategory",
> > make_getter(&PyDLEPRInterface::m_DocumentCategory,
> > return_value_policy<return_by_value>()))
> >
> > When running in Python, the UserID is available
>
> What does "available" mean?
Only that I'm able to read it's value from Python.
>
> > however reading the DocumentCategory attribute produces the
> > following traceback:
> >
> > import DocuLive #<<Module exposing function to get an existing
> > PyDELEPRInterface object
> > import CString #<<Module handling the conversion
> > v = DocuLive.getit() #<<Fetch the exisiting object
> > v.UserID #<<Print the value for UserID attribute
> > 44
> > v.DocumentCategory
> > Traceback (most recent call last):
> > File "<input>", line 1, in ?
> > TypeError: bad argument type for built-in operation
>
> Can you post a complete, minimal test case that we can use to
> reproduce the problem?
>
I'll try to make a test-case. Problem with the current system is that it
includes a lot of propriatory code that I cannot provide.
> > I'm running the python statements in a PyCrust (wxPython/wxWindows)
> > shell application. In my posting 20th of June I asked for help
> > relating to exception when staring the second time. It appears that
> > the starting of the mainloop in the PyCrust application produces the
> > exception if other applications (in Windows) has been activated in
> > between.
>
> I don't know what that means, but I can tell you that if you want to
> initialize the same Boost.Python extension modules a 2nd time, the
> Boost.Python DLL must be unloaded first. I don't know what it takes
> to do that, but I'm guessing we have a problem because it gets
> referenced by each of the BPL extension modules which is loaded, and
> they in turn are being kept alive because no PyFinalize() is being
> called, because we don't support PyFinalize() yet. Dirk Gerrits has
> been working on a solution, but has been waylaid. It's an important
> feature to get implemented, but Boost Consulting has to focus on
> projects which have been funded.
>
>
What code actually initiates the Boost.Python initialization ? My extension
DLL is not unloaded, at least when running in the debugger (VS 7.0) the
Modules windows lists the DLLs (Python22.dll, boost_python_debug.dll and
DLEPRPythonDld.dll (mine)).
I enclose my 'module' file. Maybe the solution is obvious to someone. I'll
be away for some time and I'll look into making a 'workable' test-case when
back. Untill then, thanks for your quick reply and help.
PS: Could the problem (getting access to the property) be related to the
fact that I wrap the actual instance object in a new class PyDLEPRInterface
inheriting from DLEPRInterface, something I had to do because of compiler
error (see my posting on the 20th of June (Exception second time loaded).
PPS: The CPythonDocuLiveDlg dialog is executed with the DoModal().
PPPS: I've not been able to retreive the exception information when the
statement "wxPython.lib.PyCrust.PyShellApp.main()" fails. So I've made a
counter to indicate where the it failed, an 'i' comes out with the value 2.
Nikolai Kirsebom
////////////////////////////////////////////////////////////////////////////
////////////////////////////////
//
//
#include "stdafx.h"
#include "resource.h"
#include <DLEPRInterface.h>
#include <DLdbAPI.h>
#include "PyInterface.h"
//#include "Python.h"
#include <boost/python/dict.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/handle.hpp>
#include <boost/python/to_python_converter.hpp>
#include <boost/python/detail/wrap_python.hpp>
#include <boost/python.hpp>
////////////////////////////////////////////////////////////////////////////
//////////////
//
class PyDLEPRInterface : public DLEPRInterface
{
public:
PyDLEPRInterface();
PyDLEPRInterface(const PyDLEPRInterface& objectSrc);
};
PyDLEPRInterface::PyDLEPRInterface(const PyDLEPRInterface& objectSrc)
{
}
PyDLEPRInterface::PyDLEPRInterface()
{
}
////////////////////////////////////////////////////////////////////////////
/////////////
///// EXPOSED INTERFACE
/////////////////////////////////////////////////////////////////
using namespace boost::python;
static PyDLEPRInterface* curr=NULL;
static bool ThreadRunning = FALSE;
class PythonException
{
std::string m_exception_type;
std::string m_error_message;
public:
PythonException():m_exception_type(""),m_error_message(""){};
void setExceptionType(std::string msg) {m_exception_type = msg;}
void setErrorMessage(std::string msg) {m_error_message = msg;}
std::string getExceptionType() {return m_exception_type;}
std::string getErrorMessage(void) {return m_error_message;}
};
void getExceptionDetail(PythonException& exc)
{
PyObject* exc_type;
PyObject* exc_value;
PyObject* exc_traceback;
PyObject* pystring;
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
if( exc_type==0 && exc_value==0 && exc_traceback==0)
{
exc.setExceptionType("Strange: No Python exception occured");
exc.setErrorMessage("Strange: Nothing to report");
}
else
{
pystring = NULL;
if (exc_type != NULL &&
(pystring = PyObject_Str(exc_type)) != NULL && /* str(object)
*/
(PyString_Check(pystring))
)
exc.setExceptionType(PyString_AsString(pystring));
else
exc.setExceptionType("<unknown exception type>");
Py_XDECREF(pystring);
pystring = NULL;
if (exc_value != NULL &&
(pystring = PyObject_Str(exc_value)) != NULL && /*
str(object) */
(PyString_Check(pystring))
)
exc.setErrorMessage(PyString_AsString(pystring));
else
exc.setErrorMessage("<unknown exception data>");
Py_XDECREF(pystring);
Py_XDECREF(exc_type);
Py_XDECREF(exc_value); /* caller owns all 3 */
Py_XDECREF(exc_traceback); /* already NULL'd out */
}
}
PyDLEPRInterface* getit() {
return curr;
}
BOOST_PYTHON_MODULE(DocuLive)
{
def("getit", getit,
return_value_policy<reference_existing_object>())
;
class_<PyDLEPRInterface>("DLEPRInterface")
.def("GetDatabaseName", &PyDLEPRInterface::GetDatabaseName)
.def("GetDefaultServerName",
&PyDLEPRInterface::GetDefaultServerName)
.def("IsRubber", &PyDLEPRInterface::IsRubber)
.def_readonly("RecordId", &PyDLEPRInterface::m_RecordID)
.def_readonly("Item", &PyDLEPRInterface::m_Item)
.def_readonly("OriginalItem",
&PyDLEPRInterface::m_OriginalItem)
.def_readonly("Row", &PyDLEPRInterface::m_Row)
.def_readonly("Col", &PyDLEPRInterface::m_Col)
.def_readonly("UserID", &PyDLEPRInterface::m_UserID)
.def_readonly("m_CurMenuEntry",
&PyDLEPRInterface::m_CurMenuEntry)
.add_property("DocumentCategory",
make_getter(&PyDLEPRInterface::m_DocumentCategory,
return_value_policy<return_by_value>()))
.add_property("LookupCategory",
make_getter(&PyDLEPRInterface::m_LookupCategory,
return_value_policy<return_by_value>()))
.add_property("RecordCategory",
make_getter(&PyDLEPRInterface::m_RecordCategory,
return_value_policy<return_by_value>()))
.add_property("IconPurpose",
make_getter(&PyDLEPRInterface::m_IconPurpose,
return_value_policy<return_by_value>()))
;
class_<MenuEntry>("MenuEntry")
.add_property("ParamString1",
make_getter(&MenuEntry::ParamString1,
return_value_policy<return_by_value>()))
;
}
namespace MFCString { namespace {
struct CString_to_python_str
{
static PyObject* convert(CString const& s)
{
CString ss = s;
std::string x = ss.GetBuffer(1000);
return boost::python::incref(boost::python::object(x).ptr());
}
};
struct CString_from_python_str
{
CString_from_python_str()
{
boost::python::converter::registry::push_back(
&convertible,
&construct,
boost::python::type_id<CString>());
}
static void* convertible(PyObject* obj_ptr)
{
if (!PyString_Check(obj_ptr)) return 0;
return obj_ptr;
}
static void construct(
PyObject* obj_ptr,
boost::python::converter::rvalue_from_python_stage1_data* data)
{
const char* value = PyString_AsString(obj_ptr);
if (value == 0) boost::python::throw_error_already_set();
void* storage =
((boost::python::converter::rvalue_from_python_storage<CString>*)data)->stor
age.bytes;
new (storage) CString(value);
data->convertible = storage;
}
};
void init_module()
{
using namespace boost::python;
boost::python::to_python_converter<
CString,
CString_to_python_str>();
CString_from_python_str();
}
}} // namespace MFCString::<anonymous>
BOOST_PYTHON_MODULE(CString)
{
MFCString::init_module();
}
BOOST_PYTHON_MODULE(MFC)
{
class_<CRect>("CRect")
.def_readwrite("bottom", &CRect::bottom)
.def_readwrite("top", &CRect::top)
.def_readwrite("right", &CRect::right)
.def_readwrite("left", &CRect::left)
.def("Height", &CRect::Height)
.def("Width", &CRect::Width)
;
class_<CPoint>("CPoint")
.def_readwrite("x", &CPoint::x)
.def_readwrite("y", &CPoint::y)
;
}
////////////////////////////////////////////////////////////////////////////
////////
/// PYTHON EXECUTOR CLASS
//////////////////////////////////////////////////////////
class PyExecutor
{
public:
PyExecutor();
~PyExecutor();
CString RunStmt(DLEPRInterface * dl);
PyObject * MainNamespace;
};
PyExecutor::PyExecutor()
{
// Register the module with the interpreter
if (PyImport_AppendInittab("DocuLive", initDocuLive) == -1)
throw std::runtime_error("Failed to add DocuLive to the
interpreter's builtin modules");
if (PyImport_AppendInittab("CString", initCString) == -1)
throw std::runtime_error("Failed to add CString to the interpreter's
builtin modules");
if (PyImport_AppendInittab("MFC", initMFC) == -1)
throw std::runtime_error("Failed to add MFC to the interpreter's
builtin modules");
Py_Initialize();
boost::python::handle<> main_module(borrowed(
PyImport_AddModule("__main__")));
boost::python::handle<> main_namespace(borrowed(
PyModule_GetDict(main_module.get()) ));
MainNamespace = main_namespace.get();
}
PyExecutor::~PyExecutor()
{
Py_Finalize();
}
CString PyExecutor::RunStmt(DLEPRInterface * dlepr)
{
PyObject *p = NULL;
curr = (PyDLEPRInterface *)dlepr;
PythonException p_exc; // Create empty exception object on
stack
try
{
boost::python::handle<> result(PyRun_String(
"try:\n"
" i = 1\n"
" import wxPython.lib.PyCrust.PyShellApp\n"
" i += 1\n"
" wxPython.lib.PyCrust.PyShellApp.main()\n"
" i += 1\n"
" del wxPython\n"
" i += 1\n"
" valx = 'ok'\n"
" i += 1\n"
"except:\n"
" valx = 'error'\n"
" raise str(i)\n"
"#except:\n"
"#valx = 'error'\n",
Py_file_input, MainNamespace, MainNamespace));
result.reset();
p = PyRun_String("valx", Py_eval_input, MainNamespace,
MainNamespace);
result.release();
}
catch(error_already_set) // What should we catch here??
{
getExceptionDetail(p_exc);
std::string s1 = p_exc.getExceptionType();
std::string s2 = p_exc.getErrorMessage();
CString s;
//s.Format("Exception: %s %s", s1, s2);
AfxMessageBox(s);
throw(p_exc);
}
if (p != NULL) {
/**/
char *s;
int i = PyArg_Parse(p, "s", &s);
return _T(s);
/**/
} else {
return _T("NULL");
}
}
////////////////////////////////////////////////////////////////////////////
///
//// THREAD SUPPORT FUNCTIONS
/////////////////////////////////////////////////
struct IfStruct {
IfStruct(DLEPRInterface * i, CPythonDocuLiveDlg *dlg) { m_If
= i; m_Dlg = dlg; };
DLEPRInterface * m_If;
CPythonDocuLiveDlg * m_Dlg;
};
UINT ThreadFunc(LPVOID pParam)
{
static PyExecutor *x = NULL;
if (x == NULL) {
x = new PyExecutor();
}
IfStruct * p = (IfStruct *) pParam;
CString v = x->RunStmt(p->m_If);
//Send close message to window
p->m_Dlg->SendMessage(WM_CLOSE);
return 0;
}
////////////////////////////////////////////////////////////////////////////
///
// CPythonDocuLiveDlg dialog
IMPLEMENT_DYNAMIC(CPythonDocuLiveDlg, CDialog)
CPythonDocuLiveDlg::CPythonDocuLiveDlg(DLEPRInterface* pInterface, CWnd*
pParent /*=NULL*/)
: CDialog(CPythonDocuLiveDlg::IDD, pParent),m_Interface(*pInterface)
{
}
CPythonDocuLiveDlg::~CPythonDocuLiveDlg()
{
}
void CPythonDocuLiveDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BOOL CPythonDocuLiveDlg::OnInitDialog()
{
this->MoveWindow(0,0,100,100); //Should be outside the screen
(-100,-100,100,100)
IfStruct * s = new IfStruct(&m_Interface, this);
m_Thread = AfxBeginThread(ThreadFunc, s);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CPythonDocuLiveDlg::OnOK()
{
CDialog::OnOK();
}
void CPythonDocuLiveDlg::OnCancel()
{
CDialog::OnCancel();
}
BEGIN_MESSAGE_MAP(CPythonDocuLiveDlg, CDialog)
END_MESSAGE_MAP()
// CPythonDocuLiveDlg message handlers
More information about the Cplusplus-sig
mailing list