From 233bea8217e59c5fc0c35a5637b384497cc8b11f Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 14:23:52 +0100 Subject: [PATCH 01/10] Better support for UserDict on constructor --- pandas/core/frame.py | 4 ++-- pandas/tests/frame/constructors/test_from_dict.py | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 8fcb91c846826..8d7a86743abfc 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -703,7 +703,7 @@ def __init__( raise ValueError("columns cannot be a set") if copy is None: - if isinstance(data, dict): + if isinstance(data, abc.MutableMapping): # retain pre-GH#38939 default behavior copy = True elif ( @@ -732,7 +732,7 @@ def __init__( data, axes={"index": index, "columns": columns}, dtype=dtype, copy=copy ) - elif isinstance(data, dict): + elif isinstance(data, abc.MutableMapping): # GH#38939 de facto copy defaults to False only in non-dict cases mgr = dict_to_mgr(data, index, columns, dtype=dtype, copy=copy, typ=manager) elif isinstance(data, ma.MaskedArray): diff --git a/pandas/tests/frame/constructors/test_from_dict.py b/pandas/tests/frame/constructors/test_from_dict.py index d78924ff9d046..c4ea2be66a2f9 100644 --- a/pandas/tests/frame/constructors/test_from_dict.py +++ b/pandas/tests/frame/constructors/test_from_dict.py @@ -1,4 +1,4 @@ -from collections import OrderedDict +from collections import OrderedDict, UserDict import numpy as np import pytest @@ -200,3 +200,15 @@ def test_from_dict_orient_invalid(self): ) with pytest.raises(ValueError, match=msg): DataFrame.from_dict({"foo": 1, "baz": 3, "bar": 2}, orient="abc") + + def test_constructor_user_dict(self): + class CustomUserDict(UserDict): + pass + + d_1 = CustomUserDict(foo=1, bar=2) + df_1 = DataFrame(d_1, index=['a']) + + d_2 = {'foo': 1, 'bar': 2} + df_2 = DataFrame(d_2, index=['a']) + + tm.assert_frame_equal(df_1, df_2) From 0a277b10abb69f88ef39e0b67495be2d9fb622aa Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 14:31:15 +0100 Subject: [PATCH 02/10] isort --- pandas/tests/frame/constructors/test_from_dict.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pandas/tests/frame/constructors/test_from_dict.py b/pandas/tests/frame/constructors/test_from_dict.py index c4ea2be66a2f9..942dc177a0a4a 100644 --- a/pandas/tests/frame/constructors/test_from_dict.py +++ b/pandas/tests/frame/constructors/test_from_dict.py @@ -1,4 +1,7 @@ -from collections import OrderedDict, UserDict +from collections import ( + OrderedDict, + UserDict +) import numpy as np import pytest From dd0a284d9a18e317fc681ddf3a219f96d383b8af Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 14:31:36 +0100 Subject: [PATCH 03/10] trailing comma --- pandas/tests/frame/constructors/test_from_dict.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/frame/constructors/test_from_dict.py b/pandas/tests/frame/constructors/test_from_dict.py index 942dc177a0a4a..e8f7328a397a0 100644 --- a/pandas/tests/frame/constructors/test_from_dict.py +++ b/pandas/tests/frame/constructors/test_from_dict.py @@ -1,6 +1,6 @@ from collections import ( OrderedDict, - UserDict + UserDict, ) import numpy as np From 54760e3625eda7aca8fad04aac289afbe2d70d45 Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 14:39:07 +0100 Subject: [PATCH 04/10] black --- pandas/tests/frame/constructors/test_from_dict.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tests/frame/constructors/test_from_dict.py b/pandas/tests/frame/constructors/test_from_dict.py index e8f7328a397a0..64743113f6cf3 100644 --- a/pandas/tests/frame/constructors/test_from_dict.py +++ b/pandas/tests/frame/constructors/test_from_dict.py @@ -209,9 +209,9 @@ class CustomUserDict(UserDict): pass d_1 = CustomUserDict(foo=1, bar=2) - df_1 = DataFrame(d_1, index=['a']) + df_1 = DataFrame(d_1, index=["a"]) - d_2 = {'foo': 1, 'bar': 2} - df_2 = DataFrame(d_2, index=['a']) + d_2 = {"foo": 1, "bar": 2} + df_2 = DataFrame(d_2, index=["a"]) tm.assert_frame_equal(df_1, df_2) From 05c14335b807bbddb0397ded26ad2d5872107239 Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 15:29:13 +0100 Subject: [PATCH 05/10] FIX: type hint --- pandas/core/internals/construction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/internals/construction.py b/pandas/core/internals/construction.py index 6f30bc650aa36..739338d07dc06 100644 --- a/pandas/core/internals/construction.py +++ b/pandas/core/internals/construction.py @@ -421,7 +421,7 @@ def _check_values_indices_shape_match( def dict_to_mgr( - data: dict, + data: abc.MutableMapping, index, columns, *, From 7457cc333603b13e78f4c3927e8ff9af7267fe87 Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 17:21:10 +0100 Subject: [PATCH 06/10] entry on whats new on v2.2.0 --- doc/source/whatsnew/v2.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index 07be496a95adc..7ef447ac89bc1 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -29,7 +29,7 @@ enhancement2 Other enhancements ^^^^^^^^^^^^^^^^^^ - DataFrame.apply now allows the usage of numba (via ``engine="numba"``) to JIT compile the passed function, allowing for potential speedups (:issue:`54666`) -- +- It is now possible to pass an instance of a `collections.UserDict` subclass to initialize a DataFrame. The expected behaviour is the same as if you pass a `dict` (:issue:`55109`) .. --------------------------------------------------------------------------- .. _whatsnew_220.notable_bug_fixes: From 8990a0522673fb4b29ea52e4a1693d4fce40d523 Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 18:01:41 +0100 Subject: [PATCH 07/10] Mapping better than MutableMapping here --- pandas/core/frame.py | 4 ++-- pandas/core/internals/construction.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 8d7a86743abfc..b6d552ba1f6dc 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -703,7 +703,7 @@ def __init__( raise ValueError("columns cannot be a set") if copy is None: - if isinstance(data, abc.MutableMapping): + if isinstance(data, abc.Mapping): # retain pre-GH#38939 default behavior copy = True elif ( @@ -732,7 +732,7 @@ def __init__( data, axes={"index": index, "columns": columns}, dtype=dtype, copy=copy ) - elif isinstance(data, abc.MutableMapping): + elif isinstance(data, abc.Mapping): # GH#38939 de facto copy defaults to False only in non-dict cases mgr = dict_to_mgr(data, index, columns, dtype=dtype, copy=copy, typ=manager) elif isinstance(data, ma.MaskedArray): diff --git a/pandas/core/internals/construction.py b/pandas/core/internals/construction.py index 739338d07dc06..61afc7784d94a 100644 --- a/pandas/core/internals/construction.py +++ b/pandas/core/internals/construction.py @@ -421,7 +421,7 @@ def _check_values_indices_shape_match( def dict_to_mgr( - data: abc.MutableMapping, + data: abc.Mapping, index, columns, *, From 8f18470a29eee95911fc8d0cd24925d91970937f Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 18:41:48 +0100 Subject: [PATCH 08/10] fix: rst lint --- doc/source/whatsnew/v2.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index 7ef447ac89bc1..99b22ade00d7f 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -29,7 +29,7 @@ enhancement2 Other enhancements ^^^^^^^^^^^^^^^^^^ - DataFrame.apply now allows the usage of numba (via ``engine="numba"``) to JIT compile the passed function, allowing for potential speedups (:issue:`54666`) -- It is now possible to pass an instance of a `collections.UserDict` subclass to initialize a DataFrame. The expected behaviour is the same as if you pass a `dict` (:issue:`55109`) +- It is now possible to pass an instance of a ``collections.UserDict`` subclass to initialize a DataFrame. The expected behaviour is the same as if you pass a `dict` (:issue:`55109`) .. --------------------------------------------------------------------------- .. _whatsnew_220.notable_bug_fixes: From 6868cb0dab6640eab2f75df67b22f3139f06226b Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Tue, 12 Sep 2023 19:02:34 +0100 Subject: [PATCH 09/10] fix: rst lint --- doc/source/whatsnew/v2.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index 99b22ade00d7f..a9a797a1c79c6 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -29,7 +29,7 @@ enhancement2 Other enhancements ^^^^^^^^^^^^^^^^^^ - DataFrame.apply now allows the usage of numba (via ``engine="numba"``) to JIT compile the passed function, allowing for potential speedups (:issue:`54666`) -- It is now possible to pass an instance of a ``collections.UserDict`` subclass to initialize a DataFrame. The expected behaviour is the same as if you pass a `dict` (:issue:`55109`) +- It is now possible to pass an instance of a ``collections.UserDict`` subclass to initialize a DataFrame. The expected behaviour is the same as if you pass a ``dict`` (:issue:`55109`) .. --------------------------------------------------------------------------- .. _whatsnew_220.notable_bug_fixes: From 4d72bd47ad3e2bbf7d42ef034b2d5091cafd278f Mon Sep 17 00:00:00 2001 From: Gabriel Reis Date: Fri, 15 Sep 2023 08:19:04 +0100 Subject: [PATCH 10/10] Update doc/source/whatsnew/v2.2.0.rst Co-authored-by: Marcelo Duarte Trevisani --- doc/source/whatsnew/v2.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index a9a797a1c79c6..54735b4ffed45 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -29,7 +29,7 @@ enhancement2 Other enhancements ^^^^^^^^^^^^^^^^^^ - DataFrame.apply now allows the usage of numba (via ``engine="numba"``) to JIT compile the passed function, allowing for potential speedups (:issue:`54666`) -- It is now possible to pass an instance of a ``collections.UserDict`` subclass to initialize a DataFrame. The expected behaviour is the same as if you pass a ``dict`` (:issue:`55109`) +- It is now possible to pass an object that either directly inherits from ``abc.Mapping`` or has it in its inheritance chain to initialize a DataFrame. The expected behaviour is the same as if you pass a ``dict`` object. (:issue:`55109`) .. --------------------------------------------------------------------------- .. _whatsnew_220.notable_bug_fixes: