使用Openpyxl追加Pandas DataFrame至Excel工作表时,文件保存后数据未生效的问题排查
使用Openpyxl追加Pandas DataFrame至Excel工作表时,文件保存后数据未生效的问题排查
我想要把Pandas DataFrame中的数据追加到现有的Excel工作表和Excel表格(ListObject)中,目前使用openpyxl来实现这个功能。
我现在正在编写写入工作表的代码,具体如下:
def _append_to_excel_sheet(self , data_to_write: pd.DataFrame , excel_file: str , sheet_name: str , **kwargs ) -> bool: try: if Path(excel_file).exists(): # Load existing workbook self.logger.debug(f"Appending {len(data_to_write)} rows to sheet {sheet_name} in {excel_file}") with open (excel_file, "rb") as f: wb = load_workbook(f , read_only=False , keep_vba=True , data_only=False , keep_links=True , rich_text=True ) self.logger.debug(wb.sheetnames) ws = wb[sheet_name] if sheet_name in wb.sheetnames else wb.create_sheet(sheet_name) # Find last row with data last_row = ws.max_row # Write new data for idx, row in enumerate(data_to_write.values): self.logger.debug(f"Appending row: {row} to row: {last_row + idx + 1}") for col_idx, value in enumerate(row, 1): ws.cell(row=last_row + idx + 1, column=col_idx, value=value) self.logger.debug(f"New range: {ws.cell(row=last_row + 1, column=1).coordinate}:{ws.cell(row=last_row + len(data_to_write), column=len(data_to_write.columns)).coordinate}") self.logger.debug(f"Saving to file {excel_file}") wb.save(excel_file) else: # Create new file if it doesn't exist self.logger.debug(f"Creating new file {excel_file} and writing {len(data_to_write)} rows to sheet {sheet_name}") with pd.ExcelWriter(excel_file, engine='openpyxl') as writer: data_to_write.to_excel( writer, sheet_name=sheet_name, index=False ) except Exception as e: self.logger.error(f"Failed to write to Excel: {str(e)}") raise finally: wb.close()
当我运行这段代码时,logger对象能正常执行到self.logger.debug(f"Saving to file {excel_file}")这一行,没有抛出任何异常。在我的测试中,也从未触发异常分支的self.logger.error(f"Failed to write to Excel: {str(e)}")代码。
我查阅了openpyxl的官方文档以及Stack Overflow上的多个类似问题,但始终没找到代码中的问题。传入函数的文件路径是绝对路径。
我知道可以直接用Pandas追加DataFrame到现有工作表,这本来是理想的解决方案,但我同时也需要对Excel表格(ListObject)实现同样的追加功能。
请问:
- 有没有办法开启openpyxl的verbose模式,查看它后台的具体操作?
- 是不是我忽略了同名文件保存的某些限制条件?
- 如果我无法修复当前问题,还有哪些替代方案可以考虑?
编辑
补充一下我调用这段代码的上下文:这个函数是ExcelOutputHandler类的一个方法,我在Unittest.TestCase中这样调用它:
from datetime import datetime from pathlib import Path import sys import unittest from src.core.types import City # this is a NamedTuple from src.output_handler import ExcelOutputHandler import logging class test_output_handler(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.logger = logging.getLogger() cls.logger.setLevel(logging.DEBUG) cls.logger.addHandler(logging.StreamHandler(sys.stdout)) cls.test_dir = Path(__file__).parent cls.xl_testfile = cls.test_dir / f"./output_history/{datetime.now().strftime("%Y-%m-%d %H-%M-%S")}.xlsx" with open(cls.test_dir / "./test_worksheet.xlsx", "rb") as template_testfile: with open(cls.xl_testfile, "wb+") as testfile: testfile.write(template_testfile.read()) @classmethod def tearDownClass(cls) -> None: pass def setUp(self) -> None: pass def tearDown(self) -> None: pass def test_write_to_sheet_overlay(self) -> None: handler = ExcelOutputHandler(self.logger) data = [ City('London', 'UK', 'EU', 'Rainy', 50, 'S', 5) , City('Paris', 'FR', 'EU', 'Sunny', 10, 'A', 6) , City('Berlin', 'DE', 'EU', 'Cold', 20, 'A', 3) , City('Brussels', 'BE', 'EU', 'Cold', 10, 'B', 6) , City('Lisbon', 'PT', 'EU', 'Sunny', 20, 'S+', 7) , City('Oslo', 'NW', 'EU', 'Cold', 10, 'S', 3) , City('Vienna', 'AT', 'EU', 'Cold', 10, 'A+', 8) ] handler._append_to_excel_sheet(data, str(self.xl_testfile), "Sheet2") handler._append_to_excel_sheet(data, str(self.xl_testfile), "Sheet2") # Verify the results import openpyxl wb = openpyxl.load_workbook(str(self.xl_testfile)) ws = wb["Sheet2"] # Get the number of rows with data (excluding header) row_count = sum(1 for row in ws.iter_rows(min_row=2) if any(cell.value for cell in row)) # Assert we have twice the number of data rows self.assertEqual(row_count, len(data) * 2, f"Expected {len(data) * 2} rows but found {row_count}") wb.close()
在测试中,我期望Excel文件包含14条数据行,但测试总是失败,报错信息为AssertionError: 0 != 14 : Expected 14 rows but found 0。我参考了相关资料,认为初始化xl_testfile的代码会复制test_worksheet文件,然后让测试可以正常访问它。
备注:内容来源于stack exchange,提问作者Pollastre
相关产品推荐
相关产品推荐

