diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst
index 2b324a74fffaf..965833c013c03 100644
--- a/doc/source/user_guide/io.rst
+++ b/doc/source/user_guide/io.rst
@@ -3200,6 +3200,13 @@ pandas supports writing Excel files to buffer-like objects such as ``StringIO``
Excel writer engines
''''''''''''''''''''
+.. deprecated:: 1.2.0
+
+ As the `xlwt `__ package is no longer
+ maintained, the ``xlwt`` engine will be removed from a future version
+ of pandas. This is the only engine in pandas that supports writing to
+ ``.xls`` files.
+
pandas chooses an Excel writer via two methods:
1. the ``engine`` keyword argument
diff --git a/doc/source/user_guide/options.rst b/doc/source/user_guide/options.rst
index c828bc28826b1..b8e75b0535823 100644
--- a/doc/source/user_guide/options.rst
+++ b/doc/source/user_guide/options.rst
@@ -432,6 +432,16 @@ display.html.use_mathjax True When True, Jupyter notebook
dollar symbol.
io.excel.xls.writer xlwt The default Excel writer engine for
'xls' files.
+
+ .. deprecated:: 1.2.0
+
+ As `xlwt `__
+ package is no longer maintained, the ``xlwt``
+ engine will be removed in a future version of
+ pandas. Since this is the only engine in pandas
+ that supports writing to ``.xls`` files,
+ this option will also be removed.
+
io.excel.xlsm.writer openpyxl The default Excel writer engine for
'xlsm' files. Available options:
'openpyxl' (the default).
diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst
index 5c4472749e11f..84227319bf6a0 100644
--- a/doc/source/whatsnew/v1.2.0.rst
+++ b/doc/source/whatsnew/v1.2.0.rst
@@ -10,12 +10,27 @@ including other versions of pandas.
.. warning::
+ The packages `xlrd `_ for reading excel
+ files and `xlwt `_ for
+ writing excel files are no longer maintained. These are the only engines in pandas
+ that support the xls format.
+
Previously, the default argument ``engine=None`` to ``pd.read_excel``
- would result in using the `xlrd `_ engine in
- many cases. The engine ``xlrd`` is no longer maintained, and is not supported with
- python >= 3.9. If `openpyxl `_ is installed,
- many of these cases will now default to using the ``openpyxl`` engine. See the
- :func:`read_excel` documentation for more details.
+ would result in using the ``xlrd`` engine in many cases. If
+ `openpyxl `_ is installed,
+ many of these cases will now default to using the ``openpyxl`` engine.
+ See the :func:`read_excel` documentation for more details. Attempting to read
+ ``.xls`` files or specifying ``engine="xlrd"`` to ``pd.read_excel`` will not
+ raise a warning. However users should be aware that ``xlrd`` is already
+ broken with certain package configurations, for example with Python 3.9
+ when `defusedxml `_ is installed, and
+ is anticipated to be unusable in the future.
+
+ Attempting to use the the ``xlwt`` engine will raise a ``FutureWarning``
+ unless the option :attr:`io.excel.xls.writer` is set to ``"xlwt"``.
+ While this option is now deprecated and will also raise a ``FutureWarning``,
+ it can be globally set and the warning suppressed. Users are recommended to
+ write ``.xlsx`` files using the ``openpyxl`` engine instead.
.. ---------------------------------------------------------------------------
diff --git a/pandas/core/config_init.py b/pandas/core/config_init.py
index 541ecd9df6fc7..7d9664bd9f965 100644
--- a/pandas/core/config_init.py
+++ b/pandas/core/config_init.py
@@ -581,6 +581,13 @@ def use_inf_as_na_cb(key):
writer_engine_doc.format(ext="xls", others=", ".join(_xls_options)),
validator=str,
)
+cf.deprecate_option(
+ "io.excel.xls.writer",
+ msg="As the xlwt package is no longer maintained, the xlwt engine will be "
+ "removed in a future version of pandas. This is the only engine in pandas that "
+ "supports writing in the xls format. Install openpyxl and write to an "
+ "xlsx file instead.",
+)
with cf.config_prefix("io.excel.xlsm"):
cf.register_option(
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
index 637897391f6bb..b851c4d7d4931 100644
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -2093,6 +2093,13 @@ def to_excel(
Write engine to use, 'openpyxl' or 'xlsxwriter'. You can also set this
via the options ``io.excel.xlsx.writer``, ``io.excel.xls.writer``, and
``io.excel.xlsm.writer``.
+
+ .. deprecated:: 1.2.0
+
+ As the `xlwt `__ package is no longer
+ maintained, the ``xlwt`` engine will be removed in a future version
+ of pandas.
+
merge_cells : bool, default True
Write MultiIndex and Hierarchical Rows as merged cells.
encoding : str, optional
diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py
index 626c3df196380..bf1011176693f 100644
--- a/pandas/io/excel/_base.py
+++ b/pandas/io/excel/_base.py
@@ -587,6 +587,13 @@ class ExcelWriter(metaclass=abc.ABCMeta):
Engine to use for writing. If None, defaults to
``io.excel..writer``. NOTE: can only be passed as a keyword
argument.
+
+ .. deprecated:: 1.2.0
+
+ As the `xlwt `__ package is no longer
+ maintained, the ``xlwt`` engine will be removed in a future
+ version of pandas.
+
date_format : str, default None
Format string for dates written into Excel files (e.g. 'YYYY-MM-DD').
datetime_format : str, default None
@@ -691,11 +698,31 @@ def __new__(cls, path, engine=None, **kwargs):
ext = "xlsx"
try:
- engine = config.get_option(f"io.excel.{ext}.writer")
+ engine = config.get_option(f"io.excel.{ext}.writer", silent=True)
if engine == "auto":
engine = get_default_writer(ext)
except KeyError as err:
raise ValueError(f"No engine for filetype: '{ext}'") from err
+
+ if engine == "xlwt":
+ xls_config_engine = config.get_option(
+ "io.excel.xls.writer", silent=True
+ )
+ # Don't warn a 2nd time if user has changed the default engine for xls
+ if xls_config_engine != "xlwt":
+ warnings.warn(
+ "As the xlwt package is no longer maintained, the xlwt "
+ "engine will be removed in a future version of pandas. "
+ "This is the only engine in pandas that supports writing "
+ "in the xls format. Install openpyxl and write to an xlsx "
+ "file instead. You can set the option io.excel.xls.writer "
+ "to 'xlwt' to silence this warning. While this option is "
+ "deprecated and will also raise a warning, it can "
+ "be globally set and the warning suppressed.",
+ FutureWarning,
+ stacklevel=4,
+ )
+
cls = get_writer(engine)
return object.__new__(cls)
diff --git a/pandas/io/formats/excel.py b/pandas/io/formats/excel.py
index bded853f383e0..be8f2de1d53fb 100644
--- a/pandas/io/formats/excel.py
+++ b/pandas/io/formats/excel.py
@@ -805,6 +805,13 @@ def write(
write engine to use if writer is a path - you can also set this
via the options ``io.excel.xlsx.writer``, ``io.excel.xls.writer``,
and ``io.excel.xlsm.writer``.
+
+ .. deprecated:: 1.2.0
+
+ As the `xlwt `__ package is no longer
+ maintained, the ``xlwt`` engine will be removed in a future
+ version of pandas.
+
{storage_options}
.. versionadded:: 1.2.0
diff --git a/pandas/tests/io/excel/__init__.py b/pandas/tests/io/excel/__init__.py
index 419761cbe1d6d..384f1006c44df 100644
--- a/pandas/tests/io/excel/__init__.py
+++ b/pandas/tests/io/excel/__init__.py
@@ -9,4 +9,8 @@
pytest.mark.filterwarnings(
"ignore:This method will be removed in future versions:DeprecationWarning"
),
+ # GH 26552
+ pytest.mark.filterwarnings(
+ "ignore:As the xlwt package is no longer maintained:FutureWarning"
+ ),
]
diff --git a/pandas/tests/io/excel/test_xlwt.py b/pandas/tests/io/excel/test_xlwt.py
index 6bfd71beed0ca..ac53a7d5aee69 100644
--- a/pandas/tests/io/excel/test_xlwt.py
+++ b/pandas/tests/io/excel/test_xlwt.py
@@ -1,7 +1,7 @@
import numpy as np
import pytest
-from pandas import DataFrame, MultiIndex
+from pandas import DataFrame, MultiIndex, options
import pandas._testing as tm
from pandas.io.excel import ExcelWriter, _XlwtWriter
@@ -69,3 +69,24 @@ def test_write_append_mode_raises(ext):
with tm.ensure_clean(ext) as f:
with pytest.raises(ValueError, match=msg):
ExcelWriter(f, engine="xlwt", mode="a")
+
+
+def test_to_excel_xlwt_warning(ext):
+ # GH 26552
+ df = DataFrame(np.random.randn(3, 10))
+ with tm.ensure_clean(ext) as path:
+ with tm.assert_produces_warning(
+ FutureWarning,
+ match="As the xlwt package is no longer maintained",
+ ):
+ df.to_excel(path)
+
+
+def test_option_xls_writer_deprecated(ext):
+ # GH 26552
+ with tm.assert_produces_warning(
+ FutureWarning,
+ match="As the xlwt package is no longer maintained",
+ check_stacklevel=False,
+ ):
+ options.io.excel.xls.writer = "xlwt"