Skip to content

Commit c21d32f

Browse files
meeseeksmachineTomAugspurger
authored andcommitted
Backport PR #25069: REGR: rename_axis with None should remove axis name (#25079)
1 parent 4f865c5 commit c21d32f

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

doc/source/whatsnew/v0.24.1.rst

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Fixed Regressions
2525
- Fixed regression in :func:`read_sql` when passing certain queries with MySQL/pymysql (:issue:`24988`).
2626
- Fixed regression in :class:`Index.intersection` incorrectly sorting the values by default (:issue:`24959`).
2727
- Fixed regression in :func:`merge` when merging an empty ``DataFrame`` with multiple timezone-aware columns on one of the timezone-aware columns (:issue:`25014`).
28+
- Fixed regression in :meth:`Series.rename_axis` and :meth:`DataFrame.rename_axis` where passing ``None`` failed to remove the axis name (:issue:`25034`)
2829

2930
.. _whatsnew_0241.enhancements:
3031

pandas/core/generic.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@
6161
by : str or list of str
6262
Name or list of names to sort by""")
6363

64+
# sentinel value to use as kwarg in place of None when None has special meaning
65+
# and needs to be distinguished from a user explicitly passing None.
66+
sentinel = object()
67+
6468

6569
def _single_replace(self, to_replace, method, inplace, limit):
6670
"""
@@ -290,11 +294,16 @@ def _construct_axes_dict_for_slice(self, axes=None, **kwargs):
290294
d.update(kwargs)
291295
return d
292296

293-
def _construct_axes_from_arguments(self, args, kwargs, require_all=False):
297+
def _construct_axes_from_arguments(
298+
self, args, kwargs, require_all=False, sentinel=None):
294299
"""Construct and returns axes if supplied in args/kwargs.
295300
296301
If require_all, raise if all axis arguments are not supplied
297302
return a tuple of (axes, kwargs).
303+
304+
sentinel specifies the default parameter when an axis is not
305+
supplied; useful to distinguish when a user explicitly passes None
306+
in scenarios where None has special meaning.
298307
"""
299308

300309
# construct the args
@@ -322,7 +331,7 @@ def _construct_axes_from_arguments(self, args, kwargs, require_all=False):
322331
raise TypeError("not enough/duplicate arguments "
323332
"specified!")
324333

325-
axes = {a: kwargs.pop(a, None) for a in self._AXIS_ORDERS}
334+
axes = {a: kwargs.pop(a, sentinel) for a in self._AXIS_ORDERS}
326335
return axes, kwargs
327336

328337
@classmethod
@@ -1089,7 +1098,7 @@ def rename(self, *args, **kwargs):
10891098

10901099
@rewrite_axis_style_signature('mapper', [('copy', True),
10911100
('inplace', False)])
1092-
def rename_axis(self, mapper=None, **kwargs):
1101+
def rename_axis(self, mapper=sentinel, **kwargs):
10931102
"""
10941103
Set the name of the axis for the index or columns.
10951104
@@ -1218,7 +1227,8 @@ class name
12181227
cat 4 0
12191228
monkey 2 2
12201229
"""
1221-
axes, kwargs = self._construct_axes_from_arguments((), kwargs)
1230+
axes, kwargs = self._construct_axes_from_arguments(
1231+
(), kwargs, sentinel=sentinel)
12221232
copy = kwargs.pop('copy', True)
12231233
inplace = kwargs.pop('inplace', False)
12241234
axis = kwargs.pop('axis', 0)
@@ -1231,7 +1241,7 @@ class name
12311241

12321242
inplace = validate_bool_kwarg(inplace, 'inplace')
12331243

1234-
if (mapper is not None):
1244+
if (mapper is not sentinel):
12351245
# Use v0.23 behavior if a scalar or list
12361246
non_mapper = is_scalar(mapper) or (is_list_like(mapper) and not
12371247
is_dict_like(mapper))
@@ -1254,7 +1264,7 @@ class name
12541264

12551265
for axis in lrange(self._AXIS_LEN):
12561266
v = axes.get(self._AXIS_NAMES[axis])
1257-
if v is None:
1267+
if v is sentinel:
12581268
continue
12591269
non_mapper = is_scalar(v) or (is_list_like(v) and not
12601270
is_dict_like(v))

pandas/tests/frame/test_alter_axes.py

+20
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,26 @@ def test_rename_axis_mapper(self):
600600
with pytest.raises(TypeError, match='bogus'):
601601
df.rename_axis(bogus=None)
602602

603+
@pytest.mark.parametrize('kwargs, rename_index, rename_columns', [
604+
({'mapper': None, 'axis': 0}, True, False),
605+
({'mapper': None, 'axis': 1}, False, True),
606+
({'index': None}, True, False),
607+
({'columns': None}, False, True),
608+
({'index': None, 'columns': None}, True, True),
609+
({}, False, False)])
610+
def test_rename_axis_none(self, kwargs, rename_index, rename_columns):
611+
# GH 25034
612+
index = Index(list('abc'), name='foo')
613+
columns = Index(['col1', 'col2'], name='bar')
614+
data = np.arange(6).reshape(3, 2)
615+
df = DataFrame(data, index, columns)
616+
617+
result = df.rename_axis(**kwargs)
618+
expected_index = index.rename(None) if rename_index else index
619+
expected_columns = columns.rename(None) if rename_columns else columns
620+
expected = DataFrame(data, expected_index, expected_columns)
621+
tm.assert_frame_equal(result, expected)
622+
603623
def test_rename_multiindex(self):
604624

605625
tuples_index = [('foo1', 'bar1'), ('foo2', 'bar2')]

pandas/tests/series/test_alter_axes.py

+11
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,17 @@ def test_rename_axis_inplace(self, datetime_series):
258258
assert no_return is None
259259
tm.assert_series_equal(result, expected)
260260

261+
@pytest.mark.parametrize('kwargs', [{'mapper': None}, {'index': None}, {}])
262+
def test_rename_axis_none(self, kwargs):
263+
# GH 25034
264+
index = Index(list('abc'), name='foo')
265+
df = Series([1, 2, 3], index=index)
266+
267+
result = df.rename_axis(**kwargs)
268+
expected_index = index.rename(None) if kwargs else index
269+
expected = Series([1, 2, 3], index=expected_index)
270+
tm.assert_series_equal(result, expected)
271+
261272
def test_set_axis_inplace_axes(self, axis_series):
262273
# GH14636
263274
ser = Series(np.arange(4), index=[1, 3, 5, 7], dtype='int64')

0 commit comments

Comments
 (0)