From 0bf7f2b41ad9eb964fc2b4de687fb0d0458c37cc Mon Sep 17 00:00:00 2001 From: Yaswanth Kumar <155723049+VYaswanthKumar@users.noreply.github.com> Date: Sat, 11 Oct 2025 12:38:03 +0530 Subject: [PATCH 1/4] TST: Replace ensure_clean_store with temp_file in test_time_series.py Replace ensure_clean_store utility function with the temp_file pytest fixture in pandas/tests/io/pytables/test_time_series.py. Changes: - Remove import of ensure_clean_store from pandas.tests.io.pytables.common - Add HDFStore to pandas imports - Replace setup_path parameter with temp_file in all test functions - Replace context manager usage of ensure_clean_store(setup_path) with HDFStore(temp_file) Contributes to issue #62435 --- pandas/tests/io/pytables/test_time_series.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pandas/tests/io/pytables/test_time_series.py b/pandas/tests/io/pytables/test_time_series.py index 726dd0d420347..3666b186b90db 100644 --- a/pandas/tests/io/pytables/test_time_series.py +++ b/pandas/tests/io/pytables/test_time_series.py @@ -1,34 +1,33 @@ import datetime - import numpy as np import pytest from pandas import ( DataFrame, DatetimeIndex, + HDFStore, Series, _testing as tm, date_range, period_range, ) -from pandas.tests.io.pytables.common import ensure_clean_store pytestmark = pytest.mark.single_cpu @pytest.mark.parametrize("unit", ["us", "ns"]) -def test_store_datetime_fractional_secs(setup_path, unit): +def test_store_datetime_fractional_secs(temp_file, unit): dt = datetime.datetime(2012, 1, 2, 3, 4, 5, 123456) dti = DatetimeIndex([dt], dtype=f"M8[{unit}]") series = Series([0], index=dti) - with ensure_clean_store(setup_path) as store: + with HDFStore(temp_file) as store: store["a"] = series assert store["a"].index[0] == dt @pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning") -def test_tseries_indices_series(setup_path): - with ensure_clean_store(setup_path) as store: +def test_tseries_indices_series(temp_file): + with HDFStore(temp_file) as store: idx = date_range("2020-01-01", periods=10) ser = Series(np.random.default_rng(2).standard_normal(len(idx)), idx) store["a"] = ser @@ -49,8 +48,8 @@ def test_tseries_indices_series(setup_path): @pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning") -def test_tseries_indices_frame(setup_path): - with ensure_clean_store(setup_path) as store: +def test_tseries_indices_frame(temp_file): + with HDFStore(temp_file) as store: idx = date_range("2020-01-01", periods=10) df = DataFrame( np.random.default_rng(2).standard_normal((len(idx), 3)), index=idx From 38557484ca4eac9cd3aab4cd6cd174a450a4567a Mon Sep 17 00:00:00 2001 From: Yaswanth Kumar <155723049+VYaswanthKumar@users.noreply.github.com> Date: Mon, 13 Oct 2025 11:21:21 +0530 Subject: [PATCH 2/4] Restore required blank lines, fix imports, update test signatures to use temp_file --- pandas/tests/io/pytables/test_time_series.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/io/pytables/test_time_series.py b/pandas/tests/io/pytables/test_time_series.py index 3666b186b90db..b44f612d43f9e 100644 --- a/pandas/tests/io/pytables/test_time_series.py +++ b/pandas/tests/io/pytables/test_time_series.py @@ -1,4 +1,5 @@ import datetime + import numpy as np import pytest From ea7e01cf3f6c3d6b4b5653ee3e50abe5e010f973 Mon Sep 17 00:00:00 2001 From: Yaswanth Kumar <155723049+VYaswanthKumar@users.noreply.github.com> Date: Mon, 13 Oct 2025 12:39:55 +0530 Subject: [PATCH 3/4] TST: Fix unused type:ignore comment in _xlsxwriter.py for CI checks --- pandas/io/excel/_xlsxwriter.py | 38 +--------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/pandas/io/excel/_xlsxwriter.py b/pandas/io/excel/_xlsxwriter.py index 5874f720e3bd0..bae0055511e77 100644 --- a/pandas/io/excel/_xlsxwriter.py +++ b/pandas/io/excel/_xlsxwriter.py @@ -1,17 +1,14 @@ from __future__ import annotations - import json from typing import ( TYPE_CHECKING, Any, ) - from pandas.io.excel._base import ExcelWriter from pandas.io.excel._util import ( combine_kwargs, validate_freeze_panes, ) - if TYPE_CHECKING: from pandas._typing import ( ExcelWriterIfSheetExists, @@ -19,8 +16,6 @@ StorageOptions, WriteExcelBuffer, ) - - class _XlsxStyler: # Map from openpyxl-oriented styles to flatter xlsxwriter representation # Ordering necessary for both determinism and because some are keyed by @@ -91,12 +86,10 @@ class _XlsxStyler: (("left",), "left"), ], } - @classmethod def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: """ converts a style_dict to an xlsxwriter format dict - Parameters ---------- style_dict : style dictionary to convert @@ -104,17 +97,13 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: """ # Create a XlsxWriter format object. props = {} - if num_format_str is not None: props["num_format"] = num_format_str - if style_dict is None: return props - if "borders" in style_dict: style_dict = style_dict.copy() style_dict["border"] = style_dict.pop("borders") - for style_group_key, style_group in style_dict.items(): for src, dst in cls.STYLE_MAPPING.get(style_group_key, []): # src is a sequence of keys into a nested dict @@ -129,11 +118,9 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: break else: props[dst] = v - if isinstance(props.get("pattern"), str): # TODO: support other fill patterns props["pattern"] = 0 if props["pattern"] == "none" else 1 - for k in ["border", "top", "right", "bottom", "left"]: if isinstance(props.get(k), str): try: @@ -155,12 +142,10 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: ].index(props[k]) except ValueError: props[k] = 2 - if isinstance(props.get("font_script"), str): props["font_script"] = ["baseline", "superscript", "subscript"].index( props["font_script"] ) - if isinstance(props.get("underline"), str): props["underline"] = { "none": 0, @@ -169,18 +154,13 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: "singleAccounting": 33, "doubleAccounting": 34, }[props["underline"]] - # GH 30107 - xlsxwriter uses different name if props.get("valign") == "center": props["valign"] = "vcenter" - return props - - class XlsxWriter(ExcelWriter): _engine = "xlsxwriter" _supported_extensions = (".xlsx",) - def __init__( # pyright: ignore[reportInconsistentConstructor] self, path: FilePath | WriteExcelBuffer | ExcelWriter, @@ -195,12 +175,9 @@ def __init__( # pyright: ignore[reportInconsistentConstructor] ) -> None: # Use the xlsxwriter module as the Excel writer. from xlsxwriter import Workbook - engine_kwargs = combine_kwargs(engine_kwargs, kwargs) - if mode == "a": raise ValueError("Append mode is not supported with xlsxwriter!") - super().__init__( path, engine=engine, @@ -211,33 +188,27 @@ def __init__( # pyright: ignore[reportInconsistentConstructor] if_sheet_exists=if_sheet_exists, engine_kwargs=engine_kwargs, ) - try: - self._book = Workbook(self._handles.handle, **engine_kwargs) # type: ignore[arg-type] + self._book = Workbook(self._handles.handle, **engine_kwargs) except TypeError: self._handles.handle.close() raise - @property def book(self): """ Book instance of class xlsxwriter.Workbook. - This attribute can be used to access engine-specific features. """ return self._book - @property def sheets(self) -> dict[str, Any]: result = self.book.sheetnames return result - def _save(self) -> None: """ Save workbook to disk. """ self.book.close() - def _write_cells( self, cells, @@ -248,29 +219,22 @@ def _write_cells( ) -> None: # Write the frame cells using xlsxwriter. sheet_name = self._get_sheet_name(sheet_name) - wks = self.book.get_worksheet_by_name(sheet_name) if wks is None: wks = self.book.add_worksheet(sheet_name) - style_dict = {"null": None} - if validate_freeze_panes(freeze_panes): wks.freeze_panes(*(freeze_panes)) - for cell in cells: val, fmt = self._value_with_fmt(cell.val) - stylekey = json.dumps(cell.style) if fmt: stylekey += fmt - if stylekey in style_dict: style = style_dict[stylekey] else: style = self.book.add_format(_XlsxStyler.convert(cell.style, fmt)) style_dict[stylekey] = style - if cell.mergestart is not None and cell.mergeend is not None: wks.merge_range( startrow + cell.row, From 932bf57f54c460ee989fb652f985119f89d27e93 Mon Sep 17 00:00:00 2001 From: Yaswanth Kumar <155723049+VYaswanthKumar@users.noreply.github.com> Date: Mon, 13 Oct 2025 19:15:22 +0530 Subject: [PATCH 4/4] Revert whitespace changes in _xlsxwriter.py Restore original formatting with proper blank lines between methods and sections to keep the PR clean and focused on the actual test changes. --- pandas/io/excel/_xlsxwriter.py | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pandas/io/excel/_xlsxwriter.py b/pandas/io/excel/_xlsxwriter.py index bae0055511e77..4a7b8eee2bfce 100644 --- a/pandas/io/excel/_xlsxwriter.py +++ b/pandas/io/excel/_xlsxwriter.py @@ -1,14 +1,17 @@ from __future__ import annotations + import json from typing import ( TYPE_CHECKING, Any, ) + from pandas.io.excel._base import ExcelWriter from pandas.io.excel._util import ( combine_kwargs, validate_freeze_panes, ) + if TYPE_CHECKING: from pandas._typing import ( ExcelWriterIfSheetExists, @@ -16,6 +19,8 @@ StorageOptions, WriteExcelBuffer, ) + + class _XlsxStyler: # Map from openpyxl-oriented styles to flatter xlsxwriter representation # Ordering necessary for both determinism and because some are keyed by @@ -86,10 +91,12 @@ class _XlsxStyler: (("left",), "left"), ], } + @classmethod def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: """ converts a style_dict to an xlsxwriter format dict + Parameters ---------- style_dict : style dictionary to convert @@ -97,13 +104,17 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: """ # Create a XlsxWriter format object. props = {} + if num_format_str is not None: props["num_format"] = num_format_str + if style_dict is None: return props + if "borders" in style_dict: style_dict = style_dict.copy() style_dict["border"] = style_dict.pop("borders") + for style_group_key, style_group in style_dict.items(): for src, dst in cls.STYLE_MAPPING.get(style_group_key, []): # src is a sequence of keys into a nested dict @@ -118,9 +129,11 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: break else: props[dst] = v + if isinstance(props.get("pattern"), str): # TODO: support other fill patterns props["pattern"] = 0 if props["pattern"] == "none" else 1 + for k in ["border", "top", "right", "bottom", "left"]: if isinstance(props.get(k), str): try: @@ -142,10 +155,12 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: ].index(props[k]) except ValueError: props[k] = 2 + if isinstance(props.get("font_script"), str): props["font_script"] = ["baseline", "superscript", "subscript"].index( props["font_script"] ) + if isinstance(props.get("underline"), str): props["underline"] = { "none": 0, @@ -154,13 +169,18 @@ def convert(cls, style_dict, num_format_str=None) -> dict[str, Any]: "singleAccounting": 33, "doubleAccounting": 34, }[props["underline"]] + # GH 30107 - xlsxwriter uses different name if props.get("valign") == "center": props["valign"] = "vcenter" + return props + + class XlsxWriter(ExcelWriter): _engine = "xlsxwriter" _supported_extensions = (".xlsx",) + def __init__( # pyright: ignore[reportInconsistentConstructor] self, path: FilePath | WriteExcelBuffer | ExcelWriter, @@ -175,9 +195,12 @@ def __init__( # pyright: ignore[reportInconsistentConstructor] ) -> None: # Use the xlsxwriter module as the Excel writer. from xlsxwriter import Workbook + engine_kwargs = combine_kwargs(engine_kwargs, kwargs) + if mode == "a": raise ValueError("Append mode is not supported with xlsxwriter!") + super().__init__( path, engine=engine, @@ -188,27 +211,33 @@ def __init__( # pyright: ignore[reportInconsistentConstructor] if_sheet_exists=if_sheet_exists, engine_kwargs=engine_kwargs, ) + try: self._book = Workbook(self._handles.handle, **engine_kwargs) except TypeError: self._handles.handle.close() raise + @property def book(self): """ Book instance of class xlsxwriter.Workbook. + This attribute can be used to access engine-specific features. """ return self._book + @property def sheets(self) -> dict[str, Any]: result = self.book.sheetnames return result + def _save(self) -> None: """ Save workbook to disk. """ self.book.close() + def _write_cells( self, cells, @@ -219,22 +248,29 @@ def _write_cells( ) -> None: # Write the frame cells using xlsxwriter. sheet_name = self._get_sheet_name(sheet_name) + wks = self.book.get_worksheet_by_name(sheet_name) if wks is None: wks = self.book.add_worksheet(sheet_name) + style_dict = {"null": None} + if validate_freeze_panes(freeze_panes): wks.freeze_panes(*(freeze_panes)) + for cell in cells: val, fmt = self._value_with_fmt(cell.val) + stylekey = json.dumps(cell.style) if fmt: stylekey += fmt + if stylekey in style_dict: style = style_dict[stylekey] else: style = self.book.add_format(_XlsxStyler.convert(cell.style, fmt)) style_dict[stylekey] = style + if cell.mergestart is not None and cell.mergeend is not None: wks.merge_range( startrow + cell.row,