* Interpret a possible axes keyword argument, using it to fill the remap_axis * array which maps default to actual axes for each operand, indexed as * as remap_axis[iop][iaxis]. The default axis order has first all broadcast * axes and then the core axes the gufunc operates on. * * Returns 0 on success, and -1 on failure */
| 1808 | * Returns 0 on success, and -1 on failure |
| 1809 | */ |
| 1810 | static int |
| 1811 | _parse_axes_arg(PyUFuncObject *ufunc, int op_core_num_dims[], PyObject *axes, |
| 1812 | PyArrayObject **op, int broadcast_ndim, int **remap_axis) { |
| 1813 | static PyObject *AxisError_cls = NULL; |
| 1814 | |
| 1815 | int nin = ufunc->nin; |
| 1816 | int nop = ufunc->nargs; |
| 1817 | int iop, list_size; |
| 1818 | |
| 1819 | if (!PyList_Check(axes)) { |
| 1820 | PyErr_SetString(PyExc_TypeError, "axes should be a list."); |
| 1821 | return -1; |
| 1822 | } |
| 1823 | list_size = PyList_Size(axes); |
| 1824 | if (list_size != nop) { |
| 1825 | if (list_size != nin || _has_output_coredims(ufunc)) { |
| 1826 | PyErr_Format(PyExc_ValueError, |
| 1827 | "axes should be a list with an entry for all " |
| 1828 | "%d inputs and outputs; entries for outputs can only " |
| 1829 | "be omitted if none of them has core axes.", |
| 1830 | nop); |
| 1831 | return -1; |
| 1832 | } |
| 1833 | for (iop = nin; iop < nop; iop++) { |
| 1834 | remap_axis[iop] = NULL; |
| 1835 | } |
| 1836 | } |
| 1837 | for (iop = 0; iop < list_size; ++iop) { |
| 1838 | int op_ndim, op_ncore, op_nbroadcast; |
| 1839 | int have_seen_axis[NPY_MAXDIMS] = {0}; |
| 1840 | PyObject *op_axes_tuple, *axis_item; |
| 1841 | int axis, op_axis; |
| 1842 | |
| 1843 | op_ncore = op_core_num_dims[iop]; |
| 1844 | if (op[iop] != NULL) { |
| 1845 | op_ndim = PyArray_NDIM(op[iop]); |
| 1846 | op_nbroadcast = op_ndim - op_ncore; |
| 1847 | } |
| 1848 | else { |
| 1849 | op_nbroadcast = broadcast_ndim; |
| 1850 | op_ndim = broadcast_ndim + op_ncore; |
| 1851 | } |
| 1852 | /* |
| 1853 | * Get axes tuple for operand. If not a tuple already, make it one if |
| 1854 | * there is only one axis (its content is checked later). |
| 1855 | */ |
| 1856 | op_axes_tuple = PyList_GET_ITEM(axes, iop); |
| 1857 | if (PyTuple_Check(op_axes_tuple)) { |
| 1858 | if (PyTuple_Size(op_axes_tuple) != op_ncore) { |
| 1859 | /* must have been a tuple with too many entries. */ |
| 1860 | npy_cache_import( |
| 1861 | "numpy.exceptions", "AxisError", &AxisError_cls); |
| 1862 | if (AxisError_cls == NULL) { |
| 1863 | return -1; |
| 1864 | } |
| 1865 | PyErr_Format(AxisError_cls, |
| 1866 | "%s: operand %d has %d core dimensions, " |
| 1867 | "but %zd dimensions are specified by axes tuple.", |
no test coverage detected