@@ -248,6 +248,27 @@ string_discover_descriptor_from_pyobject(PyTypeObject *NPY_UNUSED(cls),
248
248
return ret ;
249
249
}
250
250
251
+ #ifndef PYPY_VERSION
252
+ #define NA_IS_COMPARE (a , b ) a == b
253
+ #else
254
+ static PyObject * py_id = NULL ;
255
+
256
+ static int
257
+ eq_compare_pypy_na (PyObject * a , PyObject * b ) {
258
+ PyObject * a_id = PyObject_CallOneArg (py_id , a );
259
+ if (a_id == NULL ) {
260
+ return -1 ;
261
+ }
262
+ PyObject * b_id = PyObject_CallOneArg (py_id , b );
263
+ if (b_id == NULL ) {
264
+ return -1 ;
265
+ }
266
+ return PyObject_RichCompareBool (a_id , b_id , Py_EQ );
267
+ }
268
+
269
+ #define NA_IS_COMPARE (a , b ) eq_compare_pypy_na(a, b)
270
+ #endif
271
+
251
272
// Take a python object `obj` and insert it into the array of dtype `descr` at
252
273
// the position given by dataptr.
253
274
int
@@ -260,40 +281,47 @@ stringdtype_setitem(StringDTypeObject *descr, PyObject *obj, char **dataptr)
260
281
// borrow reference
261
282
PyObject * na_object = descr -> na_object ;
262
283
263
- // setting NA *must* check pointer equality since NA types might not
264
- // allow equality
265
- if (na_object != NULL && obj == na_object ) {
266
- if (NpyString_pack_null (allocator , sdata ) < 0 ) {
267
- PyErr_SetString (PyExc_MemoryError ,
268
- "Failed to pack null string during StringDType "
269
- "setitem" );
284
+ if (na_object != NULL ) {
285
+ // specifically for pandas.NA, we *have* to use "is" comparison
286
+ // because there's no other way to identify NA, since "NA == anything"
287
+ // returns NA.
288
+ int is_cmp = NA_IS_COMPARE (obj , na_object );
289
+ if (is_cmp == -1 ) {
270
290
goto fail ;
271
291
}
292
+ if (is_cmp ) {
293
+ if (NpyString_pack_null (allocator , sdata ) < 0 ) {
294
+ PyErr_SetString (PyExc_MemoryError ,
295
+ "Failed to pack null string during StringDType "
296
+ "setitem" );
297
+ goto fail ;
298
+ }
299
+ goto success ;
300
+ }
272
301
}
273
- else {
274
- PyObject * val_obj = get_value (obj , descr -> coerce );
302
+ PyObject * val_obj = get_value (obj , descr -> coerce );
275
303
276
- if (val_obj == NULL ) {
277
- goto fail ;
278
- }
304
+ if (val_obj == NULL ) {
305
+ goto fail ;
306
+ }
279
307
280
- Py_ssize_t length = 0 ;
281
- const char * val = PyUnicode_AsUTF8AndSize (val_obj , & length );
282
- if (val == NULL ) {
283
- Py_DECREF (val_obj );
284
- goto fail ;
285
- }
308
+ Py_ssize_t length = 0 ;
309
+ const char * val = PyUnicode_AsUTF8AndSize (val_obj , & length );
310
+ if (val == NULL ) {
311
+ Py_DECREF (val_obj );
312
+ goto fail ;
313
+ }
286
314
287
- if (NpyString_pack (allocator , sdata , val , length ) < 0 ) {
288
- PyErr_SetString (PyExc_MemoryError ,
289
- "Failed to pack string during StringDType "
290
- "setitem" );
291
- Py_DECREF (val_obj );
292
- goto fail ;
293
- }
315
+ if (NpyString_pack (allocator , sdata , val , length ) < 0 ) {
316
+ PyErr_SetString (PyExc_MemoryError ,
317
+ "Failed to pack string during StringDType "
318
+ "setitem" );
294
319
Py_DECREF (val_obj );
320
+ goto fail ;
295
321
}
322
+ Py_DECREF (val_obj );
296
323
324
+ success :
297
325
NpyString_release_allocator (descr );
298
326
299
327
return 0 ;
@@ -853,6 +881,13 @@ init_string_dtype(void)
853
881
.casts = StringDType_casts ,
854
882
};
855
883
884
+ #ifdef PYPY_VERSION
885
+ py_id = PyDict_GetItemString (PyEval_GetBuiltins (), "id" );
886
+ if (py_id == NULL ) {
887
+ return -1 ;
888
+ }
889
+ #endif
890
+
856
891
/* Loaded dynamically, so may need to be set here: */
857
892
((PyObject * )& StringDType )-> ob_type = & PyArrayDTypeMeta_Type ;
858
893
((PyTypeObject * )& StringDType )-> tp_base = & PyArrayDescr_Type ;
0 commit comments