Skip to content

Python 3 compatibility #335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 8, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 83 additions & 5 deletions python/_jsonnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ static const char *exc_to_str(void)
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
PyObject *exc_str = PyObject_Str(pvalue);
#if PY_MAJOR_VERSION >= 3
return PyUnicode_AsUTF8(exc_str);
#else
return PyString_AsString(exc_str);
#endif
}

struct NativeCtx {
Expand All @@ -45,20 +49,34 @@ struct NativeCtx {
static struct JsonnetJsonValue *python_to_jsonnet_json(struct JsonnetVm *vm, PyObject *v,
const char **err_msg)
{
#if PY_MAJOR_VERSION < 3
if (PyString_Check(v)) {
return jsonnet_json_make_string(vm, PyString_AsString(v));
} else if (PyUnicode_Check(v)) {
#else
if (PyUnicode_Check(v)) {
#endif
struct JsonnetJsonValue *r;
PyObject *str = PyUnicode_AsUTF8String(v);
r = jsonnet_json_make_string(vm, PyString_AsString(str));
#if PY_MAJOR_VERSION >= 3
const char *cstr = PyBytes_AsString(str);
#else
const char *cstr = PyString_AsString(str);
#endif
r = jsonnet_json_make_string(vm, cstr);
Py_DECREF(str);
return r;
} else if (PyBool_Check(v)) {
return jsonnet_json_make_bool(vm, PyObject_IsTrue(v));
} else if (PyFloat_Check(v)) {
return jsonnet_json_make_number(vm, PyFloat_AsDouble(v));
#if PY_MAJOR_VERSION >= 3
} else if (PyLong_Check(v)) {
return jsonnet_json_make_number(vm, (double)(PyLong_AsLong(v)));
#else
} else if (PyInt_Check(v)) {
return jsonnet_json_make_number(vm, (double)(PyInt_AsLong(v)));
#endif
} else if (v == Py_None) {
return jsonnet_json_make_null(vm);
} else if (PySequence_Check(v)) {
Expand Down Expand Up @@ -88,7 +106,11 @@ static struct JsonnetJsonValue *python_to_jsonnet_json(struct JsonnetVm *vm, PyO
obj = jsonnet_json_make_object(vm);
while (PyDict_Next(v, &pos, &key, &val)) {
struct JsonnetJsonValue *json_val;
#if PY_MAJOR_VERSION >= 3
const char *key_ = PyUnicode_AsUTF8(key);
#else
const char *key_ = PyString_AsString(key);
#endif
if (key_ == NULL) {
*err_msg = "Non-string key in dict returned from Python Jsonnet native extension.";
jsonnet_json_destroy(vm, obj);
Expand All @@ -108,7 +130,7 @@ static struct JsonnetJsonValue *python_to_jsonnet_json(struct JsonnetVm *vm, PyO
}
}

/* This function is bound for every native callback, but with a different
/* This function is bound for every native callback, but with a different
* context.
*/
static struct JsonnetJsonValue *cpython_native_callback(
Expand All @@ -130,7 +152,11 @@ static struct JsonnetJsonValue *cpython_native_callback(
int param_num = jsonnet_json_extract_number(ctx->vm, argv[i], &d);
PyObject *pyobj;
if (param_str != NULL) {
#if PY_MAJOR_VERSION >= 3
pyobj = PyUnicode_FromString(param_str);
#else
pyobj = PyString_FromString(param_str);
#endif
} else if (param_null) {
pyobj = Py_None;
} else if (param_bool != 2) {
Expand Down Expand Up @@ -204,12 +230,21 @@ static char *cpython_import_callback(void *ctx_, const char *base, const char *r
} else {
PyObject *file_name = PyTuple_GetItem(result, 0);
PyObject *file_content = PyTuple_GetItem(result, 1);
#if PY_MAJOR_VERSION >= 3
if (!PyUnicode_Check(file_name) || !PyUnicode_Check(file_content)) {
#else
if (!PyString_Check(file_name) || !PyString_Check(file_content)) {
#endif
out = jsonnet_str(ctx->vm, "import_callback did not return a pair of strings");
*success = 0;
} else {
#if PY_MAJOR_VERSION >= 3
const char *found_here_cstr = PyUnicode_AsUTF8(file_name);
const char *content_cstr = PyUnicode_AsUTF8(file_content);
#else
const char *found_here_cstr = PyString_AsString(file_name);
const char *content_cstr = PyString_AsString(file_content);
#endif
*found_here = jsonnet_str(ctx->vm, found_here_cstr);
out = jsonnet_str(ctx->vm, content_cstr);
*success = 1;
Expand All @@ -229,7 +264,11 @@ static PyObject *handle_result(struct JsonnetVm *vm, char *out, int error)
jsonnet_destroy(vm);
return NULL;
} else {
#if PY_MAJOR_VERSION >= 3
PyObject *ret = PyUnicode_FromString(out);
#else
PyObject *ret = PyString_FromString(out);
#endif
jsonnet_realloc(vm, out, 0);
jsonnet_destroy(vm);
return ret;
Expand All @@ -242,14 +281,22 @@ int handle_vars(struct JsonnetVm *vm, PyObject *map, int code, int tla)

PyObject *key, *val;
Py_ssize_t pos = 0;

while (PyDict_Next(map, &pos, &key, &val)) {
#if PY_MAJOR_VERSION >= 3
const char *key_ = PyUnicode_AsUTF8(key);
#else
const char *key_ = PyString_AsString(key);
#endif
if (key_ == NULL) {
jsonnet_destroy(vm);
return 0;
}
#if PY_MAJOR_VERSION >= 3
const char *val_ = PyUnicode_AsUTF8(val);
#else
const char *val_ = PyString_AsString(val);
#endif
if (val_ == NULL) {
jsonnet_destroy(vm);
return 0;
Expand Down Expand Up @@ -308,7 +355,11 @@ static int handle_native_callbacks(struct JsonnetVm *vm, PyObject *native_callba
Py_ssize_t i;
Py_ssize_t num_params;
PyObject *params;
#if PY_MAJOR_VERSION >= 3
const char *key_ = PyUnicode_AsUTF8(key);
#else
const char *key_ = PyString_AsString(key);
#endif
if (key_ == NULL) {
PyErr_SetString(PyExc_TypeError, "native callback dict keys must be string");
goto bad;
Expand All @@ -329,7 +380,11 @@ static int handle_native_callbacks(struct JsonnetVm *vm, PyObject *native_callba
num_params = PyTuple_Size(params);
for (i = 0; i < num_params ; ++i) {
PyObject *param = PyTuple_GetItem(params, 0);
#if PY_MAJOR_VERSION >= 3
if (!PyUnicode_Check(param)) {
#else
if (!PyString_Check(param)) {
#endif
PyErr_SetString(PyExc_TypeError, "native callback param must be string");
goto bad;
}
Expand All @@ -352,21 +407,29 @@ static int handle_native_callbacks(struct JsonnetVm *vm, PyObject *native_callba
}

*ctxs = malloc(sizeof(struct NativeCtx) * num_natives);

/* Re-use num_natives but just as a counter this time. */
num_natives = 0;
pos = 0;
while (PyDict_Next(native_callbacks, &pos, &key, &val)) {
Py_ssize_t i;
Py_ssize_t num_params;
PyObject *params;
#if PY_MAJOR_VERSION >= 3
const char *key_ = PyUnicode_AsUTF8(key);
#else
const char *key_ = PyString_AsString(key);
#endif
params = PyTuple_GetItem(val, 0);
num_params = PyTuple_Size(params);
/* Include space for terminating NULL. */
const char **params_c = malloc(sizeof(const char*) * (num_params + 1));
for (i = 0; i < num_params ; ++i) {
#if PY_MAJOR_VERSION >= 3
params_c[i] = PyUnicode_AsUTF8(PyTuple_GetItem(params, i));
#else
params_c[i] = PyString_AsString(PyTuple_GetItem(params, i));
#endif
}
params_c[num_params] = NULL;
(*ctxs)[num_natives].vm = vm;
Expand Down Expand Up @@ -498,8 +561,23 @@ static PyMethodDef module_methods[] = {
{NULL, NULL, 0, NULL}
};

#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef _jsonnet =
{
PyModuleDef_HEAD_INIT,
"_jsonnet",
"A Python interface to Jsonnet.",
-1,
module_methods,
};

PyMODINIT_FUNC PyInit__jsonnet(void)
{
return PyModule_Create(&_jsonnet);
}
#else
PyMODINIT_FUNC init_jsonnet(void)
{
Py_InitModule3("_jsonnet", module_methods, "A Python interface to Jsonnet.");
}

#endif