Skip to content

Commit 2ac5580

Browse files
Backport PR #48943 on branch 1.5.x (REGR: ExcelWriter.book not settable) (#48959)
* Backport PR #48943: REGR: ExcelWriter.book not settable * type ignores Co-authored-by: Richard Shadrach <[email protected]>
1 parent 7b2dbec commit 2ac5580

File tree

7 files changed

+84
-5
lines changed

7 files changed

+84
-5
lines changed

doc/source/whatsnew/v1.5.1.rst

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Fixed regressions
8484
- Fixed Regression in :meth:`DataFrameGroupBy.apply` when user defined function is called on an empty dataframe (:issue:`47985`)
8585
- Fixed regression in :meth:`DataFrame.apply` when passing non-zero ``axis`` via keyword argument (:issue:`48656`)
8686
- Fixed regression in :meth:`Series.groupby` and :meth:`DataFrame.groupby` when the grouper is a nullable data type (e.g. :class:`Int64`) or a PyArrow-backed string array, contains null values, and ``dropna=False`` (:issue:`48794`)
87+
- Fixed regression in :class:`ExcelWriter` where the ``book`` attribute could no longer be set; however setting this attribute is now deprecated and this ability will be removed in a future version of pandas (:issue:`48780`)
8788

8889
.. ---------------------------------------------------------------------------
8990

pandas/io/excel/_base.py

+26-2
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,9 @@ def sheets(self) -> dict[str, Any]:
11921192
"""Mapping of sheet names to sheet objects."""
11931193
pass
11941194

1195-
@property
1195+
# mypy doesn't handle abstract setters prior to 0.981
1196+
# https://github.com/python/mypy/issues/4165
1197+
@property # type: ignore[misc]
11961198
@abc.abstractmethod
11971199
def book(self):
11981200
"""
@@ -1202,6 +1204,16 @@ def book(self):
12021204
"""
12031205
pass
12041206

1207+
# mypy doesn't handle abstract setters prior to 0.981
1208+
# https://github.com/python/mypy/issues/4165
1209+
@book.setter # type: ignore[misc]
1210+
@abc.abstractmethod
1211+
def book(self, other) -> None:
1212+
"""
1213+
Set book instance. Class type will depend on the engine used.
1214+
"""
1215+
pass
1216+
12051217
def write_cells(
12061218
self,
12071219
cells,
@@ -1331,12 +1343,24 @@ def _deprecate(self, attr: str):
13311343
Deprecate attribute or method for ExcelWriter.
13321344
"""
13331345
warnings.warn(
1334-
f"{attr} is not part of the public API, usage can give in unexpected "
1346+
f"{attr} is not part of the public API, usage can give unexpected "
13351347
"results and will be removed in a future version",
13361348
FutureWarning,
13371349
stacklevel=find_stack_level(inspect.currentframe()),
13381350
)
13391351

1352+
def _deprecate_set_book(self) -> None:
1353+
"""
1354+
Deprecate setting the book attribute - GH#48780.
1355+
"""
1356+
warnings.warn(
1357+
"Setting the `book` attribute is not part of the public API, "
1358+
"usage can give unexpected or corrupted results and will be "
1359+
"removed in a future version",
1360+
FutureWarning,
1361+
stacklevel=find_stack_level(inspect.currentframe()),
1362+
)
1363+
13401364
@property
13411365
def date_format(self) -> str:
13421366
"""

pandas/io/excel/_odswriter.py

+10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
)
2525

2626
if TYPE_CHECKING:
27+
from odf.opendocument import OpenDocumentSpreadsheet
28+
2729
from pandas.io.formats.excel import ExcelCell
2830

2931

@@ -70,6 +72,14 @@ def book(self):
7072
"""
7173
return self._book
7274

75+
@book.setter
76+
def book(self, other: OpenDocumentSpreadsheet) -> None:
77+
"""
78+
Set book instance. Class type will depend on the engine used.
79+
"""
80+
self._deprecate_set_book()
81+
self._book = other
82+
7383
@property
7484
def sheets(self) -> dict[str, Any]:
7585
"""Mapping of sheet names to sheet objects."""

pandas/io/excel/_openpyxl.py

+8
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ def book(self) -> Workbook:
8888
"""
8989
return self._book
9090

91+
@book.setter
92+
def book(self, other: Workbook) -> None:
93+
"""
94+
Set book instance. Class type will depend on the engine used.
95+
"""
96+
self._deprecate_set_book()
97+
self._book = other
98+
9199
@property
92100
def sheets(self) -> dict[str, Any]:
93101
"""Mapping of sheet names to sheet objects."""

pandas/io/excel/_xlsxwriter.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
from __future__ import annotations
22

3-
from typing import Any
3+
from typing import (
4+
TYPE_CHECKING,
5+
Any,
6+
)
47

58
import pandas._libs.json as json
69
from pandas._typing import (
@@ -15,6 +18,9 @@
1518
validate_freeze_panes,
1619
)
1720

21+
if TYPE_CHECKING:
22+
from xlsxwriter import Workbook
23+
1824

1925
class _XlsxStyler:
2026
# Map from openpyxl-oriented styles to flatter xlsxwriter representation
@@ -218,6 +224,14 @@ def book(self):
218224
"""
219225
return self._book
220226

227+
@book.setter
228+
def book(self, other: Workbook) -> None:
229+
"""
230+
Set book instance. Class type will depend on the engine used.
231+
"""
232+
self._deprecate_set_book()
233+
self._book = other
234+
221235
@property
222236
def sheets(self) -> dict[str, Any]:
223237
result = self.book.sheetnames

pandas/io/excel/_xlwt.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
)
2222

2323
if TYPE_CHECKING:
24-
from xlwt import XFStyle
24+
from xlwt import (
25+
Workbook,
26+
XFStyle,
27+
)
2528

2629

2730
class XlwtWriter(ExcelWriter):
@@ -64,14 +67,22 @@ def __init__(
6467
self._fm_date = xlwt.easyxf(num_format_str=self._date_format)
6568

6669
@property
67-
def book(self):
70+
def book(self) -> Workbook:
6871
"""
6972
Book instance of class xlwt.Workbook.
7073
7174
This attribute can be used to access engine-specific features.
7275
"""
7376
return self._book
7477

78+
@book.setter
79+
def book(self, other: Workbook) -> None:
80+
"""
81+
Set book instance. Class type will depend on the engine used.
82+
"""
83+
self._deprecate_set_book()
84+
self._book = other
85+
7586
@property
7687
def sheets(self) -> dict[str, Any]:
7788
"""Mapping of sheet names to sheet objects."""

pandas/tests/io/excel/test_writers.py

+11
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,17 @@ def test_deprecated_method(self, engine, ext, attr, args):
13011301
with tm.assert_produces_warning(FutureWarning, match=msg):
13021302
getattr(writer, attr)(*args)
13031303

1304+
def test_deprecated_book_setter(self, engine, ext):
1305+
# GH#48780
1306+
with tm.ensure_clean(ext) as path:
1307+
with ExcelWriter(path) as writer:
1308+
msg = "Setting the `book` attribute is not part of the public API"
1309+
# Some engines raise if nothing is written
1310+
DataFrame().to_excel(writer)
1311+
book = writer.book
1312+
with tm.assert_produces_warning(FutureWarning, match=msg):
1313+
writer.book = book
1314+
13041315

13051316
class TestExcelWriterEngineTests:
13061317
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)