From 4a4e89678678201f17a322bdac9948df40601354 Mon Sep 17 00:00:00 2001 From: RajatS Mukherjee Date: Fri, 18 Aug 2023 19:22:52 +0000 Subject: [PATCH 1/7] make arguments keyword only --- pandas/core/frame.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index c2a3d9285386e..7f07c366c3420 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1935,6 +1935,7 @@ def to_dict(self, orient: Literal["records"], into: type[dict] = ...) -> list[di def to_dict( self, + *, orient: Literal[ "dict", "list", "series", "split", "tight", "records", "index" ] = "dict", From 364cb0ec29dd3d926c00d823de1cd577ab9ba6a8 Mon Sep 17 00:00:00 2001 From: RajatS Mukherjee Date: Fri, 18 Aug 2023 20:12:40 +0000 Subject: [PATCH 2/7] added argument keywords in tests --- pandas/tests/frame/methods/test_to_dict.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pandas/tests/frame/methods/test_to_dict.py b/pandas/tests/frame/methods/test_to_dict.py index 1118ad88d5092..e39b457cc6e05 100644 --- a/pandas/tests/frame/methods/test_to_dict.py +++ b/pandas/tests/frame/methods/test_to_dict.py @@ -99,19 +99,19 @@ def test_to_dict(self, mapping): for k2, v2 in v.items(): assert v2 == recons_data[k][k2] - recons_data = DataFrame(test_data).to_dict("list", mapping) + recons_data = DataFrame(test_data).to_dict(orient="list", into=mapping) for k, v in test_data.items(): for k2, v2 in v.items(): assert v2 == recons_data[k][int(k2) - 1] - recons_data = DataFrame(test_data).to_dict("series", mapping) + recons_data = DataFrame(test_data).to_dict(orient="series", into=mapping) for k, v in test_data.items(): for k2, v2 in v.items(): assert v2 == recons_data[k][k2] - recons_data = DataFrame(test_data).to_dict("split", mapping) + recons_data = DataFrame(test_data).to_dict(orient="split", into=mapping) expected_split = { "columns": ["A", "B"], "index": ["1", "2", "3"], @@ -119,7 +119,7 @@ def test_to_dict(self, mapping): } tm.assert_dict_equal(recons_data, expected_split) - recons_data = DataFrame(test_data).to_dict("records", mapping) + recons_data = DataFrame(test_data).to_dict(orient="records", into=mapping) expected_records = [ {"A": 1.0, "B": "1"}, {"A": 2.0, "B": "2"}, @@ -131,7 +131,7 @@ def test_to_dict(self, mapping): tm.assert_dict_equal(left, right) # GH#10844 - recons_data = DataFrame(test_data).to_dict("index") + recons_data = DataFrame(test_data).to_dict(orient="index") for k, v in test_data.items(): for k2, v2 in v.items(): @@ -139,7 +139,7 @@ def test_to_dict(self, mapping): df = DataFrame(test_data) df["duped"] = df[df.columns[0]] - recons_data = df.to_dict("index") + recons_data = df.to_dict(orient="index") comp_data = test_data.copy() comp_data["duped"] = comp_data[df.columns[0]] for k, v in comp_data.items(): @@ -254,14 +254,14 @@ def test_to_dict_index_dtypes(self, into, expected): def test_to_dict_numeric_names(self): # GH#24940 df = DataFrame({str(i): [i] for i in range(5)}) - result = set(df.to_dict("records")[0].keys()) + result = set(df.to_dict(orient="records")[0].keys()) expected = set(df.columns) assert result == expected def test_to_dict_wide(self): # GH#24939 df = DataFrame({(f"A_{i:d}"): [i] for i in range(256)}) - result = df.to_dict("records")[0] + result = df.to_dict(orient="records")[0] expected = {f"A_{i:d}": i for i in range(256)} assert result == expected @@ -310,7 +310,7 @@ def test_to_dict_scalar_constructor_orient_dtype(self, data, expected_dtype): def test_to_dict_mixed_numeric_frame(self): # GH 12859 df = DataFrame({"a": [1.0], "b": [9.0]}) - result = df.reset_index().to_dict("records") + result = df.reset_index().to_dict(orient="records") expected = [{"index": 0, "a": 1.0, "b": 9.0}] assert result == expected @@ -395,7 +395,7 @@ def test_to_dict_returns_native_types(self, orient, data, expected_types): # GH 46751 # Tests we get back native types for all orient types df = DataFrame(data) - result = df.to_dict(orient) + result = df.to_dict(orient=orient) if orient == "dict": assertion_iterator = ( (i, key, value) From a644bcaf050939e887ac83d4fa038a620e9c8efa Mon Sep 17 00:00:00 2001 From: RajatS Mukherjee Date: Fri, 18 Aug 2023 20:16:34 +0000 Subject: [PATCH 3/7] modified overloaded methods --- pandas/core/frame.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 7f07c366c3420..67b0f09c202f5 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1924,13 +1924,16 @@ def _create_data_for_split_and_tight_to_dict( @overload def to_dict( self, + *, orient: Literal["dict", "list", "series", "split", "tight", "index"] = ..., into: type[dict] = ..., ) -> dict: ... @overload - def to_dict(self, orient: Literal["records"], into: type[dict] = ...) -> list[dict]: + def to_dict( + self, *, orient: Literal["records"], into: type[dict] = ... + ) -> list[dict]: ... def to_dict( From fce74cfb9692ac575c09e07cd3dbba7a298e746d Mon Sep 17 00:00:00 2001 From: RajatS Mukherjee Date: Sat, 19 Aug 2023 05:58:25 +0000 Subject: [PATCH 4/7] fixed docs --- pandas/core/frame.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 67b0f09c202f5..258847ce23f55 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2009,7 +2009,7 @@ def to_dict( You can specify the return orientation. - >>> df.to_dict('series') + >>> df.to_dict(orient='series') {'col1': row1 1 row2 2 Name: col1, dtype: int64, @@ -2017,17 +2017,17 @@ def to_dict( row2 0.75 Name: col2, dtype: float64} - >>> df.to_dict('split') + >>> df.to_dict(orient='split') {'index': ['row1', 'row2'], 'columns': ['col1', 'col2'], 'data': [[1, 0.5], [2, 0.75]]} - >>> df.to_dict('records') + >>> df.to_dict(orient='records') [{'col1': 1, 'col2': 0.5}, {'col1': 2, 'col2': 0.75}] - >>> df.to_dict('index') + >>> df.to_dict(orient='index') {'row1': {'col1': 1, 'col2': 0.5}, 'row2': {'col1': 2, 'col2': 0.75}} - >>> df.to_dict('tight') + >>> df.to_dict(orient='tight') {'index': ['row1', 'row2'], 'columns': ['col1', 'col2'], 'data': [[1, 0.5], [2, 0.75]], 'index_names': [None], 'column_names': [None]} @@ -2041,7 +2041,7 @@ def to_dict( If you want a `defaultdict`, you need to initialize it: >>> dd = defaultdict(list) - >>> df.to_dict('records', into=dd) + >>> df.to_dict(orient='records', into=dd) [defaultdict(, {'col1': 1, 'col2': 0.5}), defaultdict(, {'col1': 2, 'col2': 0.75})] """ From 45a51d941fbdab0a031962112c8e00a0450a9261 Mon Sep 17 00:00:00 2001 From: RajatS Mukherjee Date: Sat, 19 Aug 2023 09:02:38 +0000 Subject: [PATCH 5/7] added whatsnew --- doc/source/whatsnew/v2.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index b90563ba43d83..0a4692b64cf55 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -92,6 +92,7 @@ Other API changes Deprecations ~~~~~~~~~~~~ +- Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_dict`. (:issue:`54229`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_hdf` except ``path_or_buf``. (:issue:`54229`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_json` except ``path_or_buf``. (:issue:`54229`) - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_latex` except ``buf``. (:issue:`54229`) From 45e413f065013430a1d31ba56d0fa857de4efd38 Mon Sep 17 00:00:00 2001 From: RajatS Mukherjee Date: Mon, 21 Aug 2023 10:30:36 +0000 Subject: [PATCH 6/7] made orient as positional --- pandas/core/frame.py | 18 +++++++++--------- pandas/tests/frame/methods/test_to_dict.py | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index cb6f030544f5b..a5fdf0947ebd7 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1924,24 +1924,24 @@ def _create_data_for_split_and_tight_to_dict( @overload def to_dict( self, - *, orient: Literal["dict", "list", "series", "split", "tight", "index"] = ..., + *, into: type[dict] = ..., ) -> dict: ... @overload def to_dict( - self, *, orient: Literal["records"], into: type[dict] = ... + self, orient: Literal["records"], *, into: type[dict] = ... ) -> list[dict]: ... def to_dict( self, - *, orient: Literal[ "dict", "list", "series", "split", "tight", "records", "index" ] = "dict", + *, into: type[dict] = dict, index: bool = True, ) -> dict | list[dict]: @@ -2009,7 +2009,7 @@ def to_dict( You can specify the return orientation. - >>> df.to_dict(orient='series') + >>> df.to_dict('series') {'col1': row1 1 row2 2 Name: col1, dtype: int64, @@ -2017,17 +2017,17 @@ def to_dict( row2 0.75 Name: col2, dtype: float64} - >>> df.to_dict(orient='split') + >>> df.to_dict('split') {'index': ['row1', 'row2'], 'columns': ['col1', 'col2'], 'data': [[1, 0.5], [2, 0.75]]} - >>> df.to_dict(orient='records') + >>> df.to_dict('records') [{'col1': 1, 'col2': 0.5}, {'col1': 2, 'col2': 0.75}] - >>> df.to_dict(orient='index') + >>> df.to_dict('index') {'row1': {'col1': 1, 'col2': 0.5}, 'row2': {'col1': 2, 'col2': 0.75}} - >>> df.to_dict(orient='tight') + >>> df.to_dict('tight') {'index': ['row1', 'row2'], 'columns': ['col1', 'col2'], 'data': [[1, 0.5], [2, 0.75]], 'index_names': [None], 'column_names': [None]} @@ -2041,7 +2041,7 @@ def to_dict( If you want a `defaultdict`, you need to initialize it: >>> dd = defaultdict(list) - >>> df.to_dict(orient='records', into=dd) + >>> df.to_dict('records', into=dd) [defaultdict(, {'col1': 1, 'col2': 0.5}), defaultdict(, {'col1': 2, 'col2': 0.75})] """ diff --git a/pandas/tests/frame/methods/test_to_dict.py b/pandas/tests/frame/methods/test_to_dict.py index e39b457cc6e05..ab3dc42bb580e 100644 --- a/pandas/tests/frame/methods/test_to_dict.py +++ b/pandas/tests/frame/methods/test_to_dict.py @@ -99,19 +99,19 @@ def test_to_dict(self, mapping): for k2, v2 in v.items(): assert v2 == recons_data[k][k2] - recons_data = DataFrame(test_data).to_dict(orient="list", into=mapping) + recons_data = DataFrame(test_data).to_dict("list", into=mapping) for k, v in test_data.items(): for k2, v2 in v.items(): assert v2 == recons_data[k][int(k2) - 1] - recons_data = DataFrame(test_data).to_dict(orient="series", into=mapping) + recons_data = DataFrame(test_data).to_dict("series", into=mapping) for k, v in test_data.items(): for k2, v2 in v.items(): assert v2 == recons_data[k][k2] - recons_data = DataFrame(test_data).to_dict(orient="split", into=mapping) + recons_data = DataFrame(test_data).to_dict("split", into=mapping) expected_split = { "columns": ["A", "B"], "index": ["1", "2", "3"], @@ -119,7 +119,7 @@ def test_to_dict(self, mapping): } tm.assert_dict_equal(recons_data, expected_split) - recons_data = DataFrame(test_data).to_dict(orient="records", into=mapping) + recons_data = DataFrame(test_data).to_dict("records", into=mapping) expected_records = [ {"A": 1.0, "B": "1"}, {"A": 2.0, "B": "2"}, @@ -131,7 +131,7 @@ def test_to_dict(self, mapping): tm.assert_dict_equal(left, right) # GH#10844 - recons_data = DataFrame(test_data).to_dict(orient="index") + recons_data = DataFrame(test_data).to_dict("index") for k, v in test_data.items(): for k2, v2 in v.items(): @@ -139,7 +139,7 @@ def test_to_dict(self, mapping): df = DataFrame(test_data) df["duped"] = df[df.columns[0]] - recons_data = df.to_dict(orient="index") + recons_data = df.to_dict("index") comp_data = test_data.copy() comp_data["duped"] = comp_data[df.columns[0]] for k, v in comp_data.items(): @@ -254,14 +254,14 @@ def test_to_dict_index_dtypes(self, into, expected): def test_to_dict_numeric_names(self): # GH#24940 df = DataFrame({str(i): [i] for i in range(5)}) - result = set(df.to_dict(orient="records")[0].keys()) + result = set(df.to_dict("records")[0].keys()) expected = set(df.columns) assert result == expected def test_to_dict_wide(self): # GH#24939 df = DataFrame({(f"A_{i:d}"): [i] for i in range(256)}) - result = df.to_dict(orient="records")[0] + result = df.to_dict("records")[0] expected = {f"A_{i:d}": i for i in range(256)} assert result == expected @@ -310,7 +310,7 @@ def test_to_dict_scalar_constructor_orient_dtype(self, data, expected_dtype): def test_to_dict_mixed_numeric_frame(self): # GH 12859 df = DataFrame({"a": [1.0], "b": [9.0]}) - result = df.reset_index().to_dict(orient="records") + result = df.reset_index().to_dict("records") expected = [{"index": 0, "a": 1.0, "b": 9.0}] assert result == expected @@ -395,7 +395,7 @@ def test_to_dict_returns_native_types(self, orient, data, expected_types): # GH 46751 # Tests we get back native types for all orient types df = DataFrame(data) - result = df.to_dict(orient=orient) + result = df.to_dict(orient) if orient == "dict": assertion_iterator = ( (i, key, value) From 0940b3a204e17a47ff1c1d80b69d37ae502938ce Mon Sep 17 00:00:00 2001 From: RajatS Mukherjee Date: Mon, 21 Aug 2023 19:48:02 +0000 Subject: [PATCH 7/7] added test and deprecation --- pandas/core/frame.py | 9 ++++----- pandas/tests/frame/methods/test_to_dict.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 825657b985cbb..23355d9b6c42f 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1925,23 +1925,22 @@ def _create_data_for_split_and_tight_to_dict( def to_dict( self, orient: Literal["dict", "list", "series", "split", "tight", "index"] = ..., - *, into: type[dict] = ..., ) -> dict: ... @overload - def to_dict( - self, orient: Literal["records"], *, into: type[dict] = ... - ) -> list[dict]: + def to_dict(self, orient: Literal["records"], into: type[dict] = ...) -> list[dict]: ... + @deprecate_nonkeyword_arguments( + version="3.0", allowed_args=["self", "orient"], name="to_dict" + ) def to_dict( self, orient: Literal[ "dict", "list", "series", "split", "tight", "records", "index" ] = "dict", - *, into: type[dict] = dict, index: bool = True, ) -> dict | list[dict]: diff --git a/pandas/tests/frame/methods/test_to_dict.py b/pandas/tests/frame/methods/test_to_dict.py index ab3dc42bb580e..7bb9518f9b0f9 100644 --- a/pandas/tests/frame/methods/test_to_dict.py +++ b/pandas/tests/frame/methods/test_to_dict.py @@ -494,3 +494,13 @@ def test_to_dict_masked_native_python(self): df = DataFrame({"a": Series([1, NA], dtype="Int64"), "B": 1}) result = df.to_dict(orient="records") assert isinstance(result[0]["a"], int) + + def test_to_dict_pos_args_deprecation(self): + # GH-54229 + df = DataFrame({"a": [1, 2, 3]}) + msg = ( + r"Starting with pandas version 3.0 all arguments of to_dict except for the " + r"argument 'orient' will be keyword-only." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + df.to_dict("records", {})