Skip to content
Merged
79 changes: 37 additions & 42 deletions src/luainpython.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>

/* need this to build with Lua 5.2: enables lua_strlen() macro */
Expand Down Expand Up @@ -110,7 +111,12 @@ static PyObject *LuaCall(lua_State *L, PyObject *args)
{
PyObject *ret = NULL;
PyObject *arg;
int nargs, rc, i;
#ifdef PY_SSIZE_T_CLEAN
Py_ssize_t nargs, i;
#else
int nargs, i;
#endif
int rc;

if (!PyTuple_Check(args)) {
PyErr_SetString(PyExc_TypeError, "tuple expected");
Expand Down Expand Up @@ -358,7 +364,7 @@ static PyObject* LuaObject_richcmp(PyObject *lhs, PyObject *rhs, int op)
PyErr_SetString(PyExc_RuntimeError, lua_tostring(LuaState, -1));
return NULL;
}
return lua_toboolean(LuaState, -1) ? Py_True : Py_False;
return LuaConvert(LuaState, -1);
}

static PyObject *LuaObject_call(PyObject *obj, PyObject *args)
Expand Down Expand Up @@ -396,9 +402,17 @@ static PyObject *LuaObject_iternext(LuaObject *obj)
return ret;
}

#ifdef PY_SSIZE_T_CLEAN
static Py_ssize_t LuaObject_length(LuaObject *obj)
#else
static int LuaObject_length(LuaObject *obj)
#endif
{
#ifdef PY_SSIZE_T_CLEAN
Py_ssize_t len;
#else
int len;
#endif
lua_rawgeti(LuaState, LUA_REGISTRYINDEX, ((LuaObject*)obj)->ref);
len = luaL_len(LuaState, -1);
lua_settop(LuaState, 0);
Expand Down Expand Up @@ -428,54 +442,35 @@ static PyMappingMethods LuaObject_as_mapping = {

PyTypeObject LuaObject_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"lua.custom", /*tp_name*/
sizeof(LuaObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)LuaObject_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
LuaObject_str, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&LuaObject_as_mapping, /*tp_as_mapping*/
0, /*tp_hash*/
(ternaryfunc)LuaObject_call, /*tp_call*/
LuaObject_str, /*tp_str*/
LuaObject_getattr, /*tp_getattro*/
LuaObject_setattr, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"custom lua object", /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
LuaObject_richcmp, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
PyObject_SelfIter, /*tp_iter*/
(iternextfunc)LuaObject_iternext, /*tp_iternext*/
0, /*tp_methods*/
0, /*tp_members*/
0, /*tp_getset*/
0, /*tp_base*/
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
0, /*tp_init*/
PyType_GenericAlloc, /*tp_alloc*/
PyType_GenericNew, /*tp_new*/
PyObject_Del, /*tp_free*/
0, /*tp_is_gc*/
.tp_name = "lua.custom",
.tp_basicsize = sizeof(LuaObject),
.tp_dealloc = (destructor)LuaObject_dealloc,
.tp_repr = LuaObject_str,
.tp_as_mapping = &LuaObject_as_mapping,
.tp_call = (ternaryfunc)LuaObject_call,
.tp_str = LuaObject_str,
.tp_getattro = LuaObject_getattr,
.tp_setattro = LuaObject_setattr,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_doc = "custom lua object",
.tp_richcompare = LuaObject_richcmp,
.tp_iter = PyObject_SelfIter,
.tp_iternext = (iternextfunc)LuaObject_iternext,
.tp_alloc = PyType_GenericAlloc,
.tp_new = PyType_GenericNew,
.tp_free = PyObject_Del,
};


PyObject *Lua_run(PyObject *args, int eval)
{
PyObject *ret;
char *buf = NULL;
char *s;
#ifdef PY_SSIZE_T_CLEAN
Py_ssize_t len;
#else
int len;
#endif

if (!PyArg_ParseTuple(args, "s#", &s, &len))
return NULL;
Expand Down
48 changes: 46 additions & 2 deletions src/pythoninlua.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <Python.h>
#if defined(__linux__)
# include <dlfcn.h>
Expand Down Expand Up @@ -183,8 +184,51 @@ static int py_object_call(lua_State *L)
ret = py_convert(L, value);
Py_DECREF(value);
} else {
PyErr_Print();
luaL_error(L, "error calling python function");
char s_exc[1024] = {0};
char s_traceback[1024] = {0};

PyObject *exc_type, *exc_value, *exc_traceback;
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);

PyObject *exc_str = PyObject_Str(exc_value);

// Need not be garbage collected as per documentation of PyUnicode_AsUTF8
const char *exc_cstr = (exc_str)?PyUnicode_AsUTF8(exc_str):"";
strncpy(s_exc, (!(exc_cstr)?"UNKNOWN ERROR\n":exc_cstr), 1023);

if (exc_value != NULL && exc_traceback != NULL) {
PyObject *traceback_module = PyImport_ImportModule("traceback");
if (traceback_module != NULL) {
PyObject *traceback_list = PyObject_CallMethod(traceback_module,
"format_exception", "OOO", exc_type, exc_value, exc_traceback);
if (traceback_list != NULL) {
PyObject *traceback_str = PyUnicode_Join(PyUnicode_FromString(""), traceback_list);
if (traceback_str != NULL) {
// Need not be garbage collected as per documentation of PyUnicode_AsUTF8
const char *traceback_cstr = PyUnicode_AsUTF8(traceback_str);
if (traceback_cstr != NULL) {
strncpy(s_traceback, traceback_cstr, 1023);
}
Py_XDECREF(traceback_str);
}
Py_XDECREF(traceback_list);
}
Py_XDECREF(traceback_module);
}
}
Py_XDECREF(exc_type);
Py_XDECREF(exc_value);
Py_XDECREF(exc_traceback);
Py_XDECREF(exc_str);

if (*s_traceback == '\0') {
luaL_error(L, "error calling python function:\nException: %s", s_exc);
}
else {
luaL_error(L, "error calling python function:\nException: %s", s_traceback);
}

}

return ret;
Expand Down
25 changes: 25 additions & 0 deletions tests/test_py.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,28 @@ bar = 2

assert(python.globals().foo == 1)
assert(python.globals().bar == 2)

python.execute
[[
def throw_exc():
raise Exception("THIS EXCEPTION")
]]

local status, exc = pcall(python.globals().throw_exc)
assert(status == false)
assert(exc ==
[[error calling python function:
Exception: Traceback (most recent call last):
File "<string>", line 2, in throw_exc
Exception: THIS EXCEPTION
]], exc)

local b, e = string.find(exc, "Exception: ", 1);
local ob, oe = b, e;
while (b ~= nil) do
ob, oe = b, e
b, e = string.find(exc, "Exception: ", e+1)
end
local exc_s = (string.sub(exc, oe+1))
--assert((require "pl.stringx").strip(exc_s) == "THIS EXCEPTION");