From bb560a90a532e24b73dac0407764e0624afa535b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 20 Mar 2022 09:38:21 -0400 Subject: [PATCH 1/5] BUG: ExcelWriter's engine and supported_extensions are properties --- pandas/io/excel/_base.py | 15 ++++++++------- pandas/io/excel/_odswriter.py | 4 ++-- pandas/io/excel/_openpyxl.py | 4 ++-- pandas/io/excel/_xlsxwriter.py | 4 ++-- pandas/io/excel/_xlwt.py | 4 ++-- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 40007a0abe233..60723fd06c175 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -945,9 +945,9 @@ class ExcelWriter(metaclass=abc.ABCMeta): # - Mandatory # - ``write_cells(self, cells, sheet_name=None, startrow=0, startcol=0)`` # --> called to write additional DataFrames to disk - # - ``supported_extensions`` (tuple of supported extensions), used to + # - ``_supported_extensions`` (tuple of supported extensions), used to # check that engine supports the given extension. - # - ``engine`` - string that gives the engine name. Necessary to + # - ``_engine`` - string that gives the engine name. Necessary to # instantiate class directly and bypass ``ExcelWriterMeta`` engine # lookup. # - ``save(self)`` --> called to save file to disk @@ -961,6 +961,10 @@ class ExcelWriter(metaclass=abc.ABCMeta): # You also need to register the class with ``register_writer()``. # Technically, ExcelWriter implementations don't need to subclass # ExcelWriter. + + _engine: str + _supported_extensions: tuple[str, ...] | list[str] + def __new__( cls, path: FilePath | WriteExcelBuffer | ExcelWriter, @@ -983,7 +987,6 @@ def __new__( ) # only switch class if generic(ExcelWriter) - if cls is ExcelWriter: if engine is None or (isinstance(engine, str) and engine == "auto"): if isinstance(path, str): @@ -1027,16 +1030,14 @@ def __new__( _path = None @property - @abc.abstractmethod def supported_extensions(self) -> tuple[str, ...] | list[str]: """Extensions that writer engine supports.""" - pass + return self._supported_extensions @property - @abc.abstractmethod def engine(self) -> str: """Name of engine.""" - pass + return self._engine @property @abc.abstractmethod diff --git a/pandas/io/excel/_odswriter.py b/pandas/io/excel/_odswriter.py index 4f127f7c2f867..f5367df6f228d 100644 --- a/pandas/io/excel/_odswriter.py +++ b/pandas/io/excel/_odswriter.py @@ -25,8 +25,8 @@ class ODSWriter(ExcelWriter): - engine = "odf" - supported_extensions = (".ods",) + _engine = "odf" + _supported_extensions = (".ods",) def __init__( self, diff --git a/pandas/io/excel/_openpyxl.py b/pandas/io/excel/_openpyxl.py index af0ae29a76988..6d70b3f319f37 100644 --- a/pandas/io/excel/_openpyxl.py +++ b/pandas/io/excel/_openpyxl.py @@ -36,8 +36,8 @@ class OpenpyxlWriter(ExcelWriter): - engine = "openpyxl" - supported_extensions = (".xlsx", ".xlsm") + _engine = "openpyxl" + _supported_extensions = (".xlsx", ".xlsm") def __init__( self, diff --git a/pandas/io/excel/_xlsxwriter.py b/pandas/io/excel/_xlsxwriter.py index f789378720613..302d0281019f5 100644 --- a/pandas/io/excel/_xlsxwriter.py +++ b/pandas/io/excel/_xlsxwriter.py @@ -169,8 +169,8 @@ def convert(cls, style_dict, num_format_str=None): class XlsxWriter(ExcelWriter): - engine = "xlsxwriter" - supported_extensions = (".xlsx",) + _engine = "xlsxwriter" + _supported_extensions = (".xlsx",) def __init__( self, diff --git a/pandas/io/excel/_xlwt.py b/pandas/io/excel/_xlwt.py index 5f723da61dde4..234d9e72de10d 100644 --- a/pandas/io/excel/_xlwt.py +++ b/pandas/io/excel/_xlwt.py @@ -25,8 +25,8 @@ class XlwtWriter(ExcelWriter): - engine = "xlwt" - supported_extensions = (".xls",) + _engine = "xlwt" + _supported_extensions = (".xls",) def __init__( self, From 1f3241f7fc73a20b2d5d747d1537418d1503de69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 20 Mar 2022 17:08:56 -0400 Subject: [PATCH 2/5] adjust register_writer --- pandas/io/excel/_util.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/io/excel/_util.py b/pandas/io/excel/_util.py index 6be5ef0f64e16..c315657170a97 100644 --- a/pandas/io/excel/_util.py +++ b/pandas/io/excel/_util.py @@ -41,9 +41,7 @@ def register_writer(klass: ExcelWriter_t) -> None: """ if not callable(klass): raise ValueError("Can only register callables as engines") - engine_name = klass.engine - # for mypy - assert isinstance(engine_name, str) + engine_name = klass._engine _writers[engine_name] = klass From 9640b02cc4ca9f5669a528882be18dbc58748297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 20 Mar 2022 19:44:09 -0400 Subject: [PATCH 3/5] need to use _supported_extensions for class access :( --- pandas/io/excel/_base.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 60723fd06c175..fc34c2dc266ca 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -1293,12 +1293,7 @@ def check_extension(cls, ext: str) -> Literal[True]: """ if ext.startswith("."): ext = ext[1:] - # error: "Callable[[ExcelWriter], Any]" has no attribute "__iter__" (not - # iterable) - if not any( - ext in extension - for extension in cls.supported_extensions # type: ignore[attr-defined] - ): + if not any(ext in extension for extension in cls._supported_extensions): raise ValueError(f"Invalid extension for engine '{cls.engine}': '{ext}'") else: return True From ecee1acbf2a4e69b2ed8c68911bae38b4b978634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 20 Mar 2022 20:47:01 -0400 Subject: [PATCH 4/5] adjust test_register_writer --- pandas/tests/io/excel/test_writers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/io/excel/test_writers.py b/pandas/tests/io/excel/test_writers.py index 5b46c0baac165..845d327a41ba9 100644 --- a/pandas/tests/io/excel/test_writers.py +++ b/pandas/tests/io/excel/test_writers.py @@ -1313,8 +1313,8 @@ class DummyClass(ExcelWriter): called_save = False called_write_cells = False called_sheets = False - supported_extensions = ["xlsx", "xls"] - engine = "dummy" + _supported_extensions = ["xlsx", "xls"] + _engine = "dummy" def book(self): pass From d0a00f4bb88c441846dfe8081be0d53a2fb5a830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 20 Mar 2022 23:37:21 -0400 Subject: [PATCH 5/5] cannot be list --- pandas/io/excel/_base.py | 4 ++-- pandas/tests/io/excel/test_writers.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index fc34c2dc266ca..030ae9fefda98 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -963,7 +963,7 @@ class ExcelWriter(metaclass=abc.ABCMeta): # ExcelWriter. _engine: str - _supported_extensions: tuple[str, ...] | list[str] + _supported_extensions: tuple[str, ...] def __new__( cls, @@ -1030,7 +1030,7 @@ def __new__( _path = None @property - def supported_extensions(self) -> tuple[str, ...] | list[str]: + def supported_extensions(self) -> tuple[str, ...]: """Extensions that writer engine supports.""" return self._supported_extensions diff --git a/pandas/tests/io/excel/test_writers.py b/pandas/tests/io/excel/test_writers.py index 845d327a41ba9..de855fa30b88d 100644 --- a/pandas/tests/io/excel/test_writers.py +++ b/pandas/tests/io/excel/test_writers.py @@ -1313,7 +1313,7 @@ class DummyClass(ExcelWriter): called_save = False called_write_cells = False called_sheets = False - _supported_extensions = ["xlsx", "xls"] + _supported_extensions = ("xlsx", "xls") _engine = "dummy" def book(self):