* Create the array of converter functions from the Python converters. */
| 30 | * Create the array of converter functions from the Python converters. |
| 31 | */ |
| 32 | static PyObject ** |
| 33 | create_conv_funcs( |
| 34 | PyObject *converters, Py_ssize_t num_fields, const Py_ssize_t *usecols) |
| 35 | { |
| 36 | assert(converters != Py_None); |
| 37 | |
| 38 | PyObject **conv_funcs = PyMem_Calloc(num_fields, sizeof(PyObject *)); |
| 39 | if (conv_funcs == NULL) { |
| 40 | PyErr_NoMemory(); |
| 41 | return NULL; |
| 42 | } |
| 43 | |
| 44 | if (PyCallable_Check(converters)) { |
| 45 | /* a single converter used for all columns individually */ |
| 46 | for (Py_ssize_t i = 0; i < num_fields; i++) { |
| 47 | Py_INCREF(converters); |
| 48 | conv_funcs[i] = converters; |
| 49 | } |
| 50 | return conv_funcs; |
| 51 | } |
| 52 | else if (!PyDict_Check(converters)) { |
| 53 | PyErr_SetString(PyExc_TypeError, |
| 54 | "converters must be a dictionary mapping columns to converter " |
| 55 | "functions or a single callable."); |
| 56 | goto error; |
| 57 | } |
| 58 | |
| 59 | PyObject *key, *value; |
| 60 | Py_ssize_t pos = 0; |
| 61 | while (PyDict_Next(converters, &pos, &key, &value)) { |
| 62 | Py_ssize_t column = PyNumber_AsSsize_t(key, PyExc_IndexError); |
| 63 | if (column == -1 && PyErr_Occurred()) { |
| 64 | PyErr_Format(PyExc_TypeError, |
| 65 | "keys of the converters dictionary must be integers; " |
| 66 | "got %.100R", key); |
| 67 | goto error; |
| 68 | } |
| 69 | if (usecols != NULL) { |
| 70 | /* |
| 71 | * This code searches for the corresponding usecol. It is |
| 72 | * identical to the legacy usecols code, which has two weaknesses: |
| 73 | * 1. It fails for duplicated usecols only setting converter for |
| 74 | * the first one. |
| 75 | * 2. It fails e.g. if usecols uses negative indexing and |
| 76 | * converters does not. (This is a feature, since it allows |
| 77 | * us to correctly normalize converters to result column here.) |
| 78 | */ |
| 79 | Py_ssize_t i = 0; |
| 80 | for (; i < num_fields; i++) { |
| 81 | if (column == usecols[i]) { |
| 82 | column = i; |
| 83 | break; |
| 84 | } |
| 85 | } |
| 86 | if (i == num_fields) { |
| 87 | continue; /* ignore unused converter */ |
| 88 | } |
| 89 | } |