Repository: numpy/numpy
File: numpy/_core/src/umath/ufunc_type_resolution.c (C)

Code before:
    if (out_dtypes[0]->type_num == NPY_BOOL) {
        PyErr_Format(PyExc_TypeError,
            "The numpy boolean negative, the `-` operator, is not supported, "
            "use the `~` operator or the logical_not function instead.");
        return -1;
    }

    return ret;
}

/*
 * This function applies special type resolution rules for the 'sign' ufunc.
 * 'sign' converts timedelta64 to float64, so isn't covered by the simple
 * unary type resolution.
 *
 * Returns 0 on success, -1 on error.
 */
NPY_NO_EXPORT int
PyUFunc_SignTypeResolver(PyUFuncObject *ufunc,
                         NPY_CASTING casting,
                         PyArrayObject **operands,
                         PyObject *type_tup,
                         PyArray_Descr **out_dtypes)
{
    if (PyArray_DESCR(operands[0])->type_num == NPY_TIMEDELTA) {
        out_dtypes[0] = NPY_DT_CALL_ensure_canonical(PyArray_DESCR(operands[0]));
        out_dtypes[1] = PyArray_DescrFromType(NPY_DOUBLE);
        return 0;
    }
    else {
        return PyUFunc_SimpleUniformOperationTypeResolver(ufunc, casting,
                    operands, type_tup, out_dtypes);
    }
}


/*
 * The ones_like function shouldn't really be a ufunc, but while it
 * still is, this provides type resolution that always forces UNSAFE
 * casting.
 */
NPY_NO_EXPORT int
PyUFunc_OnesLikeTypeResolver(PyUFuncObject *ufunc,
                                NPY_CASTING NPY_UNUSED(casting),
                                PyArrayObject **operands,
                                PyObject *type_tup,
                                PyArray_Descr **out_dtypes)
{
    return PyUFunc_SimpleUniformOperationTypeResolver(ufunc,
                        NPY_UNSAFE_CASTING,
                        operands, type_tup, out_dtypes);

Review comment (bug):
I guess it's practically impossible, but I think this call can actually fail.
Maybe I should actually fix this, so that it can't fail for the simple dtypes (i.e. the simple ones can actually just return the `singleton` here, but they create a new dtype right now).

Other than this nit (and I think it's probably wrong in at least one other place, so I am happy to change `_ensure_canonical` here for the simple dtypes), it looks good to me.

@mhvk I am fine with putting this in, don't see much chance of downstream annoyance. I'll note that astropy asked before to not merge weirder things while the rc is in progress because it can be confusing in CI (i.e. you expect the change to be part of the rc release, but it's not).
But I am fine with just merging either way.

Code after:
    if (out_dtypes[0]->type_num == NPY_BOOL) {
        PyErr_Format(PyExc_TypeError,
            "The numpy boolean negative, the `-` operator, is not supported, "
            "use the `~` operator or the logical_not function instead.");
        return -1;
    }

    return ret;
}

/*
 * This function applies special type resolution rules for the 'sign' ufunc.
 * 'sign' converts timedelta64 to float64, so isn't covered by the simple
 * unary type resolution.
 *
 * Returns 0 on success, -1 on error.
 */
NPY_NO_EXPORT int
PyUFunc_SignTypeResolver(PyUFuncObject *ufunc,
                         NPY_CASTING casting,
                         PyArrayObject **operands,
                         PyObject *type_tup,
                         PyArray_Descr **out_dtypes)
{
    if (PyArray_DESCR(operands[0])->type_num == NPY_TIMEDELTA) {
        out_dtypes[0] = NPY_DT_CALL_ensure_canonical(PyArray_DESCR(operands[0]));
        if (out_dtypes[0] == NULL) {
            return -1;
        }
        out_dtypes[1] = PyArray_DescrFromType(NPY_DOUBLE);
        return 0;
    }
    else {
        return PyUFunc_SimpleUniformOperationTypeResolver(ufunc, casting,
                    operands, type_tup, out_dtypes);
    }
}


/*
 * The ones_like function shouldn't really be a ufunc, but while it
 * still is, this provides type resolution that always forces UNSAFE
 * casting.
 */
NPY_NO_EXPORT int
PyUFunc_OnesLikeTypeResolver(PyUFuncObject *ufunc,
                                NPY_CASTING NPY_UNUSED(casting),
                                PyArrayObject **operands,
                                PyObject *type_tup,
                                PyArray_Descr **out_dtypes)
{