diff --git a/odoo/addons/base/models/ir_actions_report.py b/odoo/addons/base/models/ir_actions_report.py index 296cbd508e2..327d75dfcbe 100644 --- a/odoo/addons/base/models/ir_actions_report.py +++ b/odoo/addons/base/models/ir_actions_report.py @@ -22,13 +22,17 @@ import json from lxml import etree from contextlib import closing from reportlab.graphics.barcode import createBarcodeDrawing -from PyPDF2 import PdfFileWriter, PdfFileReader, utils +from PyPDF2 import PdfFileWriter, PdfFileReader from collections import OrderedDict from collections.abc import Iterable from PIL import Image, ImageFile # Allow truncated images ImageFile.LOAD_TRUNCATED_IMAGES = True +try: + from PyPDF2.errors import PdfReadError +except ImportError: + from PyPDF2.utils import PdfReadError _logger = logging.getLogger(__name__) @@ -615,7 +619,7 @@ class IrActionsReport(models.Model): try: reader = PdfFileReader(stream) writer.appendPagesFromReader(reader) - except utils.PdfReadError: + except PdfReadError: raise UserError(_("Odoo is unable to merge the generated PDFs.")) result_stream = io.BytesIO() streams.append(result_stream) diff --git a/odoo/addons/base/tests/minimal.pdf b/odoo/addons/base/tests/minimal.pdf index 2a73de072da..ec69682def7 100644 Binary files a/odoo/addons/base/tests/minimal.pdf and b/odoo/addons/base/tests/minimal.pdf differ diff --git a/odoo/tools/pdf.py b/odoo/tools/pdf.py index 46fee2c6ed0..cdd2e359af7 100644 --- a/odoo/tools/pdf.py +++ b/odoo/tools/pdf.py @@ -6,8 +6,6 @@ import re from datetime import datetime from hashlib import md5 from logging import getLogger -from PyPDF2 import PdfFileWriter, PdfFileReader -from PyPDF2.generic import DictionaryObject, NameObject, ArrayObject, DecodedStreamObject, NumberObject, createStringObject, ByteStringObject from zlib import compress, decompress from PIL import Image, PdfImagePlugin from reportlab.lib import colors @@ -15,6 +13,28 @@ from reportlab.lib.units import cm from reportlab.lib.utils import ImageReader from reportlab.pdfgen import canvas +try: + # class were renamed in PyPDF2 > 2.0 + # https://pypdf2.readthedocs.io/en/latest/user/migration-1-to-2.html#classes + from PyPDF2 import PdfReader + import PyPDF2 + # monkey patch to discard unused arguments as the old arguments were not discarded in the transitional class + # https://pypdf2.readthedocs.io/en/2.0.0/_modules/PyPDF2/_reader.html#PdfReader + class PdfFileReader(PdfReader): + def __init__(self, *args, **kwargs): + if "strict" not in kwargs and len(args) < 2: + kwargs["strict"] = True # maintain the default + kwargs = {k:v for k, v in kwargs.items() if k in ('strict', 'stream')} + super().__init__(*args, **kwargs) + + PyPDF2.PdfFileReader = PdfFileReader + from PyPDF2 import PdfFileWriter, PdfFileReader + PdfFileWriter._addObject = PdfFileWriter._add_object +except ImportError: + from PyPDF2 import PdfFileWriter, PdfFileReader + +from PyPDF2.generic import DictionaryObject, NameObject, ArrayObject, DecodedStreamObject, NumberObject, createStringObject, ByteStringObject + try: from fontTools.ttLib import TTFont except ImportError: @@ -410,7 +430,7 @@ class OdooPdfFileWriter(PdfFileWriter): DictionaryObject({ NameObject('/CheckSum'): createStringObject(md5(attachment['content']).hexdigest()), NameObject('/ModDate'): createStringObject(datetime.now().strftime(DEFAULT_PDF_DATETIME_FORMAT)), - NameObject('/Size'): NameObject(str(len(attachment['content']))), + NameObject('/Size'): NameObject(f"/{len(attachment['content'])}"), }), }) if attachment.get('subtype'):