in src/python_embedded.c [162:271]
qd_error_t qd_py_to_composed(PyObject *value, qd_composed_field_t *field)
{
qd_python_check_lock();
qd_error_clear();
if (Py_IsNone(value)) {
qd_compose_insert_null(field);
}
else if (PyBool_Check(value)) {
qd_compose_insert_bool(field, PyLong_AsLong(value) ? 1 : 0);
}
else if (QD_PY_INT_CHECK(value)) {
// We are now sure that the value is an integer type
int64_t ival = QD_PY_INT_2_INT64(value);
if (INT32_MIN <= ival && ival <= INT32_MAX) {
qd_compose_insert_int(field, (int32_t) ival);
} else {
qd_compose_insert_long(field, ival);
}
}
else if (PyFloat_Check(value)) {
qd_compose_insert_double(field, PyFloat_AS_DOUBLE(value));
}
else if (PyUnicode_Check(value)) {
char *data = py_string_2_c(value);
if (data) {
qd_compose_insert_string(field, data);
free(data);
} else {
qd_log(log_source, QD_LOG_ERROR,
"Unable to convert python unicode object");
}
}
else if (PyBytes_Check(value)) {
// Note: In python 2.X PyBytes is simply an alias for the PyString
// type. In python 3.x PyBytes is a distinct type (may contain zeros),
// and all strings are PyUnicode types. Historically
// this code has just assumed this data is always a null terminated
// UTF8 string. We continue that tradition for Python2, but ending up
// here in Python3 means this is actually binary data which may have
// embedded zeros.
if (PY_MAJOR_VERSION <= 2) {
qd_compose_insert_string(field, PyBytes_AsString(value));
} else {
ssize_t len = 0;
char *data = NULL;
PyBytes_AsStringAndSize(value, &data, &len);
qd_compose_insert_binary(field, (uint8_t *)data, len);
}
}
else if (PyDict_Check(value)) {
Py_ssize_t iter = 0;
PyObject *key;
PyObject *val;
qd_compose_start_map(field);
while (PyDict_Next(value, &iter, &key, &val)) {
qd_py_to_composed(key, field); QD_ERROR_RET();
qd_py_to_composed(val, field); QD_ERROR_RET();
}
QD_ERROR_PY_RET();
qd_compose_end_map(field);
}
else if (PyList_Check(value)) {
Py_ssize_t count = PyList_Size(value);
if (count == 0)
qd_compose_empty_list(field);
else {
qd_compose_start_list(field);
for (Py_ssize_t idx = 0; idx < count; idx++) {
PyObject *item = PyList_GetItem(value, idx); QD_ERROR_PY_RET();
qd_py_to_composed(item, field); QD_ERROR_RET();
}
qd_compose_end_list(field);
}
}
else if (PyTuple_Check(value)) {
Py_ssize_t count = PyTuple_Size(value);
if (count == 0)
qd_compose_empty_list(field);
else {
qd_compose_start_list(field);
for (Py_ssize_t idx = 0; idx < count; idx++) {
PyObject *item = PyTuple_GetItem(value, idx); QD_ERROR_PY_RET();
qd_py_to_composed(item, field); QD_ERROR_RET();
}
qd_compose_end_list(field);
}
}
else {
PyObject *type=0, *typestr=0, *repr=0;
if ((type = PyObject_Type(value)) &&
(typestr = PyObject_Str(type)) &&
(repr = PyObject_Repr(value))) {
char *t_str = py_string_2_c(typestr);
char *r_str = py_string_2_c(repr);
qd_error(QD_ERROR_TYPE, "Can't compose object of type %s: %s",
t_str ? t_str : "Unknown",
r_str ? r_str : "Unknown");
free(t_str);
free(r_str);
} else
qd_error(QD_ERROR_TYPE, "Can't compose python object of unknown type");
Py_XDECREF(type);
Py_XDECREF(typestr);
Py_XDECREF(repr);
}
return qd_error_code();
}