@@ -3385,63 +3385,86 @@ dtype_from_element(PyObject *Py_UNUSED(m), PyObject *arg)
33853385 return (PyObject * )PyArray_DescrFromType (NPY_OBJECT );
33863386}
33873387
3388+ static char * isna_element_kwarg_names [] = {
3389+ "element" ,
3390+ "include_none" ,
3391+ NULL
3392+ };
3393+
33883394static PyObject *
3389- isna_element (PyObject * Py_UNUSED ( m ) , PyObject * arg )
3395+ isna_element (PyObject * m , PyObject * args , PyObject * kwargs )
33903396{
3397+ PyObject * element ;
3398+ int include_none = 1 ;
3399+ if (!PyArg_ParseTupleAndKeywords (args , kwargs ,
3400+ "O|p:isna_element" , isna_element_kwarg_names ,
3401+ & element ,
3402+ & include_none )) {
3403+ return NULL ;
3404+ }
3405+
33913406 // None
3392- if (arg == Py_None ) {
3407+ if (include_none && element == Py_None ) {
33933408 Py_RETURN_TRUE ;
33943409 }
33953410
33963411 // NaN
3397- if (PyFloat_Check (arg )) {
3398- return PyBool_FromLong (isnan (PyFloat_AS_DOUBLE (arg )));
3412+ if (PyFloat_Check (element )) {
3413+ return PyBool_FromLong (isnan (PyFloat_AS_DOUBLE (element )));
33993414 }
3400- if (PyArray_IsScalar (arg , Half )) {
3401- return PyBool_FromLong (npy_half_isnan (PyArrayScalar_VAL (arg , Half )));
3415+ if (PyArray_IsScalar (element , Half )) {
3416+ return PyBool_FromLong (npy_half_isnan (PyArrayScalar_VAL (element , Half )));
34023417 }
3403- if (PyArray_IsScalar (arg , Float32 )) {
3404- return PyBool_FromLong (isnan (PyArrayScalar_VAL (arg , Float32 )));
3418+ if (PyArray_IsScalar (element , Float32 )) {
3419+ return PyBool_FromLong (isnan (PyArrayScalar_VAL (element , Float32 )));
34053420 }
3406- if (PyArray_IsScalar (arg , Float64 )) {
3407- return PyBool_FromLong (isnan (PyArrayScalar_VAL (arg , Float64 )));
3421+ if (PyArray_IsScalar (element , Float64 )) {
3422+ return PyBool_FromLong (isnan (PyArrayScalar_VAL (element , Float64 )));
34083423 }
34093424 # ifdef PyFloat128ArrType_Type
3410- if (PyArray_IsScalar (arg , Float128 )) {
3411- return PyBool_FromLong (isnan (PyArrayScalar_VAL (arg , Float128 )));
3425+ if (PyArray_IsScalar (element , Float128 )) {
3426+ return PyBool_FromLong (isnan (PyArrayScalar_VAL (element , Float128 )));
34123427 }
34133428 # endif
34143429
34153430 // Complex NaN
3416- if (PyComplex_Check (arg )) {
3417- Py_complex val = ((PyComplexObject * )arg )-> cval ;
3431+ if (PyComplex_Check (element )) {
3432+ Py_complex val = ((PyComplexObject * )element )-> cval ;
34183433 return PyBool_FromLong (isnan (val .real ) || isnan (val .imag ));
34193434 }
3420- if (PyArray_IsScalar (arg , Complex64 )) {
3421- npy_cfloat val = PyArrayScalar_VAL (arg , Complex64 );
3435+ if (PyArray_IsScalar (element , Complex64 )) {
3436+ npy_cfloat val = PyArrayScalar_VAL (element , Complex64 );
34223437 return PyBool_FromLong (isnan (val .real ) || isnan (val .imag ));
34233438 }
3424- if (PyArray_IsScalar (arg , Complex128 )) {
3425- npy_cdouble val = PyArrayScalar_VAL (arg , Complex128 );
3439+ if (PyArray_IsScalar (element , Complex128 )) {
3440+ npy_cdouble val = PyArrayScalar_VAL (element , Complex128 );
34263441 return PyBool_FromLong (isnan (val .real ) || isnan (val .imag ));
34273442 }
34283443 # ifdef PyComplex256ArrType_Type
3429- if (PyArray_IsScalar (arg , Complex256 )) {
3430- npy_clongdouble val = PyArrayScalar_VAL (arg , Complex256 );
3444+ if (PyArray_IsScalar (element , Complex256 )) {
3445+ npy_clongdouble val = PyArrayScalar_VAL (element , Complex256 );
34313446 return PyBool_FromLong (isnan (val .real ) || isnan (val .imag ));
34323447 }
34333448 # endif
34343449
34353450 // NaT - Datetime
3436- if (PyArray_IsScalar (arg , Datetime )) {
3437- return PyBool_FromLong (PyArrayScalar_VAL (arg , Datetime ) == NPY_DATETIME_NAT );
3451+ if (PyArray_IsScalar (element , Datetime )) {
3452+ return PyBool_FromLong (PyArrayScalar_VAL (element , Datetime ) == NPY_DATETIME_NAT );
34383453 }
3439-
34403454 // NaT - Timedelta
3441- if (PyArray_IsScalar (arg , Timedelta )) {
3442- return PyBool_FromLong (PyArrayScalar_VAL (arg , Timedelta ) == NPY_DATETIME_NAT );
3455+ if (PyArray_IsScalar (element , Timedelta )) {
3456+ return PyBool_FromLong (PyArrayScalar_VAL (element , Timedelta ) == NPY_DATETIME_NAT );
3457+ }
3458+ // Try to identify Pandas Timestamp NATs
3459+ if (PyObject_HasAttrString (element , "to_numpy" )) {
3460+ PyObject * to_numpy = PyObject_GetAttrString (element , "to_numpy" );
3461+ if (!PyCallable_Check (to_numpy )) {
3462+ Py_RETURN_FALSE ;
3463+ }
3464+ PyObject * post = PyObject_CallFunction (to_numpy , NULL );
3465+ if (post == NULL ) return NULL ;
3466+ return PyBool_FromLong (PyArrayScalar_VAL (post , Datetime ) == NPY_DATETIME_NAT );
34433467 }
3444-
34453468 Py_RETURN_FALSE ;
34463469}
34473470
@@ -4042,7 +4065,10 @@ static PyMethodDef arraykit_methods[] = {
40424065 METH_VARARGS | METH_KEYWORDS ,
40434066 NULL },
40444067 {"count_iteration" , count_iteration , METH_O , NULL },
4045- {"isna_element" , isna_element , METH_O , NULL },
4068+ {"isna_element" ,
4069+ (PyCFunction )isna_element ,
4070+ METH_VARARGS | METH_KEYWORDS ,
4071+ NULL },
40464072 {"dtype_from_element" , dtype_from_element , METH_O , NULL },
40474073 {"get_new_indexers_and_screen" ,
40484074 (PyCFunction )get_new_indexers_and_screen ,
0 commit comments