Repository: numpy/numpy
File: numpy/_core/src/umath/dispatching.cpp (C++)

Code before:
    PyObject *info = PyTuple_Pack(2, dtypes, bmeth->method);
    Py_DECREF(bmeth);
    Py_DECREF(dtypes);
    if (info == NULL) {
        return -1;
    }
    return PyUFunc_AddLoop((PyUFuncObject *)ufunc, info, 0);
}


/*UFUNC_API
 * Add multiple loops to ufuncs from ArrayMethod specs. This also
 * handles the registration of sort and argsort methods for dtypes
 * from ArrayMethod specs.
 */
NPY_NO_EXPORT int
PyUFunc_AddLoopsFromSpecs(PyUFunc_LoopSlot *slots)
{
    PyUFunc_LoopSlot *slot;
    for (slot = slots; slot->name != NULL; slot++) {
        PyObject *ufunc = npy_import("numpy", slot->name);
        if (ufunc == NULL) {
            return -1;
        }

        PyObject *sort = npy_import("numpy", "sort");
        PyObject *argsort = npy_import("numpy", "argsort");
        if (sort == NULL || argsort == NULL) {
            Py_XDECREF(ufunc);
            Py_XDECREF(sort);
            Py_XDECREF(argsort);
            return -1;
        }

        if (ufunc == sort) {
            PyArray_DTypeMeta *dtype = slot->spec->dtypes[0];

            PyBoundArrayMethodObject *sort_meth = PyArrayMethod_FromSpec_int(slot->spec, 0);
            if (sort_meth == NULL) {
                PyErr_Format(PyExc_TypeError, "Failed to create sort method for %R", dtype);
                return -1;
            }

            NPY_DT_SLOTS(dtype)->sort_meth = sort_meth->method;
            Py_INCREF(sort_meth->method);
            Py_DECREF(sort_meth);
        }
        else if (ufunc == argsort) {
            PyArray_DTypeMeta *dtype = slot->spec->dtypes[0];

            PyBoundArrayMethodObject *argsort_meth = PyArrayMethod_FromSpec_int(slot->spec, 0);

Review comment (bug):
So, we can still do this the inelegant way (but really, runtime import should work!). Outside of the loop,
```
static PyObject *sort = NULL;
static PyObject *argsort = NULL;
if (sort == NULL) {
    sort = npy_import("numpy", "sort");
    if (sort == NULL) {
        return -1;
    }
if (argsort == NULL) {
    argsort = npy_import("numpy", "argsort");
    if (argsort == NULL) {
        return -1;
    }
}
```

But I'm really confused why what you had failed (hard to believe it had to do with being inside the loop), i.e., 
```
if (npy_cache_import_runtime("numpy", "sort", &npy_runtime_imports.sort) == -1
    || npy_cache_import_runtime("numpy", "argsort", &npy_runtime_imports.argsort) == -1) {
    return NULL;
}
```

Code after:
    PyObject *info = PyTuple_Pack(2, dtypes, bmeth->method);
    Py_DECREF(bmeth);
    Py_DECREF(dtypes);
    if (info == NULL) {
        return -1;
    }
    return PyUFunc_AddLoop((PyUFuncObject *)ufunc, info, 0);
}


/*UFUNC_API
 * Add multiple loops to ufuncs from ArrayMethod specs. This also
 * handles the registration of sort and argsort methods for dtypes
 * from ArrayMethod specs.
 */
NPY_NO_EXPORT int
PyUFunc_AddLoopsFromSpecs(PyUFunc_LoopSlot *slots)
{
    if (npy_cache_import_runtime(
            "numpy", "sort", &npy_runtime_imports.sort) < 0) {
        return -1;
    }
    if (npy_cache_import_runtime(
            "numpy", "argsort", &npy_runtime_imports.argsort) < 0) {
        return -1;
    }

    PyUFunc_LoopSlot *slot;
    for (slot = slots; slot->name != NULL; slot++) {
        PyObject *ufunc = npy_import("numpy", slot->name);
        if (ufunc == NULL) {
            return -1;
        }

        if (ufunc == npy_runtime_imports.sort) {
            Py_DECREF(ufunc);

            PyArray_DTypeMeta *dtype = slot->spec->dtypes[0];
            PyBoundArrayMethodObject *sort_meth = PyArrayMethod_FromSpec_int(slot->spec, 0);
            if (sort_meth == NULL) {
                return -1;
            }

            NPY_DT_SLOTS(dtype)->sort_meth = sort_meth->method;
            Py_INCREF(sort_meth->method);
            Py_DECREF(sort_meth);
        }
        else if (ufunc == npy_runtime_imports.argsort) {
            Py_DECREF(ufunc);

            PyArray_DTypeMeta *dtype = slot->spec->dtypes[0];