From 3692539c5fdb38aaee151a96a44c86f88504e17e Mon Sep 17 00:00:00 2001 From: Aryan Srivastava Date: Thu, 21 May 2026 19:15:23 +0530 Subject: [PATCH 1/3] Fix to_numpy object null handling --- python/cudf/cudf/core/frame.py | 10 ++++++ .../tests/dataframe/methods/test_to_cupy.py | 34 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/python/cudf/cudf/core/frame.py b/python/cudf/cudf/core/frame.py index c248c4f7562c..022523153fcd 100644 --- a/python/cudf/cudf/core/frame.py +++ b/python/cudf/cudf/core/frame.py @@ -653,6 +653,12 @@ def _to_array( # Internal function to implement to_cupy and to_numpy, which are nearly # identical except for the attribute they access to generate values. + def is_numpy_object_dtype(dtype: Dtype | None) -> bool: + try: + return np.dtype(dtype) == np.dtype("O") + except TypeError: + return False + def to_array( col: ColumnBase, to_dtype: Dtype | None ) -> cupy.ndarray | np.ndarray: @@ -704,6 +710,10 @@ def to_array( col.has_nulls() and dtype is not None and is_string_dtype(dtype) + and ( + not is_numpy_object_dtype(dtype) + or na_value is not no_default + ) ): casted_array[col.isnull().to_numpy()] = ( cudf.NA if na_value is no_default else na_value diff --git a/python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py b/python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py index 38ec5b9dcf4f..ec72c553346c 100644 --- a/python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py +++ b/python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py @@ -195,3 +195,37 @@ def test_to_numpy_object_dtype_boxes_values(constructor, data, dtype): # Ensure boxed values are real Python scalars, not strings. for value in result.flat: assert not isinstance(value, str) + + +@pytest.mark.parametrize("constructor", ["DataFrame", "Series"]) +@pytest.mark.parametrize( + "data", + [ + [], + [None], + [None, None], + ["a", "b", None], + ], +) +def test_to_numpy_object_dtype_preserves_none_string_nulls( + constructor, data +): + values = pd.Series(data, dtype=object, name="x") + if constructor == "DataFrame": + pd_obj = pd.DataFrame({"x": values}) + else: + pd_obj = values + cudf_obj = getattr(cudf, constructor)(pd_obj) + + expected = pd_obj.to_numpy(dtype=object) + result = cudf_obj.to_numpy(dtype=object) + null_mask = pd.isna(expected) + + assert result.dtype == np.dtype("O") + np.testing.assert_array_equal(result, expected) + assert all(value is None for value in result[null_mask].flat) + + expected = pd_obj.to_numpy(dtype=object, na_value="missing") + result = cudf_obj.to_numpy(dtype=object, na_value="missing") + np.testing.assert_array_equal(result, expected) + assert all(value == "missing" for value in result[null_mask].flat) From 78c7264a8260840df6f10b065cc565c4133d3e96 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 23:31:13 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto code formatting --- python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py b/python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py index ec72c553346c..c66ba620413b 100644 --- a/python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py +++ b/python/cudf/cudf/tests/dataframe/methods/test_to_cupy.py @@ -207,9 +207,7 @@ def test_to_numpy_object_dtype_boxes_values(constructor, data, dtype): ["a", "b", None], ], ) -def test_to_numpy_object_dtype_preserves_none_string_nulls( - constructor, data -): +def test_to_numpy_object_dtype_preserves_none_string_nulls(constructor, data): values = pd.Series(data, dtype=object, name="x") if constructor == "DataFrame": pd_obj = pd.DataFrame({"x": values}) From af970887edd68a416e170ef1262781a3e2bcbfad Mon Sep 17 00:00:00 2001 From: Aryan Srivastava Date: Mon, 1 Jun 2026 23:06:42 +0530 Subject: [PATCH 3/3] Remove redundant object null check --- python/cudf/cudf/core/frame.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/python/cudf/cudf/core/frame.py b/python/cudf/cudf/core/frame.py index fe85b86fceb5..ba2b4b436f02 100644 --- a/python/cudf/cudf/core/frame.py +++ b/python/cudf/cudf/core/frame.py @@ -684,10 +684,7 @@ def to_array( col.has_nulls() and dtype is not None and is_string_dtype(dtype) - and ( - not is_numpy_object_dtype(dtype) - or na_value is not no_default - ) + and not is_numpy_object_dtype(dtype) ): casted_array[col.isnull().to_numpy()] = ( cudf.NA if na_value is no_default else na_value