From bd811e2c80ba144eef4115ff807e3fd29c238e31 Mon Sep 17 00:00:00 2001 From: RapSku Date: Mon, 19 Sep 2022 11:59:50 +0200 Subject: [PATCH 01/10] BUG: Fixed repr type error when column in np.record --- doc/source/whatsnew/v1.6.0.rst | 2 +- pandas/core/dtypes/missing.py | 2 +- pandas/tests/frame/methods/test_to_records.py | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.6.0.rst b/doc/source/whatsnew/v1.6.0.rst index 405b8cc0a5ded..f3ee2d25f7ef5 100644 --- a/doc/source/whatsnew/v1.6.0.rst +++ b/doc/source/whatsnew/v1.6.0.rst @@ -150,7 +150,7 @@ Conversion ^^^^^^^^^^ - Bug in constructing :class:`Series` with ``int64`` dtype from a string list raising instead of casting (:issue:`44923`) - Bug in :meth:`DataFrame.eval` incorrectly raising an ``AttributeError`` when there are negative values in function call (:issue:`46471`) -- +- Bug in :meth:`DataFrame.__repr__` incorrectly raising a ``TypeError`` when the dtype of a column is ``np.record`` (:issue:`48526`) Strings ^^^^^^^ diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index cfad439e51ac7..f48a31ce1d4a5 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -292,7 +292,7 @@ def _isna_array(values: ArrayLike, inf_as_na: bool = False): # "Union[ndarray[Any, Any], ExtensionArraySupportsAnyAll]", variable has # type "ndarray[Any, dtype[bool_]]") result = values.isna() # type: ignore[assignment] - elif is_string_or_object_np_dtype(values.dtype): + elif is_string_or_object_np_dtype(values.dtype) or isinstance(values, np.recarray): result = _isna_string_dtype(values, inf_as_na=inf_as_na) elif needs_i8_conversion(dtype): # this is the NaT pattern diff --git a/pandas/tests/frame/methods/test_to_records.py b/pandas/tests/frame/methods/test_to_records.py index 32cccddc9d515..b7382ee286028 100644 --- a/pandas/tests/frame/methods/test_to_records.py +++ b/pandas/tests/frame/methods/test_to_records.py @@ -508,3 +508,11 @@ def test_to_records_datetimeindex_with_tz(self, tz): # both converted to UTC, so they are equal tm.assert_numpy_array_equal(result, expected) + + def test_to_records_no_typeerror_in_repr(self): + # GH 48526 + df = DataFrame([["a", "b"], ["c", "d"], ["e", "f"]], columns=["left", "right"]) + df["record"] = df[["left", "right"]].to_records() + + with tm.assert_produces_warning(False): + print(df) From a454c0f5d1935b2203a000fdbf0e0e87339e0e89 Mon Sep 17 00:00:00 2001 From: RapSku Date: Tue, 20 Sep 2022 10:50:11 +0200 Subject: [PATCH 02/10] Reallocated the test to proposed destination and test the repr of the frame --- pandas/tests/frame/methods/test_to_records.py | 8 -------- pandas/tests/frame/test_repr_info.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/pandas/tests/frame/methods/test_to_records.py b/pandas/tests/frame/methods/test_to_records.py index b7382ee286028..32cccddc9d515 100644 --- a/pandas/tests/frame/methods/test_to_records.py +++ b/pandas/tests/frame/methods/test_to_records.py @@ -508,11 +508,3 @@ def test_to_records_datetimeindex_with_tz(self, tz): # both converted to UTC, so they are equal tm.assert_numpy_array_equal(result, expected) - - def test_to_records_no_typeerror_in_repr(self): - # GH 48526 - df = DataFrame([["a", "b"], ["c", "d"], ["e", "f"]], columns=["left", "right"]) - df["record"] = df[["left", "right"]].to_records() - - with tm.assert_produces_warning(False): - print(df) diff --git a/pandas/tests/frame/test_repr_info.py b/pandas/tests/frame/test_repr_info.py index 86c8e36cb7bd4..121d0043fccd3 100644 --- a/pandas/tests/frame/test_repr_info.py +++ b/pandas/tests/frame/test_repr_info.py @@ -363,3 +363,14 @@ def test_datetime64tz_slice_non_truncate(self): df = df.iloc[:, :5] result = repr(df) assert result == expected + + def test_to_records_no_typeerror_in_repr(self): + # GH 48526 + df = DataFrame([["a", "b"], ["c", "d"], ["e", "f"]], columns=["left", "right"]) + df["record"] = df[["left", "right"]].to_records() + expected = """ left right record +0 a b [0, a, b] +1 c d [1, c, d] +2 e f [2, e, f]""" + result = repr(df) + assert result == expected From dd837ced107d787b5202e4386ba9076ebb02835d Mon Sep 17 00:00:00 2001 From: RaphSku Date: Fri, 10 Mar 2023 13:57:02 +0000 Subject: [PATCH 03/10] Assert has gone missing due to merge conflict --- pandas/tests/frame/test_repr_info.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/frame/test_repr_info.py b/pandas/tests/frame/test_repr_info.py index 5066152d26de5..9a1e2a0de186b 100644 --- a/pandas/tests/frame/test_repr_info.py +++ b/pandas/tests/frame/test_repr_info.py @@ -370,7 +370,8 @@ def test_to_records_no_typeerror_in_repr(self): 1 c d [1, c, d] 2 e f [2, e, f]""" result = repr(df) - + assert result == expected + def test_masked_ea_with_formatter(self): # GH#39336 df = DataFrame( From 3a15ab1202961d4570b5e71d26d353a1379281f1 Mon Sep 17 00:00:00 2001 From: RaphSku Date: Sat, 11 Mar 2023 12:41:30 +0000 Subject: [PATCH 04/10] Added new function that handles np.recarrays in _isna_array --- pandas/core/dtypes/missing.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index 2579a2734a726..eb47109ee7c6b 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -290,7 +290,10 @@ def _isna_array(values: ArrayLike, inf_as_na: bool = False): # "Union[ndarray[Any, Any], ExtensionArraySupportsAnyAll]", variable has # type "ndarray[Any, dtype[bool_]]") result = values.isna() # type: ignore[assignment] - elif is_string_or_object_np_dtype(values.dtype) or isinstance(values, np.recarray): + elif isinstance(values, np.recarray): + # GH 48526 + result = _isna_recarray_dtype(values, inf_as_na=inf_as_na) + elif is_string_or_object_np_dtype(values.dtype): result = _isna_string_dtype(values, inf_as_na=inf_as_na) elif needs_i8_conversion(dtype): # this is the NaT pattern @@ -321,6 +324,14 @@ def _isna_string_dtype(values: np.ndarray, inf_as_na: bool) -> npt.NDArray[np.bo return result +def _isna_recarray_dtype(values: np.recarray, inf_as_na: bool) -> npt.NDArray[np.bool_]: + result = np.zeros(values.shape, dtype=bool) + for i, record in enumerate(values): + result[i] = libmissing.isnaobj(np.array(record), inf_as_na=inf_as_na) + + return result + + @overload def notna(obj: Scalar) -> bool: ... From 961ebf0ace9fc3aa28c54e586c1d31f4a8517e29 Mon Sep 17 00:00:00 2001 From: RaphSku Date: Tue, 14 Mar 2023 21:48:15 +0000 Subject: [PATCH 05/10] Addes 2 more tests + refined _isna_recarray_dtype + formatting fixed --- pandas/core/dtypes/missing.py | 24 +++++++++++++++++++++++- pandas/tests/frame/test_repr_info.py | 26 ++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index eb47109ee7c6b..479332cf51319 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -327,7 +327,29 @@ def _isna_string_dtype(values: np.ndarray, inf_as_na: bool) -> npt.NDArray[np.bo def _isna_recarray_dtype(values: np.recarray, inf_as_na: bool) -> npt.NDArray[np.bool_]: result = np.zeros(values.shape, dtype=bool) for i, record in enumerate(values): - result[i] = libmissing.isnaobj(np.array(record), inf_as_na=inf_as_na) + does_record_contain_nan = np.zeros(len(record), dtype=bool) + if inf_as_na: + does_record_contain_inf = np.zeros(len(record), dtype=bool) + for j, element in enumerate(record): + if element != element: + does_record_contain_nan[j] = True + else: + does_record_contain_nan[j] = False + if inf_as_na: + try: + if np.isinf(element): + does_record_contain_inf[j] = True + else: + does_record_contain_inf[j] = False + except TypeError: + does_record_contain_inf[j] = False + + if inf_as_na: + result[i] = np.any( + np.logical_or(does_record_contain_nan, does_record_contain_inf) + ) + else: + result[i] = np.any(does_record_contain_nan) return result diff --git a/pandas/tests/frame/test_repr_info.py b/pandas/tests/frame/test_repr_info.py index 9a1e2a0de186b..42296ff556b2a 100644 --- a/pandas/tests/frame/test_repr_info.py +++ b/pandas/tests/frame/test_repr_info.py @@ -372,6 +372,32 @@ def test_to_records_no_typeerror_in_repr(self): result = repr(df) assert result == expected + def test_to_records_with_na_record_value(self): + # GH 48526 + df = DataFrame( + [["a", np.nan], ["c", "d"], ["e", "f"]], columns=["left", "right"] + ) + df["record"] = df[["left", "right"]].to_records() + expected = """ left right record +0 a NaN [0, a, nan] +1 c d [1, c, d] +2 e f [2, e, f]""" + result = repr(df) + assert result == expected + + def test_to_records_with_na_record(self): + # GH 48526 + df = DataFrame( + [["a", "b"], [np.nan, np.nan], ["e", "f"]], columns=[np.nan, "right"] + ) + df["record"] = df[[np.nan, "right"]].to_records() + expected = """ NaN right record +0 a b [0, a, b] +1 NaN NaN [1, nan, nan] +2 e f [2, e, f]""" + result = repr(df) + assert result == expected + def test_masked_ea_with_formatter(self): # GH#39336 df = DataFrame( From 4fb9443647bd81588dc6fd09ea61fa8a1cc77396 Mon Sep 17 00:00:00 2001 From: RaphSku Date: Fri, 14 Apr 2023 20:47:43 +0000 Subject: [PATCH 06/10] Reworked isna_recarray_dtype method + Added test for inf value --- pandas/core/dtypes/missing.py | 40 ++++++++++++++-------------- pandas/tests/frame/test_repr_info.py | 13 +++++++++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index 479332cf51319..441f8cb72989d 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -7,6 +7,7 @@ from functools import partial from typing import ( TYPE_CHECKING, + Any, overload, ) @@ -324,32 +325,31 @@ def _isna_string_dtype(values: np.ndarray, inf_as_na: bool) -> npt.NDArray[np.bo return result +def _check_record_value(element: Any, inf_as_na: bool) -> bool: + is_element_nan = False + if element != element: + is_element_nan = True + + is_element_inf = False + if inf_as_na: + try: + if np.isinf(element): + is_element_inf = True + except TypeError: + is_element_inf = False + + return np.any(np.logical_or(is_element_nan, is_element_inf)) + + def _isna_recarray_dtype(values: np.recarray, inf_as_na: bool) -> npt.NDArray[np.bool_]: result = np.zeros(values.shape, dtype=bool) for i, record in enumerate(values): does_record_contain_nan = np.zeros(len(record), dtype=bool) - if inf_as_na: - does_record_contain_inf = np.zeros(len(record), dtype=bool) for j, element in enumerate(record): - if element != element: - does_record_contain_nan[j] = True - else: - does_record_contain_nan[j] = False - if inf_as_na: - try: - if np.isinf(element): - does_record_contain_inf[j] = True - else: - does_record_contain_inf[j] = False - except TypeError: - does_record_contain_inf[j] = False - - if inf_as_na: - result[i] = np.any( - np.logical_or(does_record_contain_nan, does_record_contain_inf) + does_record_contain_nan[j] = _check_record_value( + element, inf_as_na=inf_as_na ) - else: - result[i] = np.any(does_record_contain_nan) + result[i] = np.any(does_record_contain_nan) return result diff --git a/pandas/tests/frame/test_repr_info.py b/pandas/tests/frame/test_repr_info.py index 42296ff556b2a..6b22207877b72 100644 --- a/pandas/tests/frame/test_repr_info.py +++ b/pandas/tests/frame/test_repr_info.py @@ -398,6 +398,19 @@ def test_to_records_with_na_record(self): result = repr(df) assert result == expected + def test_to_records_with_inf_record(self): + # GH 48526 + df = DataFrame( + [[np.inf, "b"], [np.nan, np.nan], ["e", "f"]], columns=[np.nan, np.inf] + ) + df["record"] = df[[np.nan, np.inf]].to_records() + expected = """ NaN inf record +0 inf b [0, inf, b] +1 NaN NaN [1, nan, nan] +2 e f [2, e, f]""" + result = repr(df) + assert result == expected + def test_masked_ea_with_formatter(self): # GH#39336 df = DataFrame( From 923d29d29aad33fb2abb3429c0c8d06e77fe298d Mon Sep 17 00:00:00 2001 From: RaphSku Date: Sat, 15 Apr 2023 08:55:56 +0000 Subject: [PATCH 07/10] Pre-commit fix --- pandas/tests/frame/test_repr_info.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pandas/tests/frame/test_repr_info.py b/pandas/tests/frame/test_repr_info.py index 6b22207877b72..37489335b6ab6 100644 --- a/pandas/tests/frame/test_repr_info.py +++ b/pandas/tests/frame/test_repr_info.py @@ -18,6 +18,7 @@ Timestamp, date_range, option_context, + options, period_range, ) import pandas._testing as tm @@ -398,8 +399,23 @@ def test_to_records_with_na_record(self): result = repr(df) assert result == expected + def test_to_records_with_inf_as_na_record(self): + # GH 48526 + options.mode.use_inf_as_na = True + df = DataFrame( + [[np.inf, "b"], [np.nan, np.nan], ["e", "f"]], columns=[np.nan, np.inf] + ) + df["record"] = df[[np.nan, np.inf]].to_records() + expected = """ NaN inf record +0 NaN b [0, inf, b] +1 NaN NaN [1, nan, nan] +2 e f [2, e, f]""" + result = repr(df) + assert result == expected + def test_to_records_with_inf_record(self): # GH 48526 + options.mode.use_inf_as_na = False df = DataFrame( [[np.inf, "b"], [np.nan, np.nan], ["e", "f"]], columns=[np.nan, np.inf] ) From fdcdb57ab9207bb998bf7faffb864ca94c9855dd Mon Sep 17 00:00:00 2001 From: RaphSku Date: Sat, 15 Apr 2023 10:06:03 +0000 Subject: [PATCH 08/10] Fixing typing --- pandas/core/dtypes/missing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index 441f8cb72989d..70ef9f11cc2c0 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -325,7 +325,7 @@ def _isna_string_dtype(values: np.ndarray, inf_as_na: bool) -> npt.NDArray[np.bo return result -def _check_record_value(element: Any, inf_as_na: bool) -> bool: +def _check_record_value(element: Any, inf_as_na: bool) -> np.bool_: is_element_nan = False if element != element: is_element_nan = True From 396172c81e58b77d3f70d1b85d04b61f82f81e47 Mon Sep 17 00:00:00 2001 From: RaphSku Date: Thu, 20 Apr 2023 20:08:47 +0000 Subject: [PATCH 09/10] Fixed formatting --- doc/source/whatsnew/v2.0.0.rst | 1 - doc/source/whatsnew/v2.1.0.rst | 1 + pandas/core/dtypes/missing.py | 31 +++++++++++++--------------- pandas/tests/frame/test_repr_info.py | 29 +++++++++++++------------- 4 files changed, 29 insertions(+), 33 deletions(-) diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 6ff73fb6a80f3..3ddc8b8919228 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -1229,7 +1229,6 @@ Conversion - Bug in :meth:`Series.to_numpy` converting to NumPy array before applying ``na_value`` (:issue:`48951`) - Bug in :meth:`DataFrame.astype` not copying data when converting to pyarrow dtype (:issue:`50984`) - Bug in :func:`to_datetime` was not respecting ``exact`` argument when ``format`` was an ISO8601 format (:issue:`12649`) -- Bug in :meth:`DataFrame.__repr__` incorrectly raising a ``TypeError`` when the dtype of a column is ``np.record`` (:issue:`48526`) - Bug in :meth:`TimedeltaArray.astype` raising ``TypeError`` when converting to a pyarrow duration type (:issue:`49795`) - Bug in :meth:`DataFrame.eval` and :meth:`DataFrame.query` raising for extension array dtypes (:issue:`29618`, :issue:`50261`, :issue:`31913`) - Bug in :meth:`Series` not copying data when created from :class:`Index` and ``dtype`` is equal to ``dtype`` from :class:`Index` (:issue:`52008`) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 22a2931519ffd..4180cdb245a82 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -316,6 +316,7 @@ Conversion ^^^^^^^^^^ - Bug in :func:`DataFrame.style.to_latex` and :func:`DataFrame.style.to_html` if the DataFrame contains integers with more digits than can be represented by floating point double precision (:issue:`52272`) - Bug in :meth:`ArrowDtype.numpy_dtype` returning nanosecond units for non-nanosecond ``pyarrow.timestamp`` and ``pyarrow.duration`` types (:issue:`51800`) +- Bug in :meth:`DataFrame.__repr__` incorrectly raising a ``TypeError`` when the dtype of a column is ``np.record`` (:issue:`48526`) - Bug in :meth:`DataFrame.info` raising ``ValueError`` when ``use_numba`` is set (:issue:`51922`) - diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index 11dd4bd333b02..264fc09a58a6e 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -7,7 +7,6 @@ from functools import partial from typing import ( TYPE_CHECKING, - Any, overload, ) @@ -318,31 +317,29 @@ def _isna_string_dtype(values: np.ndarray, inf_as_na: bool) -> npt.NDArray[np.bo return result -def _check_record_value(element: Any, inf_as_na: bool) -> np.bool_: - is_element_nan = False - if element != element: - is_element_nan = True - - is_element_inf = False - if inf_as_na: +def _has_record_inf_value(record: np.record) -> np.bool_: + is_inf_in_record = np.zeros(len(record), dtype=bool) + for i, value in enumerate(record): + is_element_inf = False try: - if np.isinf(element): - is_element_inf = True + is_element_inf = np.isinf(value) except TypeError: is_element_inf = False + is_inf_in_record[i] = is_element_inf - return np.any(np.logical_or(is_element_nan, is_element_inf)) + return np.any(is_inf_in_record) def _isna_recarray_dtype(values: np.recarray, inf_as_na: bool) -> npt.NDArray[np.bool_]: result = np.zeros(values.shape, dtype=bool) for i, record in enumerate(values): - does_record_contain_nan = np.zeros(len(record), dtype=bool) - for j, element in enumerate(record): - does_record_contain_nan[j] = _check_record_value( - element, inf_as_na=inf_as_na - ) - result[i] = np.any(does_record_contain_nan) + does_record_contain_nan = isna_all(np.array(record.tolist())) + does_record_contain_inf = False + if inf_as_na: + does_record_contain_inf = _has_record_inf_value(record) + result[i] = np.any( + np.logical_or(does_record_contain_nan, does_record_contain_inf) + ) return result diff --git a/pandas/tests/frame/test_repr_info.py b/pandas/tests/frame/test_repr_info.py index 37489335b6ab6..b42af8cdfcd8c 100644 --- a/pandas/tests/frame/test_repr_info.py +++ b/pandas/tests/frame/test_repr_info.py @@ -18,7 +18,6 @@ Timestamp, date_range, option_context, - options, period_range, ) import pandas._testing as tm @@ -401,30 +400,30 @@ def test_to_records_with_na_record(self): def test_to_records_with_inf_as_na_record(self): # GH 48526 - options.mode.use_inf_as_na = True - df = DataFrame( - [[np.inf, "b"], [np.nan, np.nan], ["e", "f"]], columns=[np.nan, np.inf] - ) - df["record"] = df[[np.nan, np.inf]].to_records() - expected = """ NaN inf record + with option_context("use_inf_as_na", True): + df = DataFrame( + [[np.inf, "b"], [np.nan, np.nan], ["e", "f"]], columns=[np.nan, np.inf] + ) + df["record"] = df[[np.nan, np.inf]].to_records() + expected = """ NaN inf record 0 NaN b [0, inf, b] 1 NaN NaN [1, nan, nan] 2 e f [2, e, f]""" - result = repr(df) + result = repr(df) assert result == expected def test_to_records_with_inf_record(self): # GH 48526 - options.mode.use_inf_as_na = False - df = DataFrame( - [[np.inf, "b"], [np.nan, np.nan], ["e", "f"]], columns=[np.nan, np.inf] - ) - df["record"] = df[[np.nan, np.inf]].to_records() - expected = """ NaN inf record + with option_context("use_inf_as_na", False): + df = DataFrame( + [[np.inf, "b"], [np.nan, np.nan], ["e", "f"]], columns=[np.nan, np.inf] + ) + df["record"] = df[[np.nan, np.inf]].to_records() + expected = """ NaN inf record 0 inf b [0, inf, b] 1 NaN NaN [1, nan, nan] 2 e f [2, e, f]""" - result = repr(df) + result = repr(df) assert result == expected def test_masked_ea_with_formatter(self): From 145699f61679d30d3fd558ce08ed065b4a236713 Mon Sep 17 00:00:00 2001 From: RaphSku Date: Thu, 20 Apr 2023 21:13:54 +0000 Subject: [PATCH 10/10] Fixed pyright error --- pandas/core/dtypes/missing.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index 264fc09a58a6e..1b3b8aad6de51 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -317,9 +317,9 @@ def _isna_string_dtype(values: np.ndarray, inf_as_na: bool) -> npt.NDArray[np.bo return result -def _has_record_inf_value(record: np.record) -> np.bool_: - is_inf_in_record = np.zeros(len(record), dtype=bool) - for i, value in enumerate(record): +def _has_record_inf_value(record_as_array: np.ndarray) -> np.bool_: + is_inf_in_record = np.zeros(len(record_as_array), dtype=bool) + for i, value in enumerate(record_as_array): is_element_inf = False try: is_element_inf = np.isinf(value) @@ -333,10 +333,11 @@ def _has_record_inf_value(record: np.record) -> np.bool_: def _isna_recarray_dtype(values: np.recarray, inf_as_na: bool) -> npt.NDArray[np.bool_]: result = np.zeros(values.shape, dtype=bool) for i, record in enumerate(values): - does_record_contain_nan = isna_all(np.array(record.tolist())) + record_as_array = np.array(record.tolist()) + does_record_contain_nan = isna_all(record_as_array) does_record_contain_inf = False if inf_as_na: - does_record_contain_inf = _has_record_inf_value(record) + does_record_contain_inf = bool(_has_record_inf_value(record_as_array)) result[i] = np.any( np.logical_or(does_record_contain_nan, does_record_contain_inf) )