Skip to content

Commit 13147f3

Browse files
authored
DEPR: Series([np.nan], dtype='i8') silently ignoring dtype (#45136)
1 parent b2d54d9 commit 13147f3

File tree

5 files changed

+39
-9
lines changed

5 files changed

+39
-9
lines changed

doc/source/whatsnew/v1.4.0.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,8 +656,10 @@ Other Deprecations
656656
- Deprecated ``numeric_only=None`` in :meth:`DataFrame.rank`; in a future version ``numeric_only`` must be either ``True`` or ``False`` (the default) (:issue:`45036`)
657657
- Deprecated the behavior of :meth:`Timestamp.utcfromtimestamp`, in the future it will return a timezone-aware UTC :class:`Timestamp` (:issue:`22451`)
658658
- Deprecated :meth:`NaT.freq` (:issue:`45071`)
659+
- Deprecated behavior of :class:`Series` and :class:`DataFrame` construction when passed float-dtype data containing ``NaN`` and an integer dtype ignoring the dtype argument; in a future version this will raise (:issue:`40110`)
659660
-
660661

662+
661663
.. ---------------------------------------------------------------------------
662664
663665
.. _whatsnew_140.performance:

pandas/core/construction.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,15 @@ def sanitize_array(
535535
try:
536536
subarr = _try_cast(data, dtype, copy, True)
537537
except IntCastingNaNError:
538+
warnings.warn(
539+
"In a future version, passing float-dtype values containing NaN "
540+
"and an integer dtype will raise IntCastingNaNError "
541+
"(subclass of ValueError) instead of silently ignoring the "
542+
"passed dtype. To retain the old behavior, call Series(arr) or "
543+
"DataFrame(arr) without passing a dtype.",
544+
FutureWarning,
545+
stacklevel=find_stack_level(),
546+
)
538547
subarr = np.array(data, copy=copy)
539548
except ValueError:
540549
if not raise_cast_failure:

pandas/tests/frame/test_constructors.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,14 @@ def test_constructor_dict_with_tzaware_scalar(self):
9797
def test_construct_ndarray_with_nas_and_int_dtype(self):
9898
# GH#26919 match Series by not casting np.nan to meaningless int
9999
arr = np.array([[1, np.nan], [2, 3]])
100-
df = DataFrame(arr, dtype="i8")
100+
with tm.assert_produces_warning(FutureWarning):
101+
df = DataFrame(arr, dtype="i8")
101102
assert df.values.dtype == arr.dtype
102103
assert isna(df.iloc[0, 1])
103104

104105
# check this matches Series behavior
105-
ser = Series(arr[0], dtype="i8", name=0)
106+
with tm.assert_produces_warning(FutureWarning):
107+
ser = Series(arr[0], dtype="i8", name=0)
106108
expected = df.iloc[0]
107109
tm.assert_series_equal(ser, expected)
108110

@@ -937,7 +939,11 @@ def _check_basic_constructor(self, empty):
937939
assert len(frame.index) == 3
938940
assert len(frame.columns) == 1
939941

940-
frame = DataFrame(mat, columns=["A", "B", "C"], index=[1, 2], dtype=np.int64)
942+
warn = None if empty is np.ones else FutureWarning
943+
with tm.assert_produces_warning(warn):
944+
frame = DataFrame(
945+
mat, columns=["A", "B", "C"], index=[1, 2], dtype=np.int64
946+
)
941947
if empty is np.ones:
942948
# passing dtype casts
943949
assert frame.values.dtype == np.int64
@@ -1766,7 +1772,9 @@ def test_constructor_mix_series_nonseries(self, float_frame):
17661772
DataFrame({"A": float_frame["A"], "B": list(float_frame["B"])[:-2]})
17671773

17681774
def test_constructor_miscast_na_int_dtype(self):
1769-
df = DataFrame([[np.nan, 1], [1, 0]], dtype=np.int64)
1775+
msg = "float-dtype values containing NaN and an integer dtype"
1776+
with tm.assert_produces_warning(FutureWarning, match=msg):
1777+
df = DataFrame([[np.nan, 1], [1, 0]], dtype=np.int64)
17701778
expected = DataFrame([[np.nan, 1], [1, 0]])
17711779
tm.assert_frame_equal(df, expected)
17721780

@@ -2713,10 +2721,19 @@ def test_floating_values_integer_dtype(self):
27132721
# if they can be cast losslessly, no warning
27142722
DataFrame(arr.round(), dtype="i8")
27152723

2716-
# with NaNs, we already have the correct behavior, so no warning
2724+
# with NaNs, we go through a different path with a different warning
27172725
arr[0, 0] = np.nan
2718-
with tm.assert_produces_warning(None):
2726+
msg = "passing float-dtype values containing NaN"
2727+
with tm.assert_produces_warning(FutureWarning, match=msg):
27192728
DataFrame(arr, dtype="i8")
2729+
with tm.assert_produces_warning(FutureWarning, match=msg):
2730+
Series(arr[0], dtype="i8")
2731+
# The future (raising) behavior matches what we would get via astype:
2732+
msg = r"Cannot convert non-finite values \(NA or inf\) to integer"
2733+
with pytest.raises(ValueError, match=msg):
2734+
DataFrame(arr).astype("i8")
2735+
with pytest.raises(ValueError, match=msg):
2736+
Series(arr[0]).astype("i8")
27202737

27212738

27222739
class TestDataFrameConstructorWithDatetimeTZ:

pandas/tests/frame/test_stack_unstack.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1046,8 +1046,8 @@ def _test_stack_with_multiindex(multiindex):
10461046
names=[None, "Lower"],
10471047
),
10481048
columns=Index(["B", "C"], name="Upper"),
1049-
dtype=df.dtypes[0],
10501049
)
1050+
expected["B"] = expected["B"].astype(df.dtypes[0])
10511051
tm.assert_frame_equal(result, expected)
10521052

10531053
@pytest.mark.parametrize("ordered", [False, True])

pandas/tests/series/test_constructors.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,10 @@ def test_constructor_sanitize(self):
652652
s = Series(np.array([1.0, 1.0, 8.0]), dtype="i8")
653653
assert s.dtype == np.dtype("i8")
654654

655-
s = Series(np.array([1.0, 1.0, np.nan]), copy=True, dtype="i8")
656-
assert s.dtype == np.dtype("f8")
655+
msg = "float-dtype values containing NaN and an integer dtype"
656+
with tm.assert_produces_warning(FutureWarning, match=msg):
657+
ser = Series(np.array([1.0, 1.0, np.nan]), copy=True, dtype="i8")
658+
assert ser.dtype == np.dtype("f8")
657659

658660
def test_constructor_copy(self):
659661
# GH15125

0 commit comments

Comments
 (0)