diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 193356a46a6ea..9e48e8bb35838 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -190,6 +190,7 @@ representation of :class:`DataFrame` objects (:issue:`4889`). Other enhancements ^^^^^^^^^^^^^^^^^^ +- :meth:`concat` will preserve the ``attrs`` when it is the same for all objects and discard the ``attrs`` when they are different. (:issue:`41828`) - :class:`DataFrameGroupBy` operations with ``as_index=False`` now correctly retain ``ExtensionDtype`` dtypes for columns being grouped on (:issue:`41373`) - Add support for assigning values to ``by`` argument in :meth:`DataFrame.plot.hist` and :meth:`DataFrame.plot.box` (:issue:`15079`) - :meth:`Series.sample`, :meth:`DataFrame.sample`, and :meth:`.GroupBy.sample` now accept a ``np.random.Generator`` as input to ``random_state``. A generator will be more performant, especially with ``replace=False`` (:issue:`38100`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 4aff7acc4c6fb..7f18399160cad 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -5522,6 +5522,12 @@ def __finalize__( object.__setattr__(self, name, getattr(other, name, None)) if method == "concat": + attrs = other.objs[0].attrs + check_attrs = all(objs.attrs == attrs for objs in other.objs[1:]) + if check_attrs: + for name in attrs: + self.attrs[name] = attrs[name] + allows_duplicate_labels = all( x.flags.allows_duplicate_labels for x in other.objs ) diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index 135e8cc7b7aba..f27e92a55268f 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -758,7 +758,6 @@ def test_groupby_finalize(obj, method): "method", [ lambda x: x.agg(["sum", "count"]), - lambda x: x.transform(lambda y: y), lambda x: x.apply(lambda y: y), lambda x: x.agg("std"), lambda x: x.agg("var"), diff --git a/pandas/tests/reshape/concat/test_concat.py b/pandas/tests/reshape/concat/test_concat.py index 676571e419a1a..c4b32371042b3 100644 --- a/pandas/tests/reshape/concat/test_concat.py +++ b/pandas/tests/reshape/concat/test_concat.py @@ -698,3 +698,49 @@ def test_concat_posargs_deprecation(): result = concat([df, df2], 0) expected = DataFrame([[1, 2, 3], [4, 5, 6]], index=["a", "b"]) tm.assert_frame_equal(result, expected) + + +@pytest.mark.parametrize( + "data", + [ + Series(data=[1, 2]), + DataFrame( + data={ + "col1": [1, 2], + } + ), + DataFrame(dtype=float), + Series(dtype=float), + ], +) +def test_concat_drop_attrs(data): + # GH#41828 + df1 = data.copy() + df1.attrs = {1: 1} + df2 = data.copy() + df2.attrs = {1: 2} + df = concat([df1, df2]) + assert len(df.attrs) == 0 + + +@pytest.mark.parametrize( + "data", + [ + Series(data=[1, 2]), + DataFrame( + data={ + "col1": [1, 2], + } + ), + DataFrame(dtype=float), + Series(dtype=float), + ], +) +def test_concat_retain_attrs(data): + # GH#41828 + df1 = data.copy() + df1.attrs = {1: 1} + df2 = data.copy() + df2.attrs = {1: 1} + df = concat([df1, df2]) + assert df.attrs[1] == 1