From bc6534ac897a74cdd75cc0f6b6bdc666c5afbc93 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Fri, 25 Jun 2021 15:55:43 +0200 Subject: [PATCH 01/12] ENH: add if_sheet_exists='write_to' to ExcelWriter --- pandas/io/excel/_base.py | 28 +++++++++++++++++++++++--- pandas/io/excel/_openpyxl.py | 4 +++- pandas/tests/io/excel/test_openpyxl.py | 3 ++- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 52d1e1c83d3e6..2400b200693a4 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -681,13 +681,14 @@ class ExcelWriter(metaclass=abc.ABCMeta): be parsed by ``fsspec``, e.g., starting "s3://", "gcs://". .. versionadded:: 1.2.0 - if_sheet_exists : {'error', 'new', 'replace'}, default 'error' + : {'error', 'new', 'replace', 'write_to'}, default 'error' How to behave when trying to write to a sheet that already exists (append mode only). * error: raise a ValueError. * new: Create a new sheet, with a name determined by the engine. * replace: Delete the contents of the sheet before writing to it. + * write_to: Write contents to the existing sheet. .. versionadded:: 1.3.0 engine_kwargs : dict, optional @@ -755,6 +756,27 @@ class ExcelWriter(metaclass=abc.ABCMeta): >>> with ExcelWriter("path_to_file.xlsx", mode="a", engine="openpyxl") as writer: ... df.to_excel(writer, sheet_name="Sheet3") + Here, the `if_sheet_exists` parameter can be set to replace a sheet if it + already exists: + + >>> with ExcelWriter( + ... "path_to_file.xlsx", + ... mode="a", + ... engine="openpyxl", + ... if_sheet_exists="replace" + ... ) as writer: + ... df.to_excel(writer, sheet_name="Sheet1") + + You can specify arguments to the underlying engine. For example to not + calculate the result of a formula: + + >>> df = pd.DataFrame(["=1+1"]) + ... with ExcelWriter( + ... "path_to_file.xlsx", + ... engine_kwargs={"strings_to_formulas":False} + ... ) as writer: + ... df.to_excel(writer) + You can store Excel file in RAM: >>> import io @@ -940,10 +962,10 @@ def __init__( self.mode = mode - if if_sheet_exists not in [None, "error", "new", "replace"]: + if if_sheet_exists not in [None, "error", "new", "replace", "write_to"]: raise ValueError( f"'{if_sheet_exists}' is not valid for if_sheet_exists. " - "Valid options are 'error', 'new' and 'replace'." + "Valid options are 'error', 'new', 'replace' and 'write_to'." ) if if_sheet_exists and "r+" not in mode: raise ValueError("if_sheet_exists is only valid in append mode (mode='a')") diff --git a/pandas/io/excel/_openpyxl.py b/pandas/io/excel/_openpyxl.py index d499f1a5ea89f..f7c90236e44e1 100644 --- a/pandas/io/excel/_openpyxl.py +++ b/pandas/io/excel/_openpyxl.py @@ -437,10 +437,12 @@ def write_cells( f"Sheet '{sheet_name}' already exists and " f"if_sheet_exists is set to 'error'." ) + elif self.if_sheet_exists == "write_to": + wks = self.sheets[sheet_name] else: raise ValueError( f"'{self.if_sheet_exists}' is not valid for if_sheet_exists. " - "Valid options are 'error', 'new' and 'replace'." + "Valid options are 'error', 'new', 'replace' and 'write_to'." ) else: wks = self.sheets[sheet_name] diff --git a/pandas/tests/io/excel/test_openpyxl.py b/pandas/tests/io/excel/test_openpyxl.py index cd773957c9043..386427ce6a46a 100644 --- a/pandas/tests/io/excel/test_openpyxl.py +++ b/pandas/tests/io/excel/test_openpyxl.py @@ -139,6 +139,7 @@ def test_write_append_mode(ext, mode, expected): [ ("new", 2, ["apple", "banana"]), ("replace", 1, ["pear"]), + ("write_to", 1, ["pear", "banana"]), ], ) def test_if_sheet_exists_append_modes(ext, if_sheet_exists, num_sheets, expected): @@ -170,7 +171,7 @@ def test_if_sheet_exists_append_modes(ext, if_sheet_exists, num_sheets, expected ( "invalid", "'invalid' is not valid for if_sheet_exists. Valid options " - "are 'error', 'new' and 'replace'.", + "are 'error', 'new', 'replace' and 'write_to'.", ), ( "error", From 66fcd15c9ef730ecffd037491df33a3ffa06e238 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Sat, 26 Jun 2021 14:27:24 +0200 Subject: [PATCH 02/12] DOC: added docs to #42222 --- pandas/io/excel/_base.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 2400b200693a4..bfbb19a8f6d28 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -681,7 +681,7 @@ class ExcelWriter(metaclass=abc.ABCMeta): be parsed by ``fsspec``, e.g., starting "s3://", "gcs://". .. versionadded:: 1.2.0 - : {'error', 'new', 'replace', 'write_to'}, default 'error' + if_sheet_exists : {'error', 'new', 'replace', 'write_to'}, default 'error' How to behave when trying to write to a sheet that already exists (append mode only). @@ -763,19 +763,21 @@ class ExcelWriter(metaclass=abc.ABCMeta): ... "path_to_file.xlsx", ... mode="a", ... engine="openpyxl", - ... if_sheet_exists="replace" + ... if_sheet_exists="replace", ... ) as writer: - ... df.to_excel(writer, sheet_name="Sheet1") + >>> df.to_excel(writer, sheet_name="Sheet1") - You can specify arguments to the underlying engine. For example to not - calculate the result of a formula: + You can also write multiple DataFrames to a single sheet. Note that the + `if_sheet_exists` parameter needs to be set to `write_to` if you are in + append mode: - >>> df = pd.DataFrame(["=1+1"]) - ... with ExcelWriter( - ... "path_to_file.xlsx", - ... engine_kwargs={"strings_to_formulas":False} + >>> with ExcelWriter("path_to_file.xlsx", + ... mode="a", + ... engine="openpyxl", + ... if_sheet_exists="write_to", ... ) as writer: - ... df.to_excel(writer) + >>> df.to_excel(writer, sheet_name="Sheet1") + >>> df.to_excel(writer, sheet_name="Sheet1", startcol=3) You can store Excel file in RAM: From cb59157ba08205d640d1d5d7a5c77ce8c6250e84 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Mon, 23 Aug 2021 20:51:06 +0200 Subject: [PATCH 03/12] resolved comments --- pandas/io/excel/_base.py | 16 ++++++++-------- pandas/tests/io/excel/test_openpyxl.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index bfbb19a8f6d28..30bec12df13bc 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -681,14 +681,14 @@ class ExcelWriter(metaclass=abc.ABCMeta): be parsed by ``fsspec``, e.g., starting "s3://", "gcs://". .. versionadded:: 1.2.0 - if_sheet_exists : {'error', 'new', 'replace', 'write_to'}, default 'error' + if_sheet_exists : {'error', 'new', 'replace', 'overwrite_cells'}, default 'error' How to behave when trying to write to a sheet that already exists (append mode only). * error: raise a ValueError. * new: Create a new sheet, with a name determined by the engine. * replace: Delete the contents of the sheet before writing to it. - * write_to: Write contents to the existing sheet. + * overwrite_cells: Write contents to the existing sheet. .. versionadded:: 1.3.0 engine_kwargs : dict, optional @@ -768,16 +768,16 @@ class ExcelWriter(metaclass=abc.ABCMeta): >>> df.to_excel(writer, sheet_name="Sheet1") You can also write multiple DataFrames to a single sheet. Note that the - `if_sheet_exists` parameter needs to be set to `write_to` if you are in + `if_sheet_exists` parameter needs to be set to `overwrite_cells` if you are in append mode: >>> with ExcelWriter("path_to_file.xlsx", ... mode="a", ... engine="openpyxl", - ... if_sheet_exists="write_to", + ... if_sheet_exists="overwrite_cells", ... ) as writer: - >>> df.to_excel(writer, sheet_name="Sheet1") - >>> df.to_excel(writer, sheet_name="Sheet1", startcol=3) + >>> df1.to_excel(writer, sheet_name="Sheet1") + >>> df2.to_excel(writer, sheet_name="Sheet1", startcol=3) You can store Excel file in RAM: @@ -964,10 +964,10 @@ def __init__( self.mode = mode - if if_sheet_exists not in [None, "error", "new", "replace", "write_to"]: + if if_sheet_exists not in [None, "error", "new", "replace", "overwrite_cells"]: raise ValueError( f"'{if_sheet_exists}' is not valid for if_sheet_exists. " - "Valid options are 'error', 'new', 'replace' and 'write_to'." + "Valid options are 'error', 'new', 'replace' and 'overwrite_cells'." ) if if_sheet_exists and "r+" not in mode: raise ValueError("if_sheet_exists is only valid in append mode (mode='a')") diff --git a/pandas/tests/io/excel/test_openpyxl.py b/pandas/tests/io/excel/test_openpyxl.py index 386427ce6a46a..269fbe5f5565b 100644 --- a/pandas/tests/io/excel/test_openpyxl.py +++ b/pandas/tests/io/excel/test_openpyxl.py @@ -139,7 +139,7 @@ def test_write_append_mode(ext, mode, expected): [ ("new", 2, ["apple", "banana"]), ("replace", 1, ["pear"]), - ("write_to", 1, ["pear", "banana"]), + ("overwrite_cells", 1, ["pear", "banana"]), ], ) def test_if_sheet_exists_append_modes(ext, if_sheet_exists, num_sheets, expected): @@ -171,7 +171,7 @@ def test_if_sheet_exists_append_modes(ext, if_sheet_exists, num_sheets, expected ( "invalid", "'invalid' is not valid for if_sheet_exists. Valid options " - "are 'error', 'new', 'replace' and 'write_to'.", + "are 'error', 'new', 'replace' and 'overwrite_cells'.", ), ( "error", From b9ed3276a12dbaec523c2c04abe4043aaed67f90 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 24 Aug 2021 17:45:22 +0200 Subject: [PATCH 04/12] versionadded, fix tests --- pandas/io/excel/_base.py | 2 +- pandas/io/excel/_openpyxl.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 30bec12df13bc..19700ac23bddd 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -680,7 +680,7 @@ class ExcelWriter(metaclass=abc.ABCMeta): host, port, username, password, etc., if using a URL that will be parsed by ``fsspec``, e.g., starting "s3://", "gcs://". - .. versionadded:: 1.2.0 + .. versionadded:: 1.4.0 if_sheet_exists : {'error', 'new', 'replace', 'overwrite_cells'}, default 'error' How to behave when trying to write to a sheet that already exists (append mode only). diff --git a/pandas/io/excel/_openpyxl.py b/pandas/io/excel/_openpyxl.py index f7c90236e44e1..c437b4ac3c16c 100644 --- a/pandas/io/excel/_openpyxl.py +++ b/pandas/io/excel/_openpyxl.py @@ -437,12 +437,12 @@ def write_cells( f"Sheet '{sheet_name}' already exists and " f"if_sheet_exists is set to 'error'." ) - elif self.if_sheet_exists == "write_to": + elif self.if_sheet_exists == "overwrite_cells": wks = self.sheets[sheet_name] else: raise ValueError( f"'{self.if_sheet_exists}' is not valid for if_sheet_exists. " - "Valid options are 'error', 'new', 'replace' and 'write_to'." + "Valid options are 'error', 'new', 'replace' and 'overwrite_cells'." ) else: wks = self.sheets[sheet_name] From 211683d2aafb9d5ef624203a1b9721639ee5ccdb Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 7 Sep 2021 08:47:03 +0200 Subject: [PATCH 05/12] renamed overwrite_cells to overlay --- pandas/io/excel/_base.py | 16 +++++++++------- pandas/io/excel/_openpyxl.py | 4 ++-- pandas/tests/io/excel/test_openpyxl.py | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 19700ac23bddd..18beaa777ccb6 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -680,15 +680,17 @@ class ExcelWriter(metaclass=abc.ABCMeta): host, port, username, password, etc., if using a URL that will be parsed by ``fsspec``, e.g., starting "s3://", "gcs://". - .. versionadded:: 1.4.0 - if_sheet_exists : {'error', 'new', 'replace', 'overwrite_cells'}, default 'error' + .. versionadded:: 1.2.0 + if_sheet_exists : {'error', 'new', 'replace', 'overlay'}, default 'error' How to behave when trying to write to a sheet that already exists (append mode only). * error: raise a ValueError. * new: Create a new sheet, with a name determined by the engine. * replace: Delete the contents of the sheet before writing to it. - * overwrite_cells: Write contents to the existing sheet. + ..versionadded:: 1.4.0 + * overlay: Write contents to the existing sheet without removing the old + contents. .. versionadded:: 1.3.0 engine_kwargs : dict, optional @@ -768,13 +770,13 @@ class ExcelWriter(metaclass=abc.ABCMeta): >>> df.to_excel(writer, sheet_name="Sheet1") You can also write multiple DataFrames to a single sheet. Note that the - `if_sheet_exists` parameter needs to be set to `overwrite_cells` if you are in + `if_sheet_exists` parameter needs to be set to `overlay` if you are in append mode: >>> with ExcelWriter("path_to_file.xlsx", ... mode="a", ... engine="openpyxl", - ... if_sheet_exists="overwrite_cells", + ... if_sheet_exists="overlay", ... ) as writer: >>> df1.to_excel(writer, sheet_name="Sheet1") >>> df2.to_excel(writer, sheet_name="Sheet1", startcol=3) @@ -964,10 +966,10 @@ def __init__( self.mode = mode - if if_sheet_exists not in [None, "error", "new", "replace", "overwrite_cells"]: + if if_sheet_exists not in [None, "error", "new", "replace", "overlay"]: raise ValueError( f"'{if_sheet_exists}' is not valid for if_sheet_exists. " - "Valid options are 'error', 'new', 'replace' and 'overwrite_cells'." + "Valid options are 'error', 'new', 'replace' and 'overlay'." ) if if_sheet_exists and "r+" not in mode: raise ValueError("if_sheet_exists is only valid in append mode (mode='a')") diff --git a/pandas/io/excel/_openpyxl.py b/pandas/io/excel/_openpyxl.py index c437b4ac3c16c..cc91aebc1706e 100644 --- a/pandas/io/excel/_openpyxl.py +++ b/pandas/io/excel/_openpyxl.py @@ -437,12 +437,12 @@ def write_cells( f"Sheet '{sheet_name}' already exists and " f"if_sheet_exists is set to 'error'." ) - elif self.if_sheet_exists == "overwrite_cells": + elif self.if_sheet_exists == "overlay": wks = self.sheets[sheet_name] else: raise ValueError( f"'{self.if_sheet_exists}' is not valid for if_sheet_exists. " - "Valid options are 'error', 'new', 'replace' and 'overwrite_cells'." + "Valid options are 'error', 'new', 'replace' and 'overlay'." ) else: wks = self.sheets[sheet_name] diff --git a/pandas/tests/io/excel/test_openpyxl.py b/pandas/tests/io/excel/test_openpyxl.py index 269fbe5f5565b..eb6aea23d2fc3 100644 --- a/pandas/tests/io/excel/test_openpyxl.py +++ b/pandas/tests/io/excel/test_openpyxl.py @@ -139,7 +139,7 @@ def test_write_append_mode(ext, mode, expected): [ ("new", 2, ["apple", "banana"]), ("replace", 1, ["pear"]), - ("overwrite_cells", 1, ["pear", "banana"]), + ("overlay", 1, ["pear", "banana"]), ], ) def test_if_sheet_exists_append_modes(ext, if_sheet_exists, num_sheets, expected): @@ -171,7 +171,7 @@ def test_if_sheet_exists_append_modes(ext, if_sheet_exists, num_sheets, expected ( "invalid", "'invalid' is not valid for if_sheet_exists. Valid options " - "are 'error', 'new', 'replace' and 'overwrite_cells'.", + "are 'error', 'new', 'replace' and 'overlay'.", ), ( "error", From a226668cd65ecc6d3c0d191271d7665e876d85f1 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 7 Sep 2021 15:54:45 +0200 Subject: [PATCH 06/12] small fixes, docs build well --- pandas/io/excel/_base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 18beaa777ccb6..70522d72e8e86 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -688,7 +688,8 @@ class ExcelWriter(metaclass=abc.ABCMeta): * error: raise a ValueError. * new: Create a new sheet, with a name determined by the engine. * replace: Delete the contents of the sheet before writing to it. - ..versionadded:: 1.4.0 + + .. versionadded:: 1.4.0 * overlay: Write contents to the existing sheet without removing the old contents. @@ -770,8 +771,7 @@ class ExcelWriter(metaclass=abc.ABCMeta): >>> df.to_excel(writer, sheet_name="Sheet1") You can also write multiple DataFrames to a single sheet. Note that the - `if_sheet_exists` parameter needs to be set to `overlay` if you are in - append mode: + `if_sheet_exists` parameter needs to be set to `overlay`: >>> with ExcelWriter("path_to_file.xlsx", ... mode="a", From 087274ad50bff98c7e6c556c8fb276dc22f83c18 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Wed, 8 Sep 2021 10:34:09 +0200 Subject: [PATCH 07/12] ENH: GH42222 fixed comments --- pandas/io/excel/_base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 70522d72e8e86..ae49b8c749d32 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -768,18 +768,18 @@ class ExcelWriter(metaclass=abc.ABCMeta): ... engine="openpyxl", ... if_sheet_exists="replace", ... ) as writer: - >>> df.to_excel(writer, sheet_name="Sheet1") + ... df.to_excel(writer, sheet_name="Sheet1") You can also write multiple DataFrames to a single sheet. Note that the - `if_sheet_exists` parameter needs to be set to `overlay`: + ``if_sheet_exists`` parameter needs to be set to ``overlay``: >>> with ExcelWriter("path_to_file.xlsx", ... mode="a", ... engine="openpyxl", ... if_sheet_exists="overlay", ... ) as writer: - >>> df1.to_excel(writer, sheet_name="Sheet1") - >>> df2.to_excel(writer, sheet_name="Sheet1", startcol=3) + ... df1.to_excel(writer, sheet_name="Sheet1") + ... df2.to_excel(writer, sheet_name="Sheet1", startcol=3) You can store Excel file in RAM: From 9f79b0fcdf0e814d094d572b220859e38913e2df Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Mon, 20 Sep 2021 17:44:20 +0200 Subject: [PATCH 08/12] ENH: GH42222 versionchanged --- pandas/io/excel/_base.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index ae49b8c749d32..229f2ed8b0512 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -680,7 +680,7 @@ class ExcelWriter(metaclass=abc.ABCMeta): host, port, username, password, etc., if using a URL that will be parsed by ``fsspec``, e.g., starting "s3://", "gcs://". - .. versionadded:: 1.2.0 + .. versionchanged:: 1.4.0 if_sheet_exists : {'error', 'new', 'replace', 'overlay'}, default 'error' How to behave when trying to write to a sheet that already exists (append mode only). @@ -688,8 +688,6 @@ class ExcelWriter(metaclass=abc.ABCMeta): * error: raise a ValueError. * new: Create a new sheet, with a name determined by the engine. * replace: Delete the contents of the sheet before writing to it. - - .. versionadded:: 1.4.0 * overlay: Write contents to the existing sheet without removing the old contents. From e7362eb05bce83ddff3f464fe5da0502b9dc5ed8 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Thu, 4 Nov 2021 16:24:01 +0100 Subject: [PATCH 09/12] ENH: GH42222 fixed indent --- pandas/io/excel/_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 229f2ed8b0512..ec80495b4f0ca 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -689,7 +689,7 @@ class ExcelWriter(metaclass=abc.ABCMeta): * new: Create a new sheet, with a name determined by the engine. * replace: Delete the contents of the sheet before writing to it. * overlay: Write contents to the existing sheet without removing the old - contents. + contents. .. versionadded:: 1.3.0 engine_kwargs : dict, optional From d0a4565ccaac6f2927811db1332c23e839722c89 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Fri, 5 Nov 2021 16:44:52 +0100 Subject: [PATCH 10/12] ENH: GH 42222 @twoertwein's comments --- pandas/io/excel/_base.py | 10 ++++++-- pandas/tests/io/excel/test_openpyxl.py | 34 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/pandas/io/excel/_base.py b/pandas/io/excel/_base.py index 70c0def10a2ab..bb0afb0c82f5d 100644 --- a/pandas/io/excel/_base.py +++ b/pandas/io/excel/_base.py @@ -689,7 +689,8 @@ class ExcelWriter(metaclass=abc.ABCMeta): host, port, username, password, etc., if using a URL that will be parsed by ``fsspec``, e.g., starting "s3://", "gcs://". - .. versionchanged:: 1.4.0 + .. versionadded:: 1.2.0 + if_sheet_exists : {'error', 'new', 'replace', 'overlay'}, default 'error' How to behave when trying to write to a sheet that already exists (append mode only). @@ -701,6 +702,11 @@ class ExcelWriter(metaclass=abc.ABCMeta): contents. .. versionadded:: 1.3.0 + + .. versionchanged:: 1.4.0 + + Added ``overlay`` option + engine_kwargs : dict, optional Keyword arguments to be passed into the engine. @@ -973,7 +979,7 @@ def __init__( self.mode = mode - if if_sheet_exists not in [None, "error", "new", "replace", "overlay"]: + if if_sheet_exists not in (None, "error", "new", "replace", "overlay"): raise ValueError( f"'{if_sheet_exists}' is not valid for if_sheet_exists. " "Valid options are 'error', 'new', 'replace' and 'overlay'." diff --git a/pandas/tests/io/excel/test_openpyxl.py b/pandas/tests/io/excel/test_openpyxl.py index eb6aea23d2fc3..0036e948ce02b 100644 --- a/pandas/tests/io/excel/test_openpyxl.py +++ b/pandas/tests/io/excel/test_openpyxl.py @@ -165,6 +165,40 @@ def test_if_sheet_exists_append_modes(ext, if_sheet_exists, num_sheets, expected wb.close() +@pytest.mark.parametrize( + "startrow, startcol, greeting, goodbye", + [ + (0, 0, ["poop", "world"], ["goodbye", "people"]), + (0, 1, ["hello", "world"], ["poop", "people"]), + (1, 0, ["hello", "poop"], ["goodbye", "people"]), + (1, 1, ["hello", "world"], ["goodbye", "poop"]), + ], +) +def test_append_overlay_startrow_startcol(ext, startrow, startcol, greeting, goodbye): + df1 = DataFrame({"greeting": ["hello", "world"], "goodbye": ["goodbye", "people"]}) + df2 = DataFrame(["poop"]) + + with tm.ensure_clean(ext) as f: + df1.to_excel(f, engine="openpyxl", sheet_name="poo", index=False) + with ExcelWriter( + f, engine="openpyxl", mode="a", if_sheet_exists="overlay" + ) as writer: + # use startrow+1 because we don't have a header + df2.to_excel( + writer, + index=False, + header=False, + startrow=startrow + 1, + startcol=startcol, + sheet_name="poo", + ) + + result = pd.read_excel(f, sheet_name="poo", engine="openpyxl") + assert ( + list(result["greeting"]) == greeting and list(result["goodbye"]) == goodbye + ) + + @pytest.mark.parametrize( "if_sheet_exists,msg", [ From 54e274d0fac05de6634371a786ed76afcff329c5 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Sat, 6 Nov 2021 11:07:07 +0100 Subject: [PATCH 11/12] ENH: GH 42222 What's new entry --- doc/source/whatsnew/v1.4.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 4d0dee01f05c1..2b6cead0ae696 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -182,7 +182,7 @@ Other enhancements - Added :meth:`.ExponentialMovingWindow.sum` (:issue:`13297`) - :meth:`Series.str.split` now supports a ``regex`` argument that explicitly specifies whether the pattern is a regular expression. Default is ``None`` (:issue:`43563`, :issue:`32835`, :issue:`25549`) - :meth:`DataFrame.dropna` now accepts a single label as ``subset`` along with array-like (:issue:`41021`) -- +- :class:`ExcelWriter` argument ``if_sheet_exists="overlay"`` option added .. --------------------------------------------------------------------------- From aa9afbc4ec979015d580e825c5391bd76eac3f20 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Sun, 7 Nov 2021 13:45:51 +0100 Subject: [PATCH 12/12] ENH: GH42222 whatsnew issue number, improved test --- doc/source/whatsnew/v1.4.0.rst | 2 +- pandas/tests/io/excel/test_openpyxl.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 2b6cead0ae696..e3dc31f623aa4 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -182,7 +182,7 @@ Other enhancements - Added :meth:`.ExponentialMovingWindow.sum` (:issue:`13297`) - :meth:`Series.str.split` now supports a ``regex`` argument that explicitly specifies whether the pattern is a regular expression. Default is ``None`` (:issue:`43563`, :issue:`32835`, :issue:`25549`) - :meth:`DataFrame.dropna` now accepts a single label as ``subset`` along with array-like (:issue:`41021`) -- :class:`ExcelWriter` argument ``if_sheet_exists="overlay"`` option added +- :class:`ExcelWriter` argument ``if_sheet_exists="overlay"`` option added (:issue:`40231`) .. --------------------------------------------------------------------------- diff --git a/pandas/tests/io/excel/test_openpyxl.py b/pandas/tests/io/excel/test_openpyxl.py index 0036e948ce02b..8535dae5f4b24 100644 --- a/pandas/tests/io/excel/test_openpyxl.py +++ b/pandas/tests/io/excel/test_openpyxl.py @@ -194,9 +194,8 @@ def test_append_overlay_startrow_startcol(ext, startrow, startcol, greeting, goo ) result = pd.read_excel(f, sheet_name="poo", engine="openpyxl") - assert ( - list(result["greeting"]) == greeting and list(result["goodbye"]) == goodbye - ) + expected = DataFrame({"greeting": greeting, "goodbye": goodbye}) + tm.assert_frame_equal(result, expected) @pytest.mark.parametrize(