Skip to content

Commit bb45e66

Browse files
committed
Use a class instead of a tuple to make values opaque to Pandas.
The "tuple trick" to force Pandas to treat the return value of an apply func as a scalar stopped working between Pandas 1.0.5 and 1.1.0: pandas-dev/pandas#35518
1 parent 1b5d401 commit bb45e66

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

loudspeakerexplorer/pd.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,27 @@ def index_as_columns(df):
4848
return df.index.to_frame().reset_index(drop=True)
4949

5050

51+
class _OpaqueContainer:
52+
# A trivial class that acts as a container for some value. The use case is
53+
# to force Pandas to treat the value as a scalar and not change its behavior
54+
# depending on its type (e.g. DataFrame.apply(func) behaves very differently
55+
# when func returns something that looks like a collection).
56+
#
57+
# In Pandas 1.0.5, wrapping the value inside a single-element tuple would do
58+
# the trick, but in 1.1.0 that doesn't work anymore, hence this class.
59+
# https://github.com/pandas-dev/pandas/issues/35518
60+
61+
def __init__(self, value):
62+
self.value = value
63+
64+
5165
def rollup(df, func, *kargs, **kwargs):
5266
# Similar to df.apply(), with the subtle difference that if `func` returns
5367
# a collection, the collection type is preserved instead of being expanded.
68+
5469
return (df
55-
.apply(func=lambda df: (func(df),), *kargs, **kwargs)
56-
.apply(lambda value: value[0]))
70+
.apply(func=lambda df: _OpaqueContainer(func(df)), *kargs, **kwargs)
71+
.apply(lambda container: container.value))
5772

5873

5974
def implode(df):
@@ -74,8 +89,9 @@ def implode(df):
7489
.groupby(level=list(range(0, df.index.nlevels)))
7590
# Wrap in a tuple to avoid Pandas interpreting the return value
7691
# as a list of rows.
77-
.apply(lambda df: df.aggregate(lambda column: (list(column.values),)))
78-
.applymap(lambda column: column[0]))
92+
.apply(lambda df: df.aggregate(
93+
lambda column: _OpaqueContainer(list(column.values))))
94+
.applymap(lambda container: container.value))
7995

8096

8197
def join_index(df, labels):

0 commit comments

Comments
 (0)