Code Sample, a copy-pastable example if possible

In [2]: mi = pd.MultiIndex.from_tuples([(1,2), (3,4)])

In [3]: pd.DataFrame([[1], [2]], index=mi).rename('c', level=1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-4199859c8380> in <module>()
----> 1 pd.DataFrame([[1], [2]], index=mi).rename('c', level=1)

/home/pietro/nobackup/repo/pandas/pandas/core/frame.py in rename(self, index, columns, **kwargs)
   2845     def rename(self, index=None, columns=None, **kwargs):
   2846         return super(DataFrame, self).rename(index=index, columns=columns,
-> 2847                                              **kwargs)
   2848 
   2849     @Appender(_shared_docs['fillna'] % _shared_doc_kwargs)

/home/pietro/nobackup/repo/pandas/pandas/core/generic.py in rename(self, *args, **kwargs)
    845                 level = self.axes[axis]._get_level_number(level)
    846             result._data = result._data.rename_axis(f, axis=baxis, copy=copy,
--> 847                                                     level=level)
    848             result._clear_item_cache()
    849 

/home/pietro/nobackup/repo/pandas/pandas/core/internals.py in rename_axis(self, mapper, axis, copy, level)
   2956         """
   2957         obj = self.copy(deep=copy)
-> 2958         obj.set_axis(axis, _transform_index(self.axes[axis], mapper, level))
   2959         return obj
   2960 

/home/pietro/nobackup/repo/pandas/pandas/core/internals.py in _transform_index(index, func, level)
   4842         if level is not None:
   4843             items = [tuple(func(y) if i == level else y
-> 4844                            for i, y in enumerate(x)) for x in index]
   4845         else:
   4846             items = [tuple(func(y) for y in x) for x in index]

/home/pietro/nobackup/repo/pandas/pandas/core/internals.py in <listcomp>(.0)
   4842         if level is not None:
   4843             items = [tuple(func(y) if i == level else y
-> 4844                            for i, y in enumerate(x)) for x in index]
   4845         else:
   4846             items = [tuple(func(y) for y in x) for x in index]

/home/pietro/nobackup/repo/pandas/pandas/core/internals.py in <genexpr>(.0)
   4842         if level is not None:
   4843             items = [tuple(func(y) if i == level else y
-> 4844                            for i, y in enumerate(x)) for x in index]
   4845         else:
   4846             items = [tuple(func(y) for y in x) for x in index]

TypeError: 'str' object is not callable

Problem description

Apparently, the level argument works only for relabeling, not for renaming the level. This is not, however, mentioned in the docs.

This is closely related to #14829 (that is: whatever will the new method for index renaming be called, it will need not just to steal the related logics from .rename, but also to implement this one, which is currently absent).

Expected Output

Same as

In [4]: df = pd.DataFrame([[1], [2]], index=mi)

In [5]: df.index.names = ['a', 'c']

In [6]: df
Out[6]: 
     0
a c   
1 2  1
3 4  2

Output of pd.show_versions()

INSTALLED VERSIONS ------------------ commit: None python: 3.5.3.final.0 python-bits: 64 OS: Linux OS-release: 4.9.0-3-amd64 machine: x86_64 processor: byteorder: little LC_ALL: None LANG: it_IT.UTF-8 LOCALE: it_IT.UTF-8 pandas: 0.21.0.dev+310.ge3b784068 pytest: 3.0.6 pip: 9.0.1 setuptools: None Cython: 0.25.2 numpy: 1.12.1 scipy: 0.19.0 pyarrow: None xarray: None IPython: 5.1.0.dev sphinx: 1.5.6 patsy: 0.4.1 dateutil: 2.6.0 pytz: 2017.2 blosc: None bottleneck: 1.2.1 tables: 3.3.0 numexpr: 2.6.1 feather: 0.3.1 matplotlib: 2.0.2 openpyxl: None xlrd: 1.0.0 xlwt: 1.1.2 xlsxwriter: 0.9.6 lxml: None bs4: 4.5.3 html5lib: 0.999999999 sqlalchemy: 1.0.15 pymysql: None psycopg2: None jinja2: 2.9.6 s3fs: None pandas_gbq: None pandas_datareader: 0.2.1

Comment From: gfyoung

@toobaz : I'm a little confused by what you're doing here. According to the docs, you should not be passing in a scalar for the index parameter when using a DataFrame:

Scalar or list-like will alter the Series.name attribute, and raise on DataFrame or Panel

Comment From: toobaz

Sorry, you are right. I got confused. I expected rename to allow me to rename the index, but it just doesn't do this, regardless of the index being flat or not.