Skip to content

Commit d917b33

Browse files
authored
BUG: passing a non-dict mapping to pd.concat raises a TypeError (#32953)
1 parent c6179ce commit d917b33

File tree

6 files changed

+23
-16
lines changed

6 files changed

+23
-16
lines changed

doc/source/whatsnew/v1.1.0.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,10 @@ Reshaping
386386
- :meth:`DataFrame.replace` and :meth:`Series.replace` will raise a ``TypeError`` if ``to_replace`` is not an expected type. Previously the ``replace`` would fail silently (:issue:`18634`)
387387
- Bug in :meth:`DataFrame.apply` where callback was called with :class:`Series` parameter even though ``raw=True`` requested. (:issue:`32423`)
388388
- Bug in :meth:`DataFrame.pivot_table` losing timezone information when creating a :class:`MultiIndex` level from a column with timezone-aware dtype (:issue:`32558`)
389+
- Bug in :meth:`concat` where when passing a non-dict mapping as ``objs`` would raise a ``TypeError`` (:issue:`32863`)
389390
- :meth:`DataFrame.agg` now provides more descriptive ``SpecificationError`` message when attempting to aggregating non-existant column (:issue:`32755`)
390391

392+
391393
Sparse
392394
^^^^^^
393395
- Creating a :class:`SparseArray` from timezone-aware dtype will issue a warning before dropping timezone information, instead of doing so silently (:issue:`32501`)

pandas/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def __init__(self, *args, **kwargs):
311311

312312

313313
@pytest.fixture
314-
def non_mapping_dict_subclass():
314+
def non_dict_mapping_subclass():
315315
"""
316316
Fixture for a non-mapping dictionary subclass.
317317
"""

pandas/core/reshape/concat.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Concat routines.
33
"""
44

5+
from collections import abc
56
from typing import Iterable, List, Mapping, Union, overload
67

78
import numpy as np
@@ -85,7 +86,7 @@ def concat(
8586
Parameters
8687
----------
8788
objs : a sequence or mapping of Series or DataFrame objects
88-
If a dict is passed, the sorted keys will be used as the `keys`
89+
If a mapping is passed, the sorted keys will be used as the `keys`
8990
argument, unless it is passed, in which case the values will be
9091
selected (see below). Any None objects will be dropped silently unless
9192
they are all None in which case a ValueError will be raised.
@@ -315,7 +316,7 @@ def __init__(
315316
"Only can inner (intersect) or outer (union) join the other axis"
316317
)
317318

318-
if isinstance(objs, dict):
319+
if isinstance(objs, abc.Mapping):
319320
if keys is None:
320321
keys = list(objs.keys())
321322
objs = [objs[k] for k in keys]

pandas/tests/reshape/test_concat.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,13 +1220,17 @@ def test_concat_series_partial_columns_names(self):
12201220
expected = DataFrame({0: [1, 2], 1: [1, 2], 2: [4, 5]})
12211221
tm.assert_frame_equal(result, expected)
12221222

1223-
def test_concat_dict(self):
1224-
frames = {
1225-
"foo": DataFrame(np.random.randn(4, 3)),
1226-
"bar": DataFrame(np.random.randn(4, 3)),
1227-
"baz": DataFrame(np.random.randn(4, 3)),
1228-
"qux": DataFrame(np.random.randn(4, 3)),
1229-
}
1223+
@pytest.mark.parametrize("mapping", ["mapping", "dict"])
1224+
def test_concat_mapping(self, mapping, non_dict_mapping_subclass):
1225+
constructor = dict if mapping == "dict" else non_dict_mapping_subclass
1226+
frames = constructor(
1227+
{
1228+
"foo": DataFrame(np.random.randn(4, 3)),
1229+
"bar": DataFrame(np.random.randn(4, 3)),
1230+
"baz": DataFrame(np.random.randn(4, 3)),
1231+
"qux": DataFrame(np.random.randn(4, 3)),
1232+
}
1233+
)
12301234

12311235
sorted_keys = list(frames.keys())
12321236

pandas/tests/series/test_apply.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -630,19 +630,19 @@ class DictWithoutMissing(dict):
630630
expected = Series([np.nan, np.nan, "three"])
631631
tm.assert_series_equal(result, expected)
632632

633-
def test_map_abc_mapping(self, non_mapping_dict_subclass):
633+
def test_map_abc_mapping(self, non_dict_mapping_subclass):
634634
# https://github.com/pandas-dev/pandas/issues/29733
635635
# Check collections.abc.Mapping support as mapper for Series.map
636636
s = Series([1, 2, 3])
637-
not_a_dictionary = non_mapping_dict_subclass({3: "three"})
637+
not_a_dictionary = non_dict_mapping_subclass({3: "three"})
638638
result = s.map(not_a_dictionary)
639639
expected = Series([np.nan, np.nan, "three"])
640640
tm.assert_series_equal(result, expected)
641641

642-
def test_map_abc_mapping_with_missing(self, non_mapping_dict_subclass):
642+
def test_map_abc_mapping_with_missing(self, non_dict_mapping_subclass):
643643
# https://github.com/pandas-dev/pandas/issues/29733
644644
# Check collections.abc.Mapping support as mapper for Series.map
645-
class NonDictMappingWithMissing(non_mapping_dict_subclass):
645+
class NonDictMappingWithMissing(non_dict_mapping_subclass):
646646
def __missing__(self, key):
647647
return "missing"
648648

pandas/tests/series/test_constructors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,9 +1124,9 @@ def test_constructor_dict_tuple_indexer(self):
11241124
)
11251125
tm.assert_series_equal(result, expected)
11261126

1127-
def test_constructor_mapping(self, non_mapping_dict_subclass):
1127+
def test_constructor_mapping(self, non_dict_mapping_subclass):
11281128
# GH 29788
1129-
ndm = non_mapping_dict_subclass({3: "three"})
1129+
ndm = non_dict_mapping_subclass({3: "three"})
11301130
result = Series(ndm)
11311131
expected = Series(["three"], index=[3])
11321132

0 commit comments

Comments
 (0)