Skip to content

Commit 30cbdfe

Browse files
committed
Support dataframe creation from mapping of mapping
1 parent 9400c0d commit 30cbdfe

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

pandas/core/frame.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1751,7 +1751,7 @@ def __rmatmul__(self, other) -> DataFrame:
17511751
@classmethod
17521752
def from_dict(
17531753
cls,
1754-
data: dict,
1754+
data: Mapping,
17551755
orient: FromDictOrient = "columns",
17561756
dtype: Dtype | None = None,
17571757
columns: Axes | None = None,
@@ -1764,7 +1764,7 @@ def from_dict(
17641764
17651765
Parameters
17661766
----------
1767-
data : dict
1767+
data : Mapping
17681768
Of the form {field : array-like} or {field : dict}.
17691769
orient : {'columns', 'index', 'tight'}, default 'columns'
17701770
The "orientation" of the data. If the keys of the passed dict

pandas/core/internals/construction.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@
7777
if TYPE_CHECKING:
7878
from collections.abc import (
7979
Hashable,
80-
Mapping,
8180
Sequence,
8281
)
8382

@@ -348,7 +347,7 @@ def _check_values_indices_shape_match(
348347

349348

350349
def dict_to_mgr(
351-
data: Mapping,
350+
data: abc.Mapping,
352351
index,
353352
columns,
354353
*,
@@ -537,7 +536,7 @@ def _homogenize(
537536
refs.append(val._references)
538537
val = val._values
539538
else:
540-
if isinstance(val, dict):
539+
if isinstance(val, abc.Mapping):
541540
# GH#41785 this _should_ be equivalent to (but faster than)
542541
# val = Series(val, index=index)._values
543542
if oindex is None:
@@ -579,7 +578,7 @@ def _extract_index(data) -> Index:
579578
if isinstance(val, ABCSeries):
580579
have_series = True
581580
indexes.append(val.index)
582-
elif isinstance(val, dict):
581+
elif isinstance(val, abc.Mapping):
583582
have_dicts = True
584583
indexes.append(list(val.keys()))
585584
elif is_list_like(val) and getattr(val, "ndim", 1) == 1:

pandas/tests/frame/constructors/test_from_dict.py

+12
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ def test_constructor_from_mapping(self):
146146
result = DataFrame.from_dict(DictWrapper({"A": idx, "B": dr}))
147147
tm.assert_frame_equal(result, expected)
148148

149+
def test_constructor_from_mapping_of_mapping(self):
150+
data = DictWrapper(
151+
{
152+
"a": DictWrapper({"x": 1, "y": 2}),
153+
"b": DictWrapper({"x": 3, "y": 4}),
154+
"c": DictWrapper({"x": 5, "y": 6}),
155+
}
156+
)
157+
expected = DataFrame(data)
158+
result = DataFrame.from_dict(data)
159+
tm.assert_frame_equal(result, expected)
160+
149161
def test_from_dict_columns_parameter(self):
150162
# GH#18529
151163
# Test new columns parameter for from_dict that was added to make

pandas/tests/frame/test_constructors.py

+25
Original file line numberDiff line numberDiff line change
@@ -2916,6 +2916,31 @@ def test_from_mapping(self):
29162916
tm.assert_series_equal(df["A"], Series(idx, name="A"))
29172917
tm.assert_series_equal(df["B"], Series(dr, name="B"))
29182918

2919+
def test_from_mapping_of_dict(self):
2920+
data = {
2921+
"a": {"x": 1, "y": 2},
2922+
"b": {"x": 3, "y": 4},
2923+
"c": {"x": 5, "y": 6},
2924+
}
2925+
expected = DataFrame(data)
2926+
2927+
# construction
2928+
result = DataFrame(DictWrapper(data))
2929+
tm.assert_frame_equal(result, expected)
2930+
2931+
def test_from_mapping_of_mapping(self):
2932+
data = {
2933+
"a": {"x": 1, "y": 2},
2934+
"b": {"x": 3, "y": 4},
2935+
"c": {"x": 5, "y": 6},
2936+
}
2937+
expected = DataFrame(data)
2938+
2939+
# construction
2940+
wrapped = DictWrapper({k: DictWrapper(v) for k, v in data.items()})
2941+
result = DataFrame(wrapped)
2942+
tm.assert_frame_equal(result, expected)
2943+
29192944
def test_from_mapping_list(self):
29202945
idx = Index(date_range("20130101", periods=3, tz="US/Eastern"), name="foo")
29212946
dr = date_range("20130110", periods=3)

0 commit comments

Comments
 (0)