module python.exception;


import python.raw: PyObject;


class PythonException: Exception {

    this(in string backupMsg, in string file = __FILE__, in size_t line = __LINE__) {

        import python.raw: PyErr_Occurred;

        if(PyErr_Occurred is null)
            super(backupMsg, file, line);
        else {
            super(pythonExceptionMsg, file, line);
        }
    }
}


private string pythonExceptionMsg() {
    import python.raw: PyErr_Occurred, PyErr_Fetch, PyErr_NormalizeException,
        PyObject_GetAttrString, pyTupleCheck, PyTuple_GetItem;
    import python.conv.python_to_d: to;

    assert(PyErr_Occurred);

    PyObject* type, value, traceback;
    PyErr_Fetch(&type, &value, &traceback);
    PyErr_NormalizeException(&type, &value, &traceback);

    auto args = PyObject_GetAttrString(value, "args");
    assert(args !is null);
    assert(pyTupleCheck(args));
    const msg = PyTuple_GetItem(args, 0).to!string;

    return pyExceptionTypeToString(type) ~ ": " ~ msg;
}


private string pyExceptionTypeToString(PyObject* type) {
    import python.raw: PyObject_Str;
    import python.conv.python_to_d: to;

    enum prefix = "class <'";
    enum suffix = "'>";
    auto typeAsPyString = PyObject_Str(type);

    return typeAsPyString.to!string[prefix.length .. $ - suffix.length];
}