Repository: pandas-dev/pandas
Pull request: GH10559: Minor improvement: Change read_excel sheet name
modify io/excel.py and relevant docs (io.rst) to use sheet_name for read_excel
but allow sheetname to still be used for backwards compatibility.  add test_excel
to verify that sheet_name and sheetname args produce the same result.

 - [X] closes #10559 
 - [X] tests added / passed
 - [X] passes ``git diff upstream/master --name-only -- '*.py' | flake8 --diff``
 - [x] whatsnew entry


Problem statement:
Minor improvement: Change to_excel "sheet_name" to "sheetname"
pd.read_excel() takes "sheetname" as an argument.
pd.DataFrame.to_excel() takes "sheet_name" as an argument.

For consistency, I think one ought to be changed to match the other.
On my windows installation of pandas 0.16.2, I modified to_excel to take sheetname rather than sheet_name.  All I had to do was locate frame.py within the core directory.  to_excel() is defined here, and sheet_name is written twice in the function and once in the docstring.  

Very new to github so if ideas like these are more appropriately filed through PRs I apologize.

Hints from issue discussion:
Agree we should make them the same (at least make it available, maybe not necessary to actually deprecate the discouraged alias).

I am only not fully sure if would go with `sheetname` instead of `sheet_name` (we are not always very consistent in the use of `_` to separate words in keywords, but I think the general policy is to use them).

And @saintsfan342000, opening an issue for this is very good! If you get approval, always welcome to open a PR afterwards! 

current (0.20.x) branch appears to mostly use `sheet_name` so propose changing `sheetname` to `sheet_name`.

````
$ git status
On branch 0.20.x
````

49 occurrences of sheet_name in io
````
$ grep -rc sheet_name pandas/io | grep -v 0
pandas/io/excel.py:42
pandas/io/formats/excel.py:3
pandas/io/formats/style.py:2
````

25 occurrences of sheetname in io
````
$ grep -rc sheetname pandas/io | grep -v 0
pandas/io/excel.py:25
````

Commit message: GH10559: Minor improvement: Change to_excel sheet name

modify io/excel.py and relevant docs (io.rst) to use sheet_name for read_excel
but allow sheetname to still be used for backwards compatibility.  add test_excel
to verify that sheet_name and sheetname args produce the same result.

Patch to review:
diff --git a/doc/source/io.rst b/doc/source/io.rst
index 9692766505d7a..bca23dd18a0e3 100644
--- a/doc/source/io.rst
+++ b/doc/source/io.rst
@@ -2561,12 +2561,12 @@ Reading Excel Files
 '''''''''''''''''''
 
 In the most basic use-case, ``read_excel`` takes a path to an Excel
-file, and the ``sheetname`` indicating which sheet to parse.
+file, and the ``sheet_name`` indicating which sheet to parse.
 
 .. code-block:: python
 
    # Returns a DataFrame
-   read_excel('path_to_file.xls', sheetname='Sheet1')
+   read_excel('path_to_file.xls', sheet_name='Sheet1')
 
 
 .. _io.excel.excelfile_class:
@@ -2634,12 +2634,12 @@ of sheet names can simply be passed to ``read_excel`` with no loss in performanc
 Specifying Sheets
 +++++++++++++++++
 
-.. note :: The second argument is ``sheetname``, not to be confused with ``ExcelFile.sheet_names``
+.. note :: The second argument is ``sheet_name``, not to be confused with ``ExcelFile.sheet_names``
 
 .. note :: An ExcelFile's attribute ``sheet_names`` provides access to a list of sheets.
 
-- The arguments ``sheetname`` allows specifying the sheet or sheets to read.
-- The default value for ``sheetname`` is 0, indicating to read the first sheet
+- The arguments ``sheet_name`` allows specifying the sheet or sheets to read.
+- The default value for ``sheet_name`` is 0, indicating to read the first sheet
 - Pass a string to refer to the name of a particular sheet in the workbook.
 - Pass an integer to refer to the index of a sheet. Indices follow Python
   convention, beginning at 0.
@@ -2670,18 +2670,18 @@ Using None to get all sheets:
 .. code-block:: python
 
    # Returns a dictionary of DataFrames
-   read_excel('path_to_file.xls',sheetname=None)
+   read_excel('path_to_file.xls',sheet_name=None)
 
 Using a list to get multiple sheets:
 
 .. code-block:: python
 
    # Returns the 1st and 4th sheet, as a dictionary of DataFrames.
-   read_excel('path_to_file.xls',sheetname=['Sheet1',3])
+   read_excel('path_to_file.xls',sheet_name=['Sheet1',3])
 
 .. versionadded:: 0.16
 
-``read_excel`` can read more than one sheet, by setting ``sheetname`` to either
+``read_excel`` can read more than one sheet, by setting ``sheet_name`` to either
 a list of sheet names, a list of sheet positions, or ``None`` to read all sheets.
 
 .. versionadded:: 0.13
diff --git a/pandas/io/excel.py b/pandas/io/excel.py
index fba3d7559aeaf..35c9bcdc37892 100644
--- a/pandas/io/excel.py
+++ b/pandas/io/excel.py
@@ -48,7 +48,7 @@
     The string could be a URL. Valid URL schemes include http, ftp, s3,
     and file. For file URLs, a host is expected. For instance, a local
     file could be file://localhost/path/to/workbook.xlsx
-sheetname : string, int, mixed list of strings/ints, or None, default 0
+sheet_name : string, int, mixed list of strings/ints, or None, default 0
 
     Strings are used for sheet names, Integers are used in zero-indexed
     sheet positions.
@@ -144,7 +144,7 @@
 Returns
 -------
 parsed : DataFrame or Dict of DataFrames
-    DataFrame from the passed in Excel file.  See notes in sheetname
+    DataFrame from the passed in Excel file.  See notes in sheet_name
     argument for more information on when a Dict of Dataframes is returned.
 """
 
@@ -190,7 +190,7 @@ def get_writer(engine_name):
 
 
 @Appender(_read_excel_doc)
-def read_excel(io, sheetname=0, header=0, skiprows=None, skip_footer=0,
+def read_excel(io, sheet_name=0, header=0, skiprows=None, skip_footer=0,
                index_col=None, names=None, parse_cols=None, parse_dates=False,
                date_parser=None, na_values=None, thousands=None,
                convert_float=True, has_index_names=None, converters=None,
@@ -200,8 +200,12 @@ def read_excel(io, sheetname=0, header=0, skiprows=None, skip_footer=0,
     if not isinstance(io, ExcelFile):
         io = ExcelFile(io, engine=engine)
 
+    # maintain backwards compatibility by converting sheetname to sheet_name
+    if 'sheetname' in kwds:
+         sheet_name = kwds.pop('sheetname')
+
     return io._parse_excel(
-        sheetname=sheetname, header=header, skiprows=skiprows, names=names,
+        sheetname=sheet_name, header=header, skiprows=skiprows, names=names,
         index_col=index_col, parse_cols=parse_cols, parse_dates=parse_dates,
         date_parser=date_parser, na_values=na_values, thousands=thousands,
         convert_float=convert_float, has_index_names=has_index_names,
@@ -266,7 +270,7 @@ def __init__(self, io, **kwds):
     def __fspath__(self):
         return self._io
 
-    def parse(self, sheetname=0, header=0, skiprows=None, skip_footer=0,
+    def parse(self, sheet_name=0, header=0, skiprows=None, skip_footer=0,
               names=None, index_col=None, parse_cols=None, parse_dates=False,
               date_parser=None, na_values=None, thousands=None,
               convert_float=True, has_index_names=None,
@@ -279,7 +283,7 @@ def parse(self, sheetname=0, header=0, skiprows=None, skip_footer=0,
         docstring for more info on accepted parameters
         """
 
-        return self._parse_excel(sheetname=sheetname, header=header,
+        return self._parse_excel(sheetname=sheet_name, header=header,
                                  skiprows=skiprows, names=names,
                                  index_col=index_col,
                                  has_index_names=has_index_names,
diff --git a/pandas/tests/io/test_excel.py b/pandas/tests/io/test_excel.py
index bbf4f1107ac9e..0956b00803371 100644
--- a/pandas/tests/io/test_excel.py
+++ b/pandas/tests/io/test_excel.py
@@ -544,6 +544,18 @@ def test_date_conversion_overflow(self):
         result = self.get_exceldf('testdateoverflow')
         tm.assert_frame_equal(result, expected)
 
+    # GH10559: Minor improvement: Change to_excel "sheet_name" to "sheetname"
+    # GH10969: DOC: Consistent variable names (sheetname vs sheet_name, issue 10559)
+    # GH12604: CLN GH10559 Rename sheetname variable to sheet_name for consistency
+    def test_sheet_name_and_sheetname(self):
+        dfref = self.get_csv_refdf('test1')
+        df1 = self.get_exceldf('test1', sheet_name='Sheet1')    # doc
+        df2 = self.get_exceldf('test1', sheetname='Sheet2')     # bkwrds compat
+
+        tm.assert_frame_equal(df1, dfref, check_names=False)
+        tm.assert_frame_equal(df2, dfref, check_names=False)
+
+
 
 class XlrdTests(ReadingTestsBase):
     """


Code review comments:
diff_hunk: @@ -544,6 +544,18 @@ def test_date_conversion_overflow(self):
         result = self.get_exceldf('testdateoverflow')
         tm.assert_frame_equal(result, expected)
 
+    # GH10559: Minor improvement: Change to_excel "sheet_name" to "sheetname"
path: pandas/tests/io/test_excel.py
text: @user1:
comments go inside the function.

diff_hunk: @@ -544,6 +544,18 @@ def test_date_conversion_overflow(self):
         result = self.get_exceldf('testdateoverflow')
         tm.assert_frame_equal(result, expected)
 
+    # GH10559: Minor improvement: Change to_excel "sheet_name" to "sheetname"
+    # GH10969: DOC: Consistent variable names (sheetname vs sheet_name, issue 10559)
+    # GH12604: CLN GH10559 Rename sheetname variable to sheet_name for consistency
+    def test_sheet_name_and_sheetname(self):
+        dfref = self.get_csv_refdf('test1')
+        df1 = self.get_exceldf('test1', sheet_name='Sheet1')    # doc
+        df2 = self.get_exceldf('test1', sheetname='Sheet2')     # bkwrds compat
path: pandas/tests/io/test_excel.py
text: @user1:
this should show a FutureWarning

@user2:
You can assert that a warning is issued with the`tm.assert_produces_warning` context manager.

diff_hunk: @@ -200,8 +200,12 @@ def read_excel(io, sheetname=0, header=0, skiprows=None, skip_footer=0,
     if not isinstance(io, ExcelFile):
         io = ExcelFile(io, engine=engine)
 
+    # maintain backwards compatibility by converting sheetname to sheet_name
+    if 'sheetname' in kwds:
+         sheet_name = kwds.pop('sheetname')
path: pandas/io/excel.py
text: @user1:
needs a deprecation warning on the original arg. You need to *also* accept the original arg as a kwarg.

@user1:
you can use ``pandas.util._decorators.deprecate_kwarg``