From 9f3132833fbac04ebd63179bfb3263adeea72c78 Mon Sep 17 00:00:00 2001 From: Vincent Hatakeyama Date: Tue, 21 Oct 2025 10:57:29 +0200 Subject: [PATCH 1/2] [FIX] report_xlsx: remove requiremnts already present in odoo --- report_xlsx/__manifest__.py | 1 - requirements.txt | 2 -- 2 files changed, 3 deletions(-) diff --git a/report_xlsx/__manifest__.py b/report_xlsx/__manifest__.py index 5eb444a018..d072d3f115 100644 --- a/report_xlsx/__manifest__.py +++ b/report_xlsx/__manifest__.py @@ -9,7 +9,6 @@ "version": "18.0.1.0.1", "development_status": "Mature", "license": "AGPL-3", - "external_dependencies": {"python": ["xlsxwriter", "xlrd"]}, "depends": ["base", "web"], "demo": ["demo/report.xml"], "installable": True, diff --git a/requirements.txt b/requirements.txt index 65153ae3b9..73f4688642 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,3 @@ mock openpyxl py3o.formats py3o.template -xlrd -xlsxwriter From e4be74cb9f50727500c2653cfc03f18a57ed6827 Mon Sep 17 00:00:00 2001 From: Vincent Hatakeyama Date: Tue, 21 Oct 2025 11:28:29 +0200 Subject: [PATCH 2/2] [FIX] report_xlsx: use openpyxl to open xlsx with fallback on xlrd.xlsx Version 2.0 of xlrd does not handle xlsx anymore so use openxyl by default and fallback on xlrd. --- report_xlsx/tests/test_report.py | 34 ++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/report_xlsx/tests/test_report.py b/report_xlsx/tests/test_report.py index d91383ac1f..4e978b1da5 100644 --- a/report_xlsx/tests/test_report.py +++ b/report_xlsx/tests/test_report.py @@ -1,16 +1,25 @@ # Copyright 2017 Creu Blanca +# Copyright 2025 XCG SAS # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import io import logging +import unittest -from odoo.tests import common +from odoo.tests import can_import, common _logger = logging.getLogger(__name__) -try: - from xlrd import open_workbook -except ImportError: - _logger.debug("Can not import xlrd`.") +try: # pragma: no cover + from openpyxl import load_workbook +except ImportError: # pragma: no cover + _logger.debug("Can not import openpyxl.") + load_workbook = None + try: + from xlrd import open_workbook + except ImportError: + _logger.debug("Can not import xlrd`.") + open_workbook = None class TestReport(common.TransactionCase): @@ -24,13 +33,22 @@ def setUp(self): self.report = self.report_object._get_report_from_name(self.report_name) self.docs = self.env["res.company"].search([], limit=1).partner_id + @unittest.skipUnless( + can_import("xlrd.xlsx") or can_import("openpyxl"), "XLRD/XLSX not available" + ) def test_report(self): report = self.report self.assertEqual(report.report_type, "xlsx") rep = self.report_object._render(self.report_name, self.docs.ids, {}) - wb = open_workbook(file_contents=rep[0]) - sheet = wb.sheet_by_index(0) - self.assertEqual(sheet.cell(0, 0).value, self.docs.name) + if load_workbook: # pragma: no cover + wb = load_workbook(io.BytesIO(rep[0]), read_only=True) + sheet = wb[wb.sheetnames[0]] + cell_0_0 = sheet.cell(1, 1) + elif open_workbook: # pragma: no cover + wb = open_workbook(file_contents=rep[0]) + sheet = wb.sheet_by_index(0) + cell_0_0 = sheet.cell(0, 0) + self.assertEqual(cell_0_0.value, self.docs.name) def test_save_attachment(self): self.report.attachment = 'object.name + ".xlsx"'