Skip to content

DEPR: xlwt for writing excel files #38317

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

Merged
merged 5 commits into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/source/user_guide/io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3200,6 +3200,13 @@ pandas supports writing Excel files to buffer-like objects such as ``StringIO``
Excel writer engines
''''''''''''''''''''

.. deprecated:: 1.2.0

The `xlwt <https://pypi.org/project/xlwt/>`__
engine, the only engine that supports writing
in an xls format, is no longer maintained and
will be removed in a future version of pandas.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: it's the package that is no longer maintained, and the engine that will be removed (now it reads like the code in pandas that will be removed is no longer maintained)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(now, since it's written this way in many places in your PR (and the previous one), it might not be worth it to change ..)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the nitpicks; and as long as it's not holding things up happy to work on it to get it right. What do you think of:

The `xlwt <https://pypi.org/project/xlwt/>`__ package is no longer maintained and will not be available in a future version of pandas. This is the only engine currently in pandas that supports writing in an xls format.


pandas chooses an Excel writer via two methods:

1. the ``engine`` keyword argument
Expand Down
9 changes: 9 additions & 0 deletions doc/source/user_guide/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,15 @@ 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

The `xlwt <https://pypi.org/project/xlwt/>`__
engine, the only engine that supports writing
in an xls format, is no longer maintained and
will be removed in a future version of pandas.
This option will also be removed.

io.excel.xlsm.writer openpyxl The default Excel writer engine for
'xlsm' files. Available options:
'openpyxl' (the default).
Expand Down
25 changes: 20 additions & 5 deletions doc/source/whatsnew/v1.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,27 @@ including other versions of pandas.

.. warning::

The engine `xlrd <https://xlrd.readthedocs.io/en/latest/>`_ for reading excel
files and the engine `xlwt <https://xlwt.readthedocs.io/en/latest/>`_ for
writing excel files are no longer maintained.
These are the only engines that support the xls format.
Users are recommended to write excel files in the xlsx format using the
`openpyxl <https://openpyxl.readthedocs.io/en/stable/>`_ engine instead.
Attempting to use the the ``xlwt`` engine will raise a ``FutureWarning``
unless the option :attr:`io.excel.xls.writer` is set to ``"xlwt"``.

Previously, the default argument ``engine=None`` to ``pd.read_excel``
would result in using the `xlrd <https://xlrd.readthedocs.io/en/latest/>`_ engine in
many cases. The engine ``xlrd`` is no longer maintained, and is not supported with
python >= 3.9. If `openpyxl <https://pypi.org/project/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 ``FutureWarning``. However, users should be aware that ``xlrd`` is
broken with certain configurations of packages, for example with Python 3.9
when `defusedxml <https://github.com/tiran/defusedxml/>`_ is installed. It
is anticipated to be unusable in the future.

.. ---------------------------------------------------------------------------

Expand Down
7 changes: 7 additions & 0 deletions pandas/core/config_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -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="The xlwt engine, the only engine that supports writing in "
"an xls format, is no longer maintained and will be removed in "
"a future version of pandas. This option will also be removed. "
"Install openpyxl and write to an xlsx file instead.",
)

with cf.config_prefix("io.excel.xlsm"):
cf.register_option(
Expand Down
7 changes: 7 additions & 0 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

The `xlwt <https://pypi.org/project/xlwt/>`__ engine, the only engine
that supports writing in an xls format, is no longer maintained and
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
Expand Down
26 changes: 25 additions & 1 deletion pandas/io/excel/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,13 @@ class ExcelWriter(metaclass=abc.ABCMeta):
Engine to use for writing. If None, defaults to
``io.excel.<extension>.writer``. NOTE: can only be passed as a keyword
argument.

.. deprecated:: 1.2.0

The `xlwt <https://pypi.org/project/xlwt/>`__ engine, the only engine
that supports writing in an xls format, is no longer maintained and
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
Expand Down Expand Up @@ -691,11 +698,28 @@ 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(
"The xlwt engine, the only engine that supports writing in "
"an xls format, is no longer maintained and will be removed in "
"a future version of pandas. Install openpyxl and write to an "
"xlsx file instead. You can set the option "
"io.excel.xls.writer to 'xlwt' to silence this warning.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But setting the option is also deprecated and will also raise a warning?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - but at least it is in hopefully fewer places in user code. The warning can still be ignored there, but I see now that will cause confusion when a user follows the instruction and then still gets a warning. I'm thinking I'll change to:

You can set the option io.excel.xls.writer to 'xlwt' to silence this warning. This option is deprecated as well and will also give a warning, but can be globally set and suppressed.

FutureWarning,
stacklevel=4,
)

cls = get_writer(engine)

return object.__new__(cls)
Expand Down
7 changes: 7 additions & 0 deletions pandas/io/formats/excel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

The `xlwt <https://pypi.org/project/xlwt/>`__ engine, the only engine
that supports writing in an xls format, is no longer maintained and
will be removed in a future version of pandas.

{storage_options}

.. versionadded:: 1.2.0
Expand Down
5 changes: 5 additions & 0 deletions pandas/tests/io/excel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@
pytest.mark.filterwarnings(
"ignore:This method will be removed in future versions:DeprecationWarning"
),
# GH 26552
pytest.mark.filterwarnings(
"ignore:The xlwt engine, the only engine that supports writing in an xls "
"format, is no longer maintained"
),
]
23 changes: 22 additions & 1 deletion pandas/tests/io/excel/test_xlwt.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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="The xlwt engine",
):
df.to_excel(path)


def test_option_xls_writer_deprecated(ext):
# GH 26552
with tm.assert_produces_warning(
FutureWarning,
match="The xlwt engine",
check_stacklevel=False,
):
options.io.excel.xls.writer = "xlwt"