Skip to content

Commit 851639d

Browse files
String dtype: still return nullable NA-variant in object inference (maybe_converts_object) if requested (#59487)
* String dtype: maybe_converts_object give precedence to nullable dtype * update datetimelike input validation * update tests and remove xfails * explicitly test pd.array() behaviour (remove xfail) * fixup allow_2d * undo changes related to datetimelike input validation * fix test for str on current main --------- Co-authored-by: Matthew Roeschke <[email protected]>
1 parent 320d613 commit 851639d

File tree

7 files changed

+43
-20
lines changed

7 files changed

+43
-20
lines changed

pandas/_libs/lib.pyx

+4-4
Original file line numberDiff line numberDiff line change
@@ -2699,16 +2699,16 @@ def maybe_convert_objects(ndarray[object] objects,
26992699
seen.object_ = True
27002700

27012701
elif seen.str_:
2702-
if using_string_dtype() and is_string_array(objects, skipna=True):
2702+
if convert_to_nullable_dtype and is_string_array(objects, skipna=True):
27032703
from pandas.core.arrays.string_ import StringDtype
27042704

2705-
dtype = StringDtype(na_value=np.nan)
2705+
dtype = StringDtype()
27062706
return dtype.construct_array_type()._from_sequence(objects, dtype=dtype)
27072707

2708-
elif convert_to_nullable_dtype and is_string_array(objects, skipna=True):
2708+
elif using_string_dtype() and is_string_array(objects, skipna=True):
27092709
from pandas.core.arrays.string_ import StringDtype
27102710

2711-
dtype = StringDtype()
2711+
dtype = StringDtype(na_value=np.nan)
27122712
return dtype.construct_array_type()._from_sequence(objects, dtype=dtype)
27132713

27142714
seen.object_ = True

pandas/tests/arrays/string_/test_string_arrow.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,8 @@ def test_config(string_storage, using_infer_string):
3636
result = pd.array(["a", "b"])
3737
assert result.dtype.storage == string_storage
3838

39-
dtype = StringDtype(
40-
string_storage, na_value=np.nan if using_infer_string else pd.NA
41-
)
39+
# pd.array(..) by default always returns the NA-variant
40+
dtype = StringDtype(string_storage, na_value=pd.NA)
4241
expected = dtype.construct_array_type()._from_sequence(["a", "b"], dtype=dtype)
4342
tm.assert_equal(result, expected)
4443

pandas/tests/arrays/test_array.py

+32-2
Original file line numberDiff line numberDiff line change
@@ -215,21 +215,45 @@ def test_dt64_array(dtype_unit):
215215
.construct_array_type()
216216
._from_sequence(["a", None], dtype=pd.StringDtype()),
217217
),
218+
(
219+
["a", None],
220+
"str",
221+
pd.StringDtype(na_value=np.nan)
222+
.construct_array_type()
223+
._from_sequence(["a", None], dtype=pd.StringDtype(na_value=np.nan))
224+
if using_string_dtype()
225+
else NumpyExtensionArray(np.array(["a", "None"])),
226+
),
218227
(
219228
["a", None],
220229
pd.StringDtype(),
221230
pd.StringDtype()
222231
.construct_array_type()
223232
._from_sequence(["a", None], dtype=pd.StringDtype()),
224233
),
234+
(
235+
["a", None],
236+
pd.StringDtype(na_value=np.nan),
237+
pd.StringDtype(na_value=np.nan)
238+
.construct_array_type()
239+
._from_sequence(["a", None], dtype=pd.StringDtype(na_value=np.nan)),
240+
),
225241
(
226242
# numpy array with string dtype
227243
np.array(["a", "b"], dtype=str),
228-
None,
244+
pd.StringDtype(),
229245
pd.StringDtype()
230246
.construct_array_type()
231247
._from_sequence(["a", "b"], dtype=pd.StringDtype()),
232248
),
249+
(
250+
# numpy array with string dtype
251+
np.array(["a", "b"], dtype=str),
252+
pd.StringDtype(na_value=np.nan),
253+
pd.StringDtype(na_value=np.nan)
254+
.construct_array_type()
255+
._from_sequence(["a", "b"], dtype=pd.StringDtype(na_value=np.nan)),
256+
),
233257
# Boolean
234258
(
235259
[True, None],
@@ -287,7 +311,6 @@ def test_array_copy():
287311
assert tm.shares_memory(a, b)
288312

289313

290-
@pytest.mark.xfail(using_string_dtype(), reason="TODO(infer_string)", strict=False)
291314
@pytest.mark.parametrize(
292315
"data, expected",
293316
[
@@ -387,6 +410,13 @@ def test_array_copy():
387410
.construct_array_type()
388411
._from_sequence(["a", None], dtype=pd.StringDtype()),
389412
),
413+
(
414+
# numpy array with string dtype
415+
np.array(["a", "b"], dtype=str),
416+
pd.StringDtype()
417+
.construct_array_type()
418+
._from_sequence(["a", "b"], dtype=pd.StringDtype()),
419+
),
390420
# Boolean
391421
([True, False], BooleanArray._from_sequence([True, False], dtype="boolean")),
392422
([True, None], BooleanArray._from_sequence([True, None], dtype="boolean")),

pandas/tests/arrays/test_datetimelike.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,7 @@ def test_searchsorted(self):
297297
assert result == 10
298298

299299
@pytest.mark.parametrize("box", [None, "index", "series"])
300-
def test_searchsorted_castable_strings(
301-
self, arr1d, box, string_storage, using_infer_string
302-
):
300+
def test_searchsorted_castable_strings(self, arr1d, box, string_storage):
303301
arr = arr1d
304302
if box is None:
305303
pass
@@ -335,8 +333,7 @@ def test_searchsorted_castable_strings(
335333
TypeError,
336334
match=re.escape(
337335
f"value should be a '{arr1d._scalar_type.__name__}', 'NaT', "
338-
"or array of those. Got "
339-
f"{'str' if using_infer_string else 'string'} array instead."
336+
"or array of those. Got string array instead."
340337
),
341338
):
342339
arr.searchsorted([str(arr[1]), "baz"])

pandas/tests/base/test_value_counts.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def test_value_counts_inferred(index_or_series, using_infer_string):
114114
else:
115115
exp = np.unique(np.array(s_values, dtype=np.object_))
116116
if using_infer_string:
117-
exp = array(exp)
117+
exp = array(exp, dtype="str")
118118
tm.assert_equal(s.unique(), exp)
119119

120120
assert s.nunique() == 4
@@ -192,7 +192,7 @@ def test_value_counts_bins(index_or_series, using_infer_string):
192192
else:
193193
exp = np.array(["a", "b", np.nan, "d"], dtype=object)
194194
if using_infer_string:
195-
exp = array(exp)
195+
exp = array(exp, dtype="str")
196196
tm.assert_equal(s.unique(), exp)
197197
assert s.nunique() == 3
198198

pandas/tests/dtypes/cast/test_construct_ndarray.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def test_construct_1d_ndarray_preserving_na(
2121
):
2222
result = sanitize_array(values, index=None, dtype=dtype)
2323
if using_infer_string and expected.dtype == object and dtype is None:
24-
tm.assert_extension_array_equal(result, pd.array(expected))
24+
tm.assert_extension_array_equal(result, pd.array(expected, dtype="str"))
2525
else:
2626
tm.assert_numpy_array_equal(result, expected)
2727

pandas/tests/io/parser/usecols/test_usecols_basic.py

-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import numpy as np
99
import pytest
1010

11-
from pandas._config import using_string_dtype
12-
1311
from pandas.errors import ParserError
1412

1513
from pandas import (
@@ -531,7 +529,6 @@ def test_usecols_additional_columns_integer_columns(all_parsers):
531529
tm.assert_frame_equal(result, expected)
532530

533531

534-
@pytest.mark.xfail(using_string_dtype(), reason="TODO(infer_string)")
535532
def test_usecols_dtype(all_parsers):
536533
parser = all_parsers
537534
data = """

0 commit comments

Comments
 (0)