Skip to content

Commit 493dd9d

Browse files
committed
Add method _validate_setitem_value and fix tests
1 parent 21c1d28 commit 493dd9d

File tree

16 files changed

+115
-43
lines changed

16 files changed

+115
-43
lines changed

pandas/core/arrays/numpy_.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,84 @@ def _values_for_factorize(self) -> tuple[np.ndarray, float | None]:
239239
fv = np.nan
240240
return self._ndarray, fv
241241

242+
def _validate_setitem_value(self, value):
243+
"""
244+
Check if we have a scalar that we can cast losslessly.
245+
246+
Raises
247+
------
248+
TypeError
249+
"""
250+
251+
kind = self.dtype.kind
252+
253+
if kind == "b":
254+
if lib.is_bool(value) or np.can_cast(type(value), self.dtype.type):
255+
return value
256+
if isinstance(value, NumpyExtensionArray) and (
257+
lib.is_bool_array(value.to_numpy())
258+
):
259+
return value
260+
261+
elif kind == "i":
262+
if lib.is_integer(value) or np.can_cast(type(value), self.dtype.type):
263+
return value
264+
if isinstance(value, NumpyExtensionArray) and lib.is_integer_array(
265+
value.to_numpy()
266+
):
267+
return value
268+
269+
elif kind == "u":
270+
if (lib.is_integer(value) and value > -1) or np.can_cast(
271+
type(value), self.dtype.type
272+
):
273+
return value
274+
275+
elif kind == "c":
276+
if lib.is_complex(value) or np.can_cast(type(value), self.dtype.type):
277+
return value
278+
279+
elif kind == "S":
280+
if isinstance(value, str) or np.can_cast(type(value), self.dtype.type):
281+
return value
282+
if isinstance(value, NumpyExtensionArray) and lib.is_string_array(
283+
value.to_numpy()
284+
):
285+
return value
286+
287+
elif kind == "M":
288+
if isinstance(value, np.datetime64):
289+
return value
290+
if isinstance(value, NumpyExtensionArray) and (
291+
lib.is_date_array(value.to_numpy())
292+
or lib.is_datetime_array(value.to_numpy())
293+
or lib.is_datetime64_array(value.to_numpy())
294+
or lib.is_datetime_with_singletz_array(value.to_numpy())
295+
):
296+
return value
297+
298+
elif kind == "m":
299+
if isinstance(value, np.timedelta64):
300+
return value
301+
if isinstance(value, NumpyExtensionArray) and (
302+
lib.is_timedelta_or_timedelta64_array(value.to_numpy())
303+
or lib.is_time_array(value.to_numpy())
304+
):
305+
return value
306+
307+
elif kind == "f":
308+
if lib.is_float(value) or np.can_cast(type(value), self.dtype.type):
309+
return value
310+
if isinstance(value, NumpyExtensionArray) and lib.is_float_array(
311+
value.to_numpy()
312+
):
313+
return value
314+
315+
elif np.can_cast(type(value), self.dtype.type):
316+
return value
317+
318+
raise TypeError(f"Invalid value '{value!s}' for dtype {self.dtype}")
319+
242320
# Base EA class (and all other EA classes) don't have limit_area keyword
243321
# This can be removed here as well when the interpolate ffill/bfill method
244322
# deprecation is enforced

pandas/tests/arithmetic/test_object.py

Lines changed: 0 additions & 3 deletions
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
import pandas.util._test_decorators as td
1412

1513
import pandas as pd
@@ -303,7 +301,6 @@ def test_iadd_string(self):
303301
index += "_x"
304302
assert "a_x" in index
305303

306-
@pytest.mark.xfail(using_string_dtype(), reason="add doesn't work")
307304
def test_add(self):
308305
index = pd.Index([str(i) for i in range(10)])
309306
expected = pd.Index(index.values * 2)

pandas/tests/arrays/numpy_/test_numpy.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,12 @@ def test_validate_reduction_keyword_args():
197197
arr.all(keepdims=True)
198198

199199

200-
@pytest.mark.xfail
201200
@pytest.mark.parametrize(
202201
"value, expectedError",
203202
[
203+
(True, False),
204+
(5, False),
205+
(5.0, True),
204206
(5.5, True),
205207
(1 + 2j, True),
206208
("t", True),
@@ -217,10 +219,13 @@ def test_int_arr_validate_setitem_value(value, expectedError):
217219
assert arr[0] == value
218220

219221

220-
@pytest.mark.xfail
221222
@pytest.mark.parametrize(
222223
"value, expectedError",
223224
[
225+
(True, False),
226+
(5, False),
227+
(5.0, False),
228+
(5.5, False),
224229
(1 + 2j, True),
225230
("t", True),
226231
(datetime.now(), True),
@@ -236,10 +241,14 @@ def test_float_arr_validate_setitem_value(value, expectedError):
236241
assert arr[0] == value
237242

238243

239-
@pytest.mark.xfail
240244
@pytest.mark.parametrize(
241245
"value, expectedError",
242246
[
247+
(True, False),
248+
(5, False),
249+
(5.0, False),
250+
(5.5, False),
251+
("t", False),
243252
(datetime.now(), True),
244253
],
245254
)
@@ -333,12 +342,15 @@ def test_setitem_object_typecode(dtype):
333342
def test_setitem_no_coercion():
334343
# https://github.com/pandas-dev/pandas/issues/28150
335344
arr = NumpyExtensionArray(np.array([1, 2, 3]))
336-
with pytest.raises(ValueError, match="int"):
345+
with pytest.raises(TypeError):
337346
arr[0] = "a"
338347

339348
# With a value that we do coerce, check that we coerce the value
340349
# and not the underlying array.
341-
arr[0] = 2.5
350+
with pytest.raises(TypeError):
351+
arr[0] = 2.5
352+
353+
arr[0] = 9
342354
assert isinstance(arr[0], (int, np.integer)), type(arr[0])
343355

344356

@@ -354,7 +366,10 @@ def test_setitem_preserves_views():
354366
assert view2[0] == 9
355367
assert view3[0] == 9
356368

357-
arr[-1] = 2.5
369+
with pytest.raises(TypeError):
370+
arr[-1] = 2.5
371+
372+
arr[-1] = 4
358373
view1[-1] = 5
359374
assert arr[-1] == 5
360375

pandas/tests/base/test_unique.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import numpy as np
22
import pytest
33

4-
from pandas._config import using_string_dtype
5-
64
import pandas as pd
75
import pandas._testing as tm
86
from pandas.tests.base.common import allow_na_ops
@@ -100,12 +98,11 @@ def test_nunique_null(null_obj, index_or_series_obj):
10098

10199

102100
@pytest.mark.single_cpu
103-
@pytest.mark.xfail(using_string_dtype(), reason="decoding fails")
104101
def test_unique_bad_unicode(index_or_series):
105102
# regression test for #34550
106103
uval = "\ud83d" # smiley emoji
107104

108-
obj = index_or_series([uval] * 2)
105+
obj = index_or_series([uval] * 2, dtype=object)
109106
result = obj.unique()
110107

111108
if isinstance(obj, pd.Index):

pandas/tests/frame/constructors/test_from_dict.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def test_constructor_single_row(self):
4444
)
4545
tm.assert_frame_equal(result, expected)
4646

47-
@pytest.mark.skipif(using_string_dtype(), reason="columns inferring logic broken")
47+
@pytest.mark.xfail(using_string_dtype(), reason="columns inferring logic broken")
4848
def test_constructor_list_of_series(self):
4949
data = [
5050
OrderedDict([["a", 1.5], ["b", 3.0], ["c", 4.0]]),
@@ -108,6 +108,7 @@ def test_constructor_list_of_series(self):
108108
expected = DataFrame.from_dict(sdict, orient="index")
109109
tm.assert_frame_equal(result, expected)
110110

111+
@pytest.mark.xfail(using_string_dtype(), reason="columns inferring logic broken")
111112
def test_constructor_orient(self, float_string_frame):
112113
data_dict = float_string_frame.T._series
113114
recons = DataFrame.from_dict(data_dict, orient="index")

pandas/tests/frame/constructors/test_from_records.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ def test_from_records_with_datetimes(self):
5757
expected["EXPIRY"] = expected["EXPIRY"].astype("M8[s]")
5858
tm.assert_frame_equal(result, expected)
5959

60-
@pytest.mark.skipif(
61-
using_string_dtype(), reason="dtype checking logic doesn't work"
62-
)
60+
@pytest.mark.xfail(using_string_dtype(), reason="dtype checking logic doesn't work")
6361
def test_from_records_sequencelike(self):
6462
df = DataFrame(
6563
{

pandas/tests/frame/methods/test_fillna.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def test_fillna_datetime(self, datetime_frame):
6565
with pytest.raises(TypeError, match=msg):
6666
datetime_frame.fillna()
6767

68+
# TODO(infer_string) test as actual error instead of xfail
6869
@pytest.mark.xfail(using_string_dtype(), reason="can't fill 0 in string")
6970
def test_fillna_mixed_type(self, float_string_frame):
7071
mf = float_string_frame
@@ -537,6 +538,7 @@ def test_fillna_col_reordering(self):
537538
filled = df.ffill()
538539
assert df.columns.tolist() == filled.columns.tolist()
539540

541+
# TODO(infer_string) test as actual error instead of xfail
540542
@pytest.mark.xfail(using_string_dtype(), reason="can't fill 0 in string")
541543
def test_fill_corner(self, float_frame, float_string_frame):
542544
mf = float_string_frame

pandas/tests/frame/methods/test_info.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from pandas import (
1616
CategoricalIndex,
1717
DataFrame,
18+
Index,
1819
MultiIndex,
1920
Series,
2021
date_range,
@@ -360,7 +361,7 @@ def test_info_memory_usage():
360361
df = DataFrame(data)
361362
df.columns = dtypes
362363

363-
df_with_object_index = DataFrame({"a": [1]}, index=["foo"])
364+
df_with_object_index = DataFrame({"a": [1]}, index=Index(["foo"], dtype=object))
364365
df_with_object_index.info(buf=buf, memory_usage=True)
365366
res = buf.getvalue().splitlines()
366367
assert re.match(r"memory usage: [^+]+\+", res[-1])
@@ -398,25 +399,25 @@ def test_info_memory_usage():
398399

399400
@pytest.mark.skipif(PYPY, reason="on PyPy deep=True doesn't change result")
400401
def test_info_memory_usage_deep_not_pypy():
401-
df_with_object_index = DataFrame({"a": [1]}, index=["foo"])
402+
df_with_object_index = DataFrame({"a": [1]}, index=Index(["foo"], dtype=object))
402403
assert (
403404
df_with_object_index.memory_usage(index=True, deep=True).sum()
404405
> df_with_object_index.memory_usage(index=True).sum()
405406
)
406407

407-
df_object = DataFrame({"a": ["a"]})
408+
df_object = DataFrame({"a": Series(["a"], dtype=object)})
408409
assert df_object.memory_usage(deep=True).sum() > df_object.memory_usage().sum()
409410

410411

411412
@pytest.mark.xfail(not PYPY, reason="on PyPy deep=True does not change result")
412413
def test_info_memory_usage_deep_pypy():
413-
df_with_object_index = DataFrame({"a": [1]}, index=["foo"])
414+
df_with_object_index = DataFrame({"a": [1]}, index=Index(["foo"], dtype=object))
414415
assert (
415416
df_with_object_index.memory_usage(index=True, deep=True).sum()
416417
== df_with_object_index.memory_usage(index=True).sum()
417418
)
418419

419-
df_object = DataFrame({"a": ["a"]})
420+
df_object = DataFrame({"a": Series(["a"], dtype=object)})
420421
assert df_object.memory_usage(deep=True).sum() == df_object.memory_usage().sum()
421422

422423

pandas/tests/frame/methods/test_interpolate.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def test_interpolate_inplace(self, frame_or_series, request):
6464
assert np.shares_memory(orig, obj.values)
6565
assert orig.squeeze()[1] == 1.5
6666

67+
# TODO(infer_string) raise proper TypeError in case of string dtype
6768
@pytest.mark.xfail(
6869
using_string_dtype(), reason="interpolate doesn't work for string"
6970
)

pandas/tests/frame/test_arithmetic.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
import numpy as np
1212
import pytest
1313

14-
from pandas._config import using_string_dtype
15-
1614
import pandas as pd
1715
from pandas import (
1816
DataFrame,
@@ -251,7 +249,6 @@ def test_timestamp_compare(self, left, right):
251249
with pytest.raises(TypeError, match=msg):
252250
right_f(pd.Timestamp("nat"), df)
253251

254-
@pytest.mark.xfail(using_string_dtype(), reason="can't compare string and int")
255252
def test_mixed_comparison(self):
256253
# GH#13128, GH#22163 != datetime64 vs non-dt64 should be False,
257254
# not raise TypeError

0 commit comments

Comments
 (0)