Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REGR: rename_axis with None should remove axis name #25069

merged 3 commits into from Feb 1, 2019
Changes from 2 commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.


Just for now

@@ -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:

@@ -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.
This conversation was marked as resolved by jschendel

This comment has been minimized.

Copy link

jreback Feb 1, 2019


I would just use object() its more pythonic, we should remove the whole sentinel_factory() bizness.

This comment has been minimized.

Copy link

jschendel Feb 1, 2019

Author Member

made the sentinel_factory() --> object() change here; planning to do the global removal of sentinel_factory() as a follow up so it can go into 0.25.0 and keep the 0.24.x changes as minimal as possible.

This comment has been minimized.

Copy link

jschendel Feb 1, 2019

Author Member

xref #25074

sentinel = com.sentinel_factory()

def _single_replace(self, to_replace, method, inplace, limit):
@@ -290,11 +294,16 @@ def _construct_axes_dict_for_slice(self, axes=None, **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
@@ -322,7 +331,7 @@ def _construct_axes_from_arguments(self, args, kwargs, require_all=False):
raise TypeError("not enough/duplicate arguments "

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

@@ -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.
@@ -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)
@@ -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
@@ -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:
non_mapper = is_scalar(v) or (is_list_like(v) and not
@@ -600,6 +600,26 @@ def test_rename_axis_mapper(self):
with pytest.raises(TypeError, match='bogus'):

@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')]
@@ -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')
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.