Skip to content

Commit

Permalink
Backport PR pandas-dev#25069: REGR: rename_axis with None should remo…
Browse files Browse the repository at this point in the history
…ve axis name
  • Loading branch information
jschendel authored and MeeseeksDev[bot] committed Feb 1, 2019
1 parent 4f865c5 commit 07f4282
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 6 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.24.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Fixed Regressions
- Fixed regression in :func:`read_sql` when passing certain queries with MySQL/pymysql (:issue:`24988`).
- Fixed regression in :class:`Index.intersection` incorrectly sorting the values by default (:issue:`24959`).
- Fixed regression in :func:`merge` when merging an empty ``DataFrame`` with multiple timezone-aware columns on one of the timezone-aware columns (:issue:`25014`).
- Fixed regression in :meth:`Series.rename_axis` and :meth:`DataFrame.rename_axis` where passing ``None`` failed to remove the axis name (:issue:`25034`)

.. _whatsnew_0241.enhancements:

Expand Down
22 changes: 16 additions & 6 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
by : str or list of str
Name or list of names to sort by""")

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


def _single_replace(self, to_replace, method, inplace, limit):
"""
Expand Down Expand Up @@ -290,11 +294,16 @@ def _construct_axes_dict_for_slice(self, axes=None, **kwargs):
d.update(kwargs)
return d

def _construct_axes_from_arguments(self, args, kwargs, require_all=False):
def _construct_axes_from_arguments(
self, args, kwargs, require_all=False, sentinel=None):
"""Construct and returns axes if supplied in args/kwargs.
If require_all, raise if all axis arguments are not supplied
return a tuple of (axes, kwargs).
sentinel specifies the default parameter when an axis is not
supplied; useful to distinguish when a user explicitly passes None
in scenarios where None has special meaning.
"""

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

axes = {a: kwargs.pop(a, None) for a in self._AXIS_ORDERS}
axes = {a: kwargs.pop(a, sentinel) for a in self._AXIS_ORDERS}
return axes, kwargs

@classmethod
Expand Down Expand Up @@ -1089,7 +1098,7 @@ def rename(self, *args, **kwargs):

@rewrite_axis_style_signature('mapper', [('copy', True),
('inplace', False)])
def rename_axis(self, mapper=None, **kwargs):
def rename_axis(self, mapper=sentinel, **kwargs):
"""
Set the name of the axis for the index or columns.
Expand Down Expand Up @@ -1218,7 +1227,8 @@ class name
cat 4 0
monkey 2 2
"""
axes, kwargs = self._construct_axes_from_arguments((), kwargs)
axes, kwargs = self._construct_axes_from_arguments(
(), kwargs, sentinel=sentinel)
copy = kwargs.pop('copy', True)
inplace = kwargs.pop('inplace', False)
axis = kwargs.pop('axis', 0)
Expand All @@ -1231,7 +1241,7 @@ class name

inplace = validate_bool_kwarg(inplace, 'inplace')

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

for axis in lrange(self._AXIS_LEN):
v = axes.get(self._AXIS_NAMES[axis])
if v is None:
if v is sentinel:
continue
non_mapper = is_scalar(v) or (is_list_like(v) and not
is_dict_like(v))
Expand Down
20 changes: 20 additions & 0 deletions pandas/tests/frame/test_alter_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,26 @@ def test_rename_axis_mapper(self):
with pytest.raises(TypeError, match='bogus'):
df.rename_axis(bogus=None)

@pytest.mark.parametrize('kwargs, rename_index, rename_columns', [
({'mapper': None, 'axis': 0}, True, False),
({'mapper': None, 'axis': 1}, False, True),
({'index': None}, True, False),
({'columns': None}, False, True),
({'index': None, 'columns': None}, True, True),
({}, False, False)])
def test_rename_axis_none(self, kwargs, rename_index, rename_columns):
# GH 25034
index = Index(list('abc'), name='foo')
columns = Index(['col1', 'col2'], name='bar')
data = np.arange(6).reshape(3, 2)
df = DataFrame(data, index, columns)

result = df.rename_axis(**kwargs)
expected_index = index.rename(None) if rename_index else index
expected_columns = columns.rename(None) if rename_columns else columns
expected = DataFrame(data, expected_index, expected_columns)
tm.assert_frame_equal(result, expected)

def test_rename_multiindex(self):

tuples_index = [('foo1', 'bar1'), ('foo2', 'bar2')]
Expand Down
11 changes: 11 additions & 0 deletions pandas/tests/series/test_alter_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,17 @@ def test_rename_axis_inplace(self, datetime_series):
assert no_return is None
tm.assert_series_equal(result, expected)

@pytest.mark.parametrize('kwargs', [{'mapper': None}, {'index': None}, {}])
def test_rename_axis_none(self, kwargs):
# GH 25034
index = Index(list('abc'), name='foo')
df = Series([1, 2, 3], index=index)

result = df.rename_axis(**kwargs)
expected_index = index.rename(None) if kwargs else index
expected = Series([1, 2, 3], index=expected_index)
tm.assert_series_equal(result, expected)

def test_set_axis_inplace_axes(self, axis_series):
# GH14636
ser = Series(np.arange(4), index=[1, 3, 5, 7], dtype='int64')
Expand Down

0 comments on commit 07f4282

Please sign in to comment.