Skip to content

Commit 42e06a7

Browse files
committed
CLN: Make ExcelWriter more pluggable
Make ExcelWriter an ABC and add ExcelWriter config to core/config_init ENH: Allow Panel.to_excel to pass keyword arguments
1 parent c0198b4 commit 42e06a7

File tree

9 files changed

+415
-139
lines changed

9 files changed

+415
-139
lines changed

Diff for: doc/source/io.rst

+18
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,24 @@ one can use the ExcelWriter class, as in the following example:
16811681
df2.to_excel(writer, sheet_name='sheet2')
16821682
writer.save()
16831683
1684+
.. _io.excel.writers:
1685+
1686+
Excel writer engines
1687+
~~~~~~~~~~~~~~~~~~~~
1688+
1689+
.. versionadded:: 0.13
1690+
1691+
``pandas`` chooses an Excel writer via two methods:
1692+
1693+
1. the ``engine`` keyword argument
1694+
2. the filename extension (via the default specified in config options)
1695+
1696+
``pandas`` only supports ``openpyxl`` for ``.xlsx`` and ``.xlsm`` files and
1697+
``xlwt`` for ``.xls`` files. If you have multiple engines installed, you can choose the
1698+
engine to use by default via the options ``io.excel.xlsx.writer`` and
1699+
``io.excel.xls.writer``.
1700+
1701+
16841702
.. _io.hdf5:
16851703
16861704
HDF5 (PyTables)

Diff for: doc/source/release.rst

+8
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ Improvements to existing features
106106
- Add ``axis`` and ``level`` keywords to ``where``, so that the ``other`` argument
107107
can now be an alignable pandas object.
108108
- ``to_datetime`` with a format of '%Y%m%d' now parses much faster
109+
- It's now easier to hook new Excel writers into pandas (just subclass
110+
``ExcelWriter`` and register your engine). You can specify an ``engine`` in
111+
``to_excel`` or in ``ExcelWriter``. You can also specify which writers you
112+
want to use by default with config options ``io.excel.xlsx.writer`` and
113+
``io.excel.xls.writer``. (:issue:`4745`, :issue:`4750`)
114+
- ``Panel.to_excel()`` now accepts keyword arguments that will be passed to
115+
its ``DataFrame``'s ``to_excel()`` methods. (:issue:`4750`)
109116

110117
API Changes
111118
~~~~~~~~~~~
@@ -194,6 +201,7 @@ API Changes
194201
- default for ``tupleize_cols`` is now ``False`` for both ``to_csv`` and ``read_csv``. Fair warning in 0.12 (:issue:`3604`)
195202
- moved timedeltas support to pandas.tseries.timedeltas.py; add timedeltas string parsing,
196203
add top-level ``to_timedelta`` function
204+
- ``NDFrame`` now is compatible with Python's toplevel ``abs()`` function (:issue:`4821`).
197205

198206
Internal Refactoring
199207
~~~~~~~~~~~~~~~~~~~~

Diff for: pandas/core/config.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def _get_single_key(pat, silent):
7373
if len(keys) == 0:
7474
if not silent:
7575
_warn_if_deprecated(pat)
76-
raise KeyError('No such keys(s)')
76+
raise KeyError('No such keys(s): %r' % pat)
7777
if len(keys) > 1:
7878
raise KeyError('Pattern matched multiple keys')
7979
key = keys[0]

Diff for: pandas/core/config_init.py

+21
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,24 @@ def use_inf_as_null_cb(key):
279279
with cf.config_prefix('mode'):
280280
cf.register_option('use_inf_as_null', False, use_inf_as_null_doc,
281281
cb=use_inf_as_null_cb)
282+
283+
284+
# Set up the io.excel specific configuration.
285+
writer_engine_doc = """
286+
: string
287+
The default Excel writer engine for '{ext}' files. Available options: '{default}' (the default){others}.
288+
"""
289+
290+
with cf.config_prefix('io.excel'):
291+
# going forward, will be additional writers
292+
for ext, options in [('xls', ['xlwt']),
293+
('xlsm', ['openpyxl']),
294+
('xlsx', ['openpyxl'])]:
295+
default = options.pop(0)
296+
if options:
297+
options = " " + ", ".join(options)
298+
else:
299+
options = ""
300+
doc = writer_engine_doc.format(ext=ext, default=default,
301+
others=options)
302+
cf.register_option(ext + '.writer', default, doc, validator=str)

Diff for: pandas/core/format.py

+2-9
Original file line numberDiff line numberDiff line change
@@ -1146,15 +1146,8 @@ class ExcelFormatter(object):
11461146
sequence should be given if the DataFrame uses MultiIndex.
11471147
"""
11481148

1149-
def __init__(self,
1150-
df,
1151-
na_rep='',
1152-
float_format=None,
1153-
cols=None,
1154-
header=True,
1155-
index=True,
1156-
index_label=None
1157-
):
1149+
def __init__(self, df, na_rep='', float_format=None, cols=None,
1150+
header=True, index=True, index_label=None):
11581151
self.df = df
11591152
self.rowcounter = 0
11601153
self.na_rep = na_rep

Diff for: pandas/core/frame.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,7 @@ def to_csv(self, path_or_buf, sep=",", na_rep='', float_format=None,
13541354

13551355
def to_excel(self, excel_writer, sheet_name='sheet1', na_rep='',
13561356
float_format=None, cols=None, header=True, index=True,
1357-
index_label=None, startrow=0, startcol=0):
1357+
index_label=None, startrow=0, startcol=0, engine=None):
13581358
"""
13591359
Write DataFrame to a excel sheet
13601360
@@ -1381,6 +1381,10 @@ def to_excel(self, excel_writer, sheet_name='sheet1', na_rep='',
13811381
sequence should be given if the DataFrame uses MultiIndex.
13821382
startow : upper left cell row to dump data frame
13831383
startcol : upper left cell column to dump data frame
1384+
engine : string, default None
1385+
write engine to use - you can also set this via the options
1386+
``io.excel.xlsx.writer``, ``io.excel.xls.writer``, and
1387+
``io.excel.xlsm.writer``.
13841388
13851389
13861390
Notes
@@ -1396,7 +1400,7 @@ def to_excel(self, excel_writer, sheet_name='sheet1', na_rep='',
13961400
from pandas.io.excel import ExcelWriter
13971401
need_save = False
13981402
if isinstance(excel_writer, compat.string_types):
1399-
excel_writer = ExcelWriter(excel_writer)
1403+
excel_writer = ExcelWriter(excel_writer, engine=engine)
14001404
need_save = True
14011405

14021406
formatter = fmt.ExcelFormatter(self,

Diff for: pandas/core/panel.py

+35-4
Original file line numberDiff line numberDiff line change
@@ -458,22 +458,53 @@ def to_sparse(self, fill_value=None, kind='block'):
458458
default_kind=kind,
459459
default_fill_value=fill_value)
460460

461-
def to_excel(self, path, na_rep=''):
461+
def to_excel(self, path, na_rep='', engine=None, **kwargs):
462462
"""
463463
Write each DataFrame in Panel to a separate excel sheet
464464
465465
Parameters
466466
----------
467-
excel_writer : string or ExcelWriter object
467+
path : string or ExcelWriter object
468468
File path or existing ExcelWriter
469469
na_rep : string, default ''
470470
Missing data representation
471+
engine : string, default None
472+
write engine to use - you can also set this via the options
473+
``io.excel.xlsx.writer``, ``io.excel.xls.writer``, and
474+
``io.excel.xlsm.writer``.
475+
476+
Keyword Arguments
477+
-----------------
478+
float_format : string, default None
479+
Format string for floating point numbers
480+
cols : sequence, optional
481+
Columns to write
482+
header : boolean or list of string, default True
483+
Write out column names. If a list of string is given it is
484+
assumed to be aliases for the column names
485+
index : boolean, default True
486+
Write row names (index)
487+
index_label : string or sequence, default None
488+
Column label for index column(s) if desired. If None is given, and
489+
`header` and `index` are True, then the index names are used. A
490+
sequence should be given if the DataFrame uses MultiIndex.
491+
startow : upper left cell row to dump data frame
492+
startcol : upper left cell column to dump data frame
493+
494+
Keyword arguments (and na_rep) are passed to the ``to_excel`` method
495+
for each DataFrame written.
471496
"""
472497
from pandas.io.excel import ExcelWriter
473-
writer = ExcelWriter(path)
498+
499+
if isinstance(path, compat.string_types):
500+
writer = ExcelWriter(path, engine=engine)
501+
else:
502+
writer = path
503+
kwargs['na_rep'] = na_rep
504+
474505
for item, df in compat.iteritems(self):
475506
name = str(item)
476-
df.to_excel(writer, name, na_rep=na_rep)
507+
df.to_excel(writer, name, **kwargs)
477508
writer.save()
478509

479510
def as_matrix(self):

0 commit comments

Comments
 (0)