Javacpp-presets: How can I call PyErr_Fetch correctly?

Created on 23 Oct 2020  路  11Comments  路  Source: bytedeco/javacpp-presets

I don't manage to use PyErr_Fetch. I am a bit confused.

I would like to do this (C++ code here):

PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
//pvalue contains error message
//ptraceback contains stack snapshot and many other information
//(see python traceback structure)

//Get error message
char *pStrErrorMessage = PyString_AsString(pvalue);

The Java method signature for PyErr_Fetch is either:

PyErr_Fetch(PointerPointer p0, PointerPointer p0, PointerPointer p0);

or

PyErr_Fetch(PyObject p0, PyObject p0, PyObject p0);

What can I do to achieve what I want (which is to get the exception string)?

Also, there is no PyString_AsString function in the wrapper! I know PyUnicode_FromString, but how to get a String from a PyObject?

Thanks for your help.

question

Most helpful comment

@saudet and @supergrecko many thanks for your help.

Before I saw your message, I did:

            PyObject arg0 = new PyObject();
            PyObject arg1 = new PyObject();
            PyObject arg2 = new PyObject();
            PointerPointer pp0 = new PointerPointer(arg0);
            PointerPointer pp1 = new PointerPointer(arg1);
            PointerPointer pp2 = new PointerPointer(arg2);
            PyErr_Fetch(pp0, pp1, pp2);
            PyObject pys = new PyObject(pp1.get());

This works, but probably is suboptimal. I just hope this is "safe" that won't crash...

All 11 comments

erm my dear i think you posted at the wrong place here is javacpp area.JAVA .lol if there is python port.You should ask the python porting dev.

What are you talking about? Isn't this the right place for questions?

I would assume this is with regards to the cpython preset?

Are you having troubles with the entire thing or just pulling the error out of the (what would in the C++ API, be *pvalue) value?

Yes, this is about the cpython preset.

I'm actually relatively familiar with the preset. But PointerPointer-stuff is really given me a bad time.

How can I pass the correct thing to PyErr_Fetch?
The above code, in C++, works fine.
How can I deal with PointerPointer's? Are they needed? How shall I create a PointerPointer? There are so many constructors, this is really difficult.

Here is where am I so far:

        PyObject arg0 = new PyObject();
        PyObject arg1 = new PyObject();
        PyObject arg2 = new PyObject();
        PointerPointer pp0 = new PointerPointer(arg0);
        PointerPointer pp1 = new PointerPointer(arg1);
        PointerPointer pp2 = new PointerPointer(arg2);
        PyErr_Fetch(pp0, pp1, pp2);
        PyObject pys = new PyObject(pp1.get());

I can't find PyString_AsString. Is it missing in the preset?

This would be very surprising it is, but I can't find it anywhere!

Just saw your message pop up, that's essentially how you'd do it, assuming arg0-2 are meaningful values, not just newly creating values.

You also mentioned the PyErr_Fetch(PyObject p0, PyObject p0, PyObject p0); overload which you should be able to use instead of the PointerPointer one.

As for PyString_AsString, I could only find documentation on this function from the Python 2.x C API. It seems it may have been removed in 3.x?


Old message, ignore:

A PointerPointer is essentially a pointer to some mapped type. It has a generic type which is the type it points to.

As C/C++ arrays decay into pointers arrays are also represented with this type which is probably why you're getting confused over all the constructors. You're essentially creating an array of size 1. Say you want something which points to a single PyObject, you could do this

// Single item. If you intend on creating an array, change 1 with size of array
PointerPointer ptr = new PointerPointer(1);

// you can then insert the element
ptr.put(0, pyObject);

For convenience, there's an overloaded constructor which can combine both of these steps.

PointerPointer ptr = new PointerPointer(pyObject);

Which will call the PointerPointer(P... array) constructor.

Thanks a lot for the clarification. I think what I've done is similar.

Do you see the PyObject -> String conversion? I don't. I searched for hours. PyString, PyStringObject.

PyObject_Str(PyObject) can be used to transform any object into a string (that's the equivalent of "str(obj)" in Python code.
The function is available, but where is this critical function to transform a PyObject into a String?

EDIT: thanks again for your reply. If it has been removed in Python 3.x, what is the new function?

As seen in the documentation for mapping 2.x modules to 3.x, the PyString type has been replaced with PyBytes. (see https://docs.python.org/2/howto/cporting.html#str-unicode-unification)

That would mean the function has been renamed to PyBytes_AsString which you can find in the javadoc. This method returns a BytePointer which is essentially a byte array, which has a nice and convenient getString() method.

Something like this should work:

PyObject ptype = new PyObject(null), pvalue = new PyObject(null), ptraceback = new PyObject(null);
PyErr_Fetch(ptype, pvalue, ptraceback);
String pStrErrorMessage = PyUnicode_AsUTF8(pvalue).getString("UTF-8");

@saudet and @supergrecko many thanks for your help.

Before I saw your message, I did:

            PyObject arg0 = new PyObject();
            PyObject arg1 = new PyObject();
            PyObject arg2 = new PyObject();
            PointerPointer pp0 = new PointerPointer(arg0);
            PointerPointer pp1 = new PointerPointer(arg1);
            PointerPointer pp2 = new PointerPointer(arg2);
            PyErr_Fetch(pp0, pp1, pp2);
            PyObject pys = new PyObject(pp1.get());

This works, but probably is suboptimal. I just hope this is "safe" that won't crash...

If you'd like to use PointerPointer, the right way would be something like this:

PointerPointer<PyObject> pp0 = new PointerPointer<PyObject>(1);
PointerPointer<PyObject> pp1 = new PointerPointer<PyObject>(1);
PointerPointer<PyObject> pp2 = new PointerPointer<PyObject>(1);
PyErr_Fetch(pp0, pp1, pp2);
PyObject pys = pp1.get(PyObject.class);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

mythly picture mythly  路  29Comments

eix128 picture eix128  路  23Comments

Maurice-Betzel picture Maurice-Betzel  路  32Comments

archenroot picture archenroot  路  56Comments

siddharthmudgal picture siddharthmudgal  路  26Comments