pyodide/src/python2js.c

222 lines
5.6 KiB
C
Raw Normal View History

2018-05-23 11:23:49 +00:00
#include "python2js.h"
#include <emscripten.h>
#include "hiwire.h"
#include "jsproxy.h"
#include "pyproxy.h"
2018-06-14 18:19:08 +00:00
int
pythonexc2js()
{
PyObject* type;
PyObject* value;
PyObject* traceback;
2018-05-23 11:23:49 +00:00
int no_traceback = 0;
PyErr_Fetch(&type, &value, &traceback);
PyErr_NormalizeException(&type, &value, &traceback);
int excval = -1;
int exc;
2018-06-14 18:19:08 +00:00
if (type == NULL || type == Py_None || value == NULL || value == Py_None) {
2018-05-30 18:09:49 +00:00
excval = hiwire_string_utf8((int)"No exception type or value");
2018-05-23 11:23:49 +00:00
PyErr_Print();
PyErr_Clear();
goto exit;
}
2018-06-14 18:19:08 +00:00
PyObject* tbmod = PyImport_ImportModule("traceback");
2018-05-23 11:23:49 +00:00
if (tbmod == NULL) {
2018-06-14 18:19:08 +00:00
PyObject* repr = PyObject_Repr(value);
2018-05-23 11:23:49 +00:00
if (repr == NULL) {
2018-05-30 18:09:49 +00:00
excval = hiwire_string_utf8((int)"Could not get repr for exception");
2018-05-23 11:23:49 +00:00
} else {
2018-05-31 00:27:18 +00:00
excval = python2js(repr);
2018-05-23 11:23:49 +00:00
Py_DECREF(repr);
}
} else {
2018-06-14 18:19:08 +00:00
PyObject* format_exception;
2018-05-23 11:23:49 +00:00
if (traceback == NULL || traceback == Py_None) {
no_traceback = 1;
format_exception = PyObject_GetAttrString(tbmod, "format_exception_only");
} else {
format_exception = PyObject_GetAttrString(tbmod, "format_exception");
}
if (format_exception == NULL) {
2018-06-14 18:19:08 +00:00
excval =
hiwire_string_utf8((int)"Could not get format_exception function");
2018-05-23 11:23:49 +00:00
} else {
2018-06-14 18:19:08 +00:00
PyObject* pylines;
2018-05-23 11:23:49 +00:00
if (no_traceback) {
2018-06-14 18:19:08 +00:00
pylines =
PyObject_CallFunctionObjArgs(format_exception, type, value, NULL);
2018-05-23 11:23:49 +00:00
} else {
2018-06-14 18:19:08 +00:00
pylines = PyObject_CallFunctionObjArgs(
format_exception, type, value, traceback, NULL);
2018-05-23 11:23:49 +00:00
}
if (pylines == NULL) {
2018-06-14 18:19:08 +00:00
excval =
hiwire_string_utf8((int)"Error calling traceback.format_exception");
2018-05-23 11:23:49 +00:00
PyErr_Print();
PyErr_Clear();
goto exit;
} else {
2018-06-14 18:19:08 +00:00
PyObject* newline = PyUnicode_FromString("");
PyObject* pystr = PyUnicode_Join(newline, pylines);
2018-05-23 11:23:49 +00:00
printf("Python exception:\n");
printf("%s\n", PyUnicode_AsUTF8(pystr));
2018-05-31 00:27:18 +00:00
excval = python2js(pystr);
2018-05-23 11:23:49 +00:00
Py_DECREF(pystr);
Py_DECREF(newline);
Py_DECREF(pylines);
}
Py_DECREF(format_exception);
}
Py_DECREF(tbmod);
}
2018-06-14 18:19:08 +00:00
exit:
2018-05-23 11:23:49 +00:00
Py_XDECREF(type);
Py_XDECREF(value);
Py_XDECREF(traceback);
PyErr_Clear();
hiwire_throw_error(excval);
return -1;
}
2018-06-14 18:19:08 +00:00
static int
is_type_name(PyObject* x, const char* name)
{
PyObject* x_type = PyObject_Type(x);
2018-05-23 11:23:49 +00:00
if (x_type == NULL) {
// If we can't get a type, that's probably ok in this case...
PyErr_Clear();
return 0;
}
2018-06-14 18:19:08 +00:00
PyObject* x_type_name = PyObject_Repr(x_type);
2018-05-23 11:23:49 +00:00
Py_DECREF(x_type);
int result = (PyUnicode_CompareWithASCIIString(x_type_name, name) == 0);
Py_DECREF(x_type_name);
return result;
}
2018-06-19 17:21:13 +00:00
static int
python2js_int(PyObject* x)
2018-06-14 18:19:08 +00:00
{
2018-05-23 11:23:49 +00:00
if (x == Py_None) {
2018-05-30 18:09:49 +00:00
return hiwire_undefined();
2018-05-23 11:23:49 +00:00
} else if (x == Py_True) {
2018-05-30 18:09:49 +00:00
return hiwire_true();
2018-05-23 11:23:49 +00:00
} else if (x == Py_False) {
2018-05-30 18:09:49 +00:00
return hiwire_false();
2018-05-23 11:23:49 +00:00
} else if (PyLong_Check(x)) {
long x_long = PyLong_AsLongLong(x);
if (x_long == -1 && PyErr_Occurred()) {
2018-06-19 17:21:13 +00:00
return -1;
2018-05-23 11:23:49 +00:00
}
2018-05-30 18:09:49 +00:00
return hiwire_int(x_long);
2018-05-23 11:23:49 +00:00
} else if (PyFloat_Check(x)) {
double x_double = PyFloat_AsDouble(x);
if (x_double == -1.0 && PyErr_Occurred()) {
2018-06-19 17:21:13 +00:00
return -1;
2018-05-23 11:23:49 +00:00
}
2018-05-30 18:09:49 +00:00
return hiwire_double(x_double);
2018-05-23 11:23:49 +00:00
} else if (PyUnicode_Check(x)) {
int kind = PyUnicode_KIND(x);
int data = (int)PyUnicode_DATA(x);
int length = (int)PyUnicode_GET_LENGTH(x);
switch (kind) {
2018-08-03 16:49:08 +00:00
case PyUnicode_1BYTE_KIND:
return hiwire_string_ucs1(data, length);
case PyUnicode_2BYTE_KIND:
return hiwire_string_ucs2(data, length);
case PyUnicode_4BYTE_KIND:
return hiwire_string_ucs4(data, length);
default:
PyErr_SetString(PyExc_ValueError, "Unknown Unicode KIND");
return -1;
2018-05-23 11:23:49 +00:00
}
} else if (PyBytes_Check(x)) {
2018-06-14 18:19:08 +00:00
char* x_buff;
2018-05-23 11:23:49 +00:00
Py_ssize_t length;
if (PyBytes_AsStringAndSize(x, &x_buff, &length)) {
2018-06-19 17:21:13 +00:00
return -1;
2018-05-23 11:23:49 +00:00
}
2018-06-14 18:19:08 +00:00
return hiwire_bytes((int)(void*)x_buff, length);
2018-05-23 11:23:49 +00:00
} else if (JsProxy_Check(x)) {
return JsProxy_AsJs(x);
2018-05-31 00:27:18 +00:00
} else if (PyList_Check(x) || is_type_name(x, "<class 'numpy.ndarray'>")) {
2018-05-30 18:09:49 +00:00
int jsarray = hiwire_array();
2018-05-23 11:23:49 +00:00
size_t length = PySequence_Size(x);
for (size_t i = 0; i < length; ++i) {
2018-06-14 18:19:08 +00:00
PyObject* pyitem = PySequence_GetItem(x, i);
if (pyitem == NULL) {
2018-05-23 11:23:49 +00:00
// If something goes wrong converting the sequence (as is the case with
// Pandas data frames), fallback to the Python object proxy
hiwire_decref(jsarray);
PyErr_Clear();
Py_INCREF(x);
return pyproxy_new((int)x);
}
2018-06-19 17:21:13 +00:00
int jsitem = python2js_int(pyitem);
2018-05-23 11:23:49 +00:00
if (jsitem == -1) {
Py_DECREF(pyitem);
2018-05-23 11:23:49 +00:00
hiwire_decref(jsarray);
2018-06-19 17:21:13 +00:00
return -1;
2018-05-23 11:23:49 +00:00
}
Py_DECREF(pyitem);
2018-05-23 11:23:49 +00:00
hiwire_push_array(jsarray, jsitem);
hiwire_decref(jsitem);
2018-05-23 11:23:49 +00:00
}
return jsarray;
} else if (PyDict_Check(x)) {
2018-05-30 18:09:49 +00:00
int jsdict = hiwire_object();
PyObject *pykey, *pyval;
2018-05-23 11:23:49 +00:00
Py_ssize_t pos = 0;
while (PyDict_Next(x, &pos, &pykey, &pyval)) {
2018-06-19 17:21:13 +00:00
int jskey = python2js_int(pykey);
if (jskey == -1) {
2018-05-23 11:23:49 +00:00
hiwire_decref(jsdict);
2018-06-19 17:21:13 +00:00
return -1;
2018-05-23 11:23:49 +00:00
}
2018-06-19 17:21:13 +00:00
int jsval = python2js_int(pyval);
if (jsval == -1) {
hiwire_decref(jskey);
2018-05-23 11:23:49 +00:00
hiwire_decref(jsdict);
2018-06-19 17:21:13 +00:00
return -1;
2018-05-23 11:23:49 +00:00
}
hiwire_push_object_pair(jsdict, jskey, jsval);
hiwire_decref(jskey);
hiwire_decref(jsval);
2018-05-23 11:23:49 +00:00
}
return jsdict;
} else {
Py_INCREF(x);
return pyproxy_new((int)x);
}
}
2018-06-19 17:21:13 +00:00
int
2018-06-20 19:05:13 +00:00
python2js(PyObject* x)
{
2018-06-19 17:21:13 +00:00
int result = python2js_int(x);
if (result == -1) {
return pythonexc2js();
}
return result;
}
2018-06-14 18:19:08 +00:00
int
python2js_init()
{
2018-05-23 11:23:49 +00:00
return 0;
}