From eafd9ea11cab2d87e92d70ae00b28aca01ec596b Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 7 Nov 2020 00:54:16 +0100 Subject: [PATCH 01/16] Start fixing dtype setting --- pandas/core/frame.py | 8 +------- pandas/core/series.py | 3 ++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 049d2c4888a69..4518649b3ef3b 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3202,13 +3202,7 @@ def _set_value(self, index, col, value, takeable: bool = False): return series = self._get_item_cache(col) - engine = self.index._engine - loc = engine.get_loc(index) - validate_numeric_casting(series.dtype, value) - - series._values[loc] = value - # Note: trying to use series._set_value breaks tests in - # tests.frame.indexing.test_indexing and tests.indexing.test_partial + series._set_value(index, value, takeable) except (KeyError, TypeError): # set using a non-recursive method & reset the cache if takeable: diff --git a/pandas/core/series.py b/pandas/core/series.py index e4a805a18bcdb..4f2cca9e503e8 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -43,7 +43,7 @@ from pandas.core.dtypes.cast import ( convert_dtypes, maybe_cast_to_extension_array, - validate_numeric_casting, + validate_numeric_casting, infer_dtype_from_scalar, ) from pandas.core.dtypes.common import ( ensure_platform_int, @@ -1110,6 +1110,7 @@ def _set_value(self, label, value, takeable: bool = False): else: loc = self.index.get_loc(label) validate_numeric_casting(self.dtype, value) + dtype, _ = infer_dtype_from_scalar(value, pandas_dtype=True) self._values[loc] = value except KeyError: From c95dcc94805e2f20afbe05b95d3bd92ff5d18448 Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 7 Nov 2020 01:28:30 +0100 Subject: [PATCH 02/16] Fix dtype setting for incompatible dtypes --- pandas/core/frame.py | 1 + pandas/core/series.py | 7 ++++++- pandas/tests/indexing/test_at.py | 18 +++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 4518649b3ef3b..521a86b2ce5a2 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3202,6 +3202,7 @@ def _set_value(self, index, col, value, takeable: bool = False): return series = self._get_item_cache(col) + self.index._engine.get_loc(index) series._set_value(index, value, takeable) except (KeyError, TypeError): # set using a non-recursive method & reset the cache diff --git a/pandas/core/series.py b/pandas/core/series.py index 4f2cca9e503e8..a24d1ad000209 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -43,7 +43,8 @@ from pandas.core.dtypes.cast import ( convert_dtypes, maybe_cast_to_extension_array, - validate_numeric_casting, infer_dtype_from_scalar, + validate_numeric_casting, + infer_dtype_from_scalar, ) from pandas.core.dtypes.common import ( ensure_platform_int, @@ -57,6 +58,7 @@ is_object_dtype, is_scalar, validate_all_hashable, + is_dtype_equal, ) from pandas.core.dtypes.generic import ABCDataFrame from pandas.core.dtypes.inference import is_hashable @@ -1111,6 +1113,9 @@ def _set_value(self, label, value, takeable: bool = False): loc = self.index.get_loc(label) validate_numeric_casting(self.dtype, value) dtype, _ = infer_dtype_from_scalar(value, pandas_dtype=True) + if not is_dtype_equal(self.dtype, dtype): + self.loc[label] = value + return self._values[loc] = value except KeyError: diff --git a/pandas/tests/indexing/test_at.py b/pandas/tests/indexing/test_at.py index 2e06d8c73d7d1..18c42772b1944 100644 --- a/pandas/tests/indexing/test_at.py +++ b/pandas/tests/indexing/test_at.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from pandas import DataFrame +from pandas import DataFrame, Series import pandas._testing as tm @@ -39,3 +39,19 @@ def test_at_with_duplicate_axes_requires_scalar_lookup(self): df.at[1, ["A"]] = 1 with pytest.raises(ValueError, match=msg): df.at[:, "A"] = 1 + + +def test_at_assign_float_to_int_frame(): + # GH: 26395 + obj = DataFrame([0, 0, 0], index=["A", "B", "C"], columns=["D"]) + obj.at["C", "D"] = 44.5 + expected = DataFrame([0, 0, 44.5], index=["A", "B", "C"], columns=["D"]) + tm.assert_frame_equal(obj, expected) + + +def test_at_assign_float_to_int_series(): + # GH: 26395 + obj = Series([0, 0, 0], index=["A", "B", "C"]) + obj.at["C"] = 44.5 + expected = Series([0, 0, 44.5], index=["A", "B", "C"]) + tm.assert_series_equal(obj, expected) From 3788c4df7ff0c5c1a714a8ca5d0b0916687e3ffb Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 7 Nov 2020 01:29:47 +0100 Subject: [PATCH 03/16] Add whatsnew --- doc/source/whatsnew/v1.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 690e6b8f725ad..b97a38588a3d1 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -465,6 +465,7 @@ Indexing - Bug in indexing on a :class:`Series` or :class:`DataFrame` with a :class:`MultiIndex` with a level named "0" (:issue:`37194`) - Bug in :meth:`Series.__getitem__` when using an unsigned integer array as an indexer giving incorrect results or segfaulting instead of raising ``KeyError`` (:issue:`37218`) - Bug in :meth:`Index.where` incorrectly casting numeric values to strings (:issue:`37591`) +- Bug in :meth:`DataFrame.at` and :meth:`Series.at` did not adjust dtype when float was assigned to integer column (:issue:`26395`) Missing ^^^^^^^ From 27d9e35a3b6b4999990080584761f9704bd8569a Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 7 Nov 2020 01:33:17 +0100 Subject: [PATCH 04/16] Fix imports --- pandas/core/frame.py | 1 - pandas/core/series.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 521a86b2ce5a2..7200ea4c14ea3 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -91,7 +91,6 @@ maybe_downcast_to_dtype, maybe_infer_to_datetimelike, maybe_upcast, - validate_numeric_casting, ) from pandas.core.dtypes.common import ( ensure_int64, diff --git a/pandas/core/series.py b/pandas/core/series.py index a24d1ad000209..8699ce58cd5b5 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -51,6 +51,7 @@ is_bool, is_categorical_dtype, is_dict_like, + is_dtype_equal, is_extension_array_dtype, is_integer, is_iterator, @@ -58,7 +59,6 @@ is_object_dtype, is_scalar, validate_all_hashable, - is_dtype_equal, ) from pandas.core.dtypes.generic import ABCDataFrame from pandas.core.dtypes.inference import is_hashable From 23cc926b146f1f9e6fea86a78b6fdbb6be87ebcf Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 7 Nov 2020 01:39:19 +0100 Subject: [PATCH 05/16] Change import order --- pandas/core/series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 8699ce58cd5b5..d79264f9ff649 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -42,9 +42,9 @@ from pandas.core.dtypes.cast import ( convert_dtypes, + infer_dtype_from_scalar, maybe_cast_to_extension_array, validate_numeric_casting, - infer_dtype_from_scalar, ) from pandas.core.dtypes.common import ( ensure_platform_int, From cee9fc2b410a2a66702eca29a10e5e93ff45c30d Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 7 Nov 2020 20:40:53 +0100 Subject: [PATCH 06/16] Add check for numeric dtype --- pandas/core/series.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index d79264f9ff649..40b2b9c446911 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -56,6 +56,7 @@ is_integer, is_iterator, is_list_like, + is_numeric_dtype, is_object_dtype, is_scalar, validate_all_hashable, @@ -1113,7 +1114,7 @@ def _set_value(self, label, value, takeable: bool = False): loc = self.index.get_loc(label) validate_numeric_casting(self.dtype, value) dtype, _ = infer_dtype_from_scalar(value, pandas_dtype=True) - if not is_dtype_equal(self.dtype, dtype): + if not is_dtype_equal(self.dtype, dtype) and is_numeric_dtype(dtype): self.loc[label] = value return self._values[loc] = value From d1bc870eab49c55feccf4c22f7b17c97f05c63ff Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 8 Nov 2020 01:22:01 +0100 Subject: [PATCH 07/16] Parametrize tests --- pandas/tests/indexing/test_at.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pandas/tests/indexing/test_at.py b/pandas/tests/indexing/test_at.py index 72e5a3ad7c477..21c90b6340df9 100644 --- a/pandas/tests/indexing/test_at.py +++ b/pandas/tests/indexing/test_at.py @@ -110,17 +110,19 @@ def test_at_frame_raises_key_error2(self): df.loc["a", 0] -def test_at_assign_float_to_int_frame(): +@pytest.mark.parametrize("func", ["at", "loc"]) +def test_at_assign_float_to_int_frame(func): # GH: 26395 obj = DataFrame([0, 0, 0], index=["A", "B", "C"], columns=["D"]) - obj.at["C", "D"] = 44.5 + getattr(obj, func)["C", "D"] = 44.5 expected = DataFrame([0, 0, 44.5], index=["A", "B", "C"], columns=["D"]) tm.assert_frame_equal(obj, expected) -def test_at_assign_float_to_int_series(): +@pytest.mark.parametrize("func", ["at", "loc"]) +def test_at_assign_float_to_int_series(func): # GH: 26395 obj = Series([0, 0, 0], index=["A", "B", "C"]) - obj.at["C"] = 44.5 + getattr(obj, func)["C"] = 44.5 expected = Series([0, 0, 44.5], index=["A", "B", "C"]) tm.assert_series_equal(obj, expected) From 4d91e666652c36715c253a601ec7bfaa3d560954 Mon Sep 17 00:00:00 2001 From: phofl Date: Tue, 10 Nov 2020 22:05:21 +0100 Subject: [PATCH 08/16] Improve dtype casting for at and iat --- pandas/core/series.py | 12 +++++++++--- pandas/tests/indexing/test_at.py | 12 ++++++++++++ pandas/tests/series/indexing/test_setitem.py | 8 ++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 77d19bddb14ef..380c04d287e0a 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1046,7 +1046,11 @@ def _set_with_engine(self, key, value): # fails with AttributeError for IntervalIndex loc = self.index._engine.get_loc(key) validate_numeric_casting(self.dtype, value) - self._values[loc] = value + dtype, _ = infer_dtype_from_scalar(value) + if is_dtype_equal(self.dtype, dtype): + self._values[loc] = value + else: + self.loc[key] = value def _set_with(self, key, value): # other: fancy integer or otherwise @@ -1108,12 +1112,14 @@ def _set_value(self, label, value, takeable: bool = False): takeable : interpret the index as indexers, default False """ try: - if takeable: + dtype, _ = infer_dtype_from_scalar(value, pandas_dtype=True) + if takeable and is_dtype_equal(self.dtype, dtype): self._values[label] = value + elif takeable: + self.iloc[label] = value else: loc = self.index.get_loc(label) validate_numeric_casting(self.dtype, value) - dtype, _ = infer_dtype_from_scalar(value, pandas_dtype=True) if not is_dtype_equal(self.dtype, dtype) and is_numeric_dtype(dtype): self.loc[label] = value return diff --git a/pandas/tests/indexing/test_at.py b/pandas/tests/indexing/test_at.py index 21c90b6340df9..466b65aef2ee5 100644 --- a/pandas/tests/indexing/test_at.py +++ b/pandas/tests/indexing/test_at.py @@ -126,3 +126,15 @@ def test_at_assign_float_to_int_series(func): getattr(obj, func)["C"] = 44.5 expected = Series([0, 0, 44.5], index=["A", "B", "C"]) tm.assert_series_equal(obj, expected) + + +def test_assign_float_to_int_series_takeable(): + # GH: 20643 + ser = Series([0, 1, 2], index=list('abc')) + ser.iat[1] = 3.1 + expected = Series([0, 3.1, 2], index=list('abc')) + tm.assert_series_equal(ser, expected) + + ser = Series([0, 1, 2], index=list('abc')) + ser.at["b"] = 3.1 + tm.assert_series_equal(ser, expected) diff --git a/pandas/tests/series/indexing/test_setitem.py b/pandas/tests/series/indexing/test_setitem.py index 7e25e5200d610..c56bd961381d3 100644 --- a/pandas/tests/series/indexing/test_setitem.py +++ b/pandas/tests/series/indexing/test_setitem.py @@ -248,3 +248,11 @@ def test_setitem_slice_into_readonly_backing_data(): series[1:3] = 1 assert not array.any() + + +def test_setitem_float_to_int(): + # GH 20643 + ser = Series([0, 1, 2], index=list('abc')) + ser["b"] = 3.1 + expected = Series([0, 3.1, 2], index=list('abc')) + tm.assert_series_equal(ser, expected) From d6084747ad0f228d84e598c857ccc6175544338e Mon Sep 17 00:00:00 2001 From: phofl Date: Tue, 10 Nov 2020 22:05:59 +0100 Subject: [PATCH 09/16] Adjust whatsnew --- doc/source/whatsnew/v1.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 250c9fb0f7328..0c89f12b5a587 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -469,7 +469,7 @@ Indexing - Bug in :meth:`Index.where` incorrectly casting numeric values to strings (:issue:`37591`) - Bug in :meth:`Series.loc` and :meth:`DataFrame.loc` raises when numeric label was given for object :class:`Index` although label was in :class:`Index` (:issue:`26491`) - Bug in :meth:`DataFrame.loc` returned requested key plus missing values when ``loc`` was applied to single level from :class:`MultiIndex` (:issue:`27104`) -- Bug in :meth:`DataFrame.at` and :meth:`Series.at` did not adjust dtype when float was assigned to integer column (:issue:`26395`) +- Bug in :meth:`DataFrame.at` and :meth:`Series.at` did not adjust dtype when float was assigned to integer column (:issue:`26395`, :issue:`20643`) Missing ^^^^^^^ From 760c6a12a38630557e2a15f9f1a3e4c9beb032a1 Mon Sep 17 00:00:00 2001 From: phofl Date: Tue, 10 Nov 2020 22:06:37 +0100 Subject: [PATCH 10/16] Run black --- pandas/tests/indexing/test_at.py | 6 +++--- pandas/tests/series/indexing/test_setitem.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pandas/tests/indexing/test_at.py b/pandas/tests/indexing/test_at.py index e802ee0152b6b..df32f78055642 100644 --- a/pandas/tests/indexing/test_at.py +++ b/pandas/tests/indexing/test_at.py @@ -148,11 +148,11 @@ def test_at_assign_float_to_int_series(func): def test_assign_float_to_int_series_takeable(): # GH: 20643 - ser = Series([0, 1, 2], index=list('abc')) + ser = Series([0, 1, 2], index=list("abc")) ser.iat[1] = 3.1 - expected = Series([0, 3.1, 2], index=list('abc')) + expected = Series([0, 3.1, 2], index=list("abc")) tm.assert_series_equal(ser, expected) - ser = Series([0, 1, 2], index=list('abc')) + ser = Series([0, 1, 2], index=list("abc")) ser.at["b"] = 3.1 tm.assert_series_equal(ser, expected) diff --git a/pandas/tests/series/indexing/test_setitem.py b/pandas/tests/series/indexing/test_setitem.py index fbf61b873a686..44c992e5ae771 100644 --- a/pandas/tests/series/indexing/test_setitem.py +++ b/pandas/tests/series/indexing/test_setitem.py @@ -261,7 +261,7 @@ def test_setitem_slice_into_readonly_backing_data(): def test_setitem_float_to_int(): # GH 20643 - ser = Series([0, 1, 2], index=list('abc')) + ser = Series([0, 1, 2], index=list("abc")) ser["b"] = 3.1 - expected = Series([0, 3.1, 2], index=list('abc')) + expected = Series([0, 3.1, 2], index=list("abc")) tm.assert_series_equal(ser, expected) From 870e927db890e9c32d84482e7e7f9531a475cada Mon Sep 17 00:00:00 2001 From: phofl Date: Tue, 10 Nov 2020 23:01:20 +0100 Subject: [PATCH 11/16] Fix tests with new dtype conversion --- pandas/tests/indexing/test_coercion.py | 42 ++++---------------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/pandas/tests/indexing/test_coercion.py b/pandas/tests/indexing/test_coercion.py index fd6f6fbc6a4ba..0c6295fe013e2 100644 --- a/pandas/tests/indexing/test_coercion.py +++ b/pandas/tests/indexing/test_coercion.py @@ -114,31 +114,17 @@ def test_setitem_series_int64(self, val, exp_dtype, request): obj = pd.Series([1, 2, 3, 4]) assert obj.dtype == np.int64 - if exp_dtype is np.float64: - exp = pd.Series([1, 1, 3, 4]) - self._assert_setitem_series_conversion(obj, 1.1, exp, np.int64) - mark = pytest.mark.xfail(reason="GH12747 The result must be float") - request.node.add_marker(mark) - exp = pd.Series([1, val, 3, 4]) self._assert_setitem_series_conversion(obj, val, exp, exp_dtype) @pytest.mark.parametrize( - "val,exp_dtype", [(np.int32(1), np.int8), (np.int16(2 ** 9), np.int16)] + "val,exp_dtype", [(np.int32(1), np.int32), (np.int16(2 ** 9), np.int16)] ) def test_setitem_series_int8(self, val, exp_dtype, request): obj = pd.Series([1, 2, 3, 4], dtype=np.int8) assert obj.dtype == np.int8 - if exp_dtype is np.int16: - exp = pd.Series([1, 0, 3, 4], dtype=np.int8) - self._assert_setitem_series_conversion(obj, val, exp, np.int8) - mark = pytest.mark.xfail( - reason="BUG: it must be pd.Series([1, 1, 3, 4], dtype=np.int16" - ) - request.node.add_marker(mark) - - exp = pd.Series([1, val, 3, 4], dtype=np.int8) + exp = pd.Series([1, val, 3, 4], dtype=exp_dtype) self._assert_setitem_series_conversion(obj, val, exp, exp_dtype) @pytest.mark.parametrize( @@ -171,10 +157,10 @@ def test_setitem_series_complex128(self, val, exp_dtype): @pytest.mark.parametrize( "val,exp_dtype", [ - (1, np.int64), - (3, np.int64), - (1.1, np.float64), - (1 + 1j, np.complex128), + (1, "object"), + (3, "object"), + (1.1, "object"), + (1 + 1j, "object"), (True, np.bool_), ], ) @@ -182,22 +168,6 @@ def test_setitem_series_bool(self, val, exp_dtype, request): obj = pd.Series([True, False, True, False]) assert obj.dtype == np.bool_ - mark = None - if exp_dtype is np.int64: - exp = pd.Series([True, True, True, False]) - self._assert_setitem_series_conversion(obj, val, exp, np.bool_) - mark = pytest.mark.xfail(reason="TODO_GH12747 The result must be int") - elif exp_dtype is np.float64: - exp = pd.Series([True, True, True, False]) - self._assert_setitem_series_conversion(obj, val, exp, np.bool_) - mark = pytest.mark.xfail(reason="TODO_GH12747 The result must be float") - elif exp_dtype is np.complex128: - exp = pd.Series([True, True, True, False]) - self._assert_setitem_series_conversion(obj, val, exp, np.bool_) - mark = pytest.mark.xfail(reason="TODO_GH12747 The result must be complex") - if mark is not None: - request.node.add_marker(mark) - exp = pd.Series([True, val, True, False]) self._assert_setitem_series_conversion(obj, val, exp, exp_dtype) From fa8b3313b675a560cc74cfd64f2395ffd5f66d7e Mon Sep 17 00:00:00 2001 From: phofl Date: Tue, 10 Nov 2020 23:08:30 +0100 Subject: [PATCH 12/16] Fix remaining test --- pandas/tests/indexing/test_partial.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tests/indexing/test_partial.py b/pandas/tests/indexing/test_partial.py index 3bf37f4cade8b..5acb1d9b6c748 100644 --- a/pandas/tests/indexing/test_partial.py +++ b/pandas/tests/indexing/test_partial.py @@ -47,7 +47,6 @@ def test_partial_setting(self): with pytest.raises(IndexError, match=msg): s.iloc[3] = 5.0 - msg = "index 3 is out of bounds for axis 0 with size 3" with pytest.raises(IndexError, match=msg): s.iat[3] = 5.0 From 903be319de7dd8fe187ae45750520351a800cf55 Mon Sep 17 00:00:00 2001 From: phofl Date: Tue, 10 Nov 2020 23:41:30 +0100 Subject: [PATCH 13/16] Change if condition --- pandas/core/series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 380c04d287e0a..ffb7a766a2cd1 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1047,7 +1047,7 @@ def _set_with_engine(self, key, value): loc = self.index._engine.get_loc(key) validate_numeric_casting(self.dtype, value) dtype, _ = infer_dtype_from_scalar(value) - if is_dtype_equal(self.dtype, dtype): + if is_dtype_equal(self.dtype, dtype) or isna(value): self._values[loc] = value else: self.loc[key] = value From 566d76921d498458b090205290b96ae16e5d898b Mon Sep 17 00:00:00 2001 From: phofl Date: Thu, 12 Nov 2020 12:43:38 +0100 Subject: [PATCH 14/16] Fix if condition --- pandas/core/series.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index ffb7a766a2cd1..2b28a3cc4dfa9 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1047,10 +1047,14 @@ def _set_with_engine(self, key, value): loc = self.index._engine.get_loc(key) validate_numeric_casting(self.dtype, value) dtype, _ = infer_dtype_from_scalar(value) - if is_dtype_equal(self.dtype, dtype) or isna(value): + if is_dtype_equal(self.dtype, dtype): self._values[loc] = value else: - self.loc[key] = value + # This only raises when index contains tuples + try: + self.loc[key] = value + except KeyError: + self._values[loc] = value def _set_with(self, key, value): # other: fancy integer or otherwise From 916faa4e5407695669f03f54774b3c3b44dd4f8f Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 15 Nov 2020 18:40:24 +0100 Subject: [PATCH 15/16] Move if condition --- pandas/core/series.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 2b28a3cc4dfa9..84897c6118247 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1121,12 +1121,14 @@ def _set_value(self, label, value, takeable: bool = False): self._values[label] = value elif takeable: self.iloc[label] = value + elif not is_dtype_equal(self.dtype, dtype) and is_numeric_dtype(dtype): + loc = self.index.get_loc(label) + validate_numeric_casting(self.dtype, value) + self.loc[label] = value + return else: loc = self.index.get_loc(label) validate_numeric_casting(self.dtype, value) - if not is_dtype_equal(self.dtype, dtype) and is_numeric_dtype(dtype): - self.loc[label] = value - return self._values[loc] = value except KeyError: From 6e7ee82af85196043ea98150a463d4f05e9497ba Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 3 Jan 2021 19:51:47 +0100 Subject: [PATCH 16/16] Move whatsnew --- doc/source/whatsnew/v1.3.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 393866b92771b..beccc1e6dfe21 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -239,6 +239,7 @@ Indexing - Bug in :meth:`CategoricalIndex.get_indexer` failing to raise ``InvalidIndexError`` when non-unique (:issue:`38372`) - Bug in inserting many new columns into a :class:`DataFrame` causing incorrect subsequent indexing behavior (:issue:`38380`) - Bug in :meth:`DataFrame.iloc.__setitem__` and :meth:`DataFrame.loc.__setitem__` with mixed dtypes when setting with a dictionary value (:issue:`38335`) +- Bug in :meth:`DataFrame.at` and :meth:`Series.at` did not adjust dtype when float was assigned to integer column (:issue:`26395`, :issue:`20643`) - Bug in :meth:`DataFrame.loc` dropping levels of :class:`MultiIndex` when :class:`DataFrame` used as input has only one row (:issue:`10521`) -