oca-ocb-core/odoo-bringout-oca-ocb-base/doc/PATCH_PDFWRITER.md
Ernad Husremovic 3f19943cec fix PyPDF2 3.x page copying issue - prevent 327-byte empty PDFs
Added explicit page copying after cloneReaderDocumentRoot() calls because
PyPDF2 3.x only copies document structure, not content pages.

🤖 assisted by claude
2025-09-02 19:31:11 +02:00

4.6 KiB

PyPDF2 Compatibility Patch

Overview

This patch addresses the PyPDF2 deprecation error that occurs when using PyPDF2 version 3.0.0 or higher with Odoo. The original error was:

PyPDF2.errors.DeprecationError: PdfFileWriter is deprecated and was removed in PyPDF2 3.0.0. Use PdfWriter instead.

Problem

In PyPDF2 3.0.0, several classes and methods were deprecated and removed:

  • PdfFileWriterPdfWriter
  • PdfFileReaderPdfReader
  • addPage()add_page()
  • addMetadata()add_metadata()
  • getNumPages()len(pages)
  • getPage(n)pages[n]
  • appendPagesFromReader()append_pages_from_reader()
  • _addObject()_add_object()
  • cloneReaderDocumentRoot()clone_reader_document_root()

Solution

This patch provides backward compatibility by creating wrapper classes that:

  1. Inherit from the new PyPDF2 classes (PdfWriter, PdfReader)
  2. Provide the old method signatures as compatibility methods
  3. Gracefully handle both old and new PyPDF2 versions

Files Modified

1. odoo/tools/pdf.py

  • Added compatibility wrapper classes PdfFileWriter and PdfFileReader
  • Updated import logic to handle both PyPDF2 2.x and 3.x
  • Added method aliases for deprecated methods
  • Updated BrandedFileWriter class to use new API with fallback

2. odoo/addons/base/models/ir_actions_report.py

  • Added compatibility import logic
  • Created local compatibility classes with required method aliases
  • Added support for numPages property and related methods

Implementation Details

Critical PyPDF2 3.x Fix - Page Content Copying

In PyPDF2 3.x, cloneReaderDocumentRoot() only copies document structure, NOT content pages. This was causing 327-byte PDFs with no actual content. Modules using this method now include explicit page copying:

writer.cloneReaderDocumentRoot(reader)
# Copy all pages from the reader to the writer (required for PyPDF2 3.x)
for page_num in range(reader.getNumPages()):
    page = reader.getPage(page_num)
    writer.addPage(page)

Compatibility Import Pattern

try:
    from PyPDF2 import PdfReader, PdfWriter
    
    # Create compatibility classes
    class PdfFileWriter(PdfWriter):
        def addPage(self, page):
            return self.add_page(page)
        
        def addMetadata(self, metadata):
            return self.add_metadata(metadata)
        
        def _addObject(self, obj):
            return self._add_object(obj)
    
    class PdfFileReader(PdfReader):
        def getNumPages(self):
            return len(self.pages)
        
        def getPage(self, page_num):
            return self.pages[page_num]

except ImportError:
    # Fallback to old API for older PyPDF2 versions
    from PyPDF2 import PdfFileWriter, PdfFileReader

Method Compatibility Mapping

Old Method (PyPDF2 < 3.0) New Method (PyPDF2 ≥ 3.0) Compatibility Method
PdfFileWriter.addPage() PdfWriter.add_page() Wrapped
PdfFileWriter.addMetadata() PdfWriter.add_metadata() Wrapped
PdfFileWriter._addObject() PdfWriter._add_object() Wrapped
PdfFileReader.getNumPages() len(PdfReader.pages) Wrapped
PdfFileReader.getPage() PdfReader.pages[] Wrapped
PdfFileWriter.appendPagesFromReader() PdfWriter.append_pages_from_reader() Wrapped
PdfFileWriter.cloneReaderDocumentRoot() PdfWriter.clone_reader_document_root() Wrapped

Testing

The patch has been tested with:

  • PyPDF2 3.0.0+ (new API)
  • PyPDF2 2.x (old API via fallback)
  • OdooPdfFileWriter instantiation
  • PDF generation workflows
  • Report generation (original error case)

Branch Information

  • Branch: pdfwrite
  • Based on: Current main/master branch
  • Type: Compatibility patch
  • Impact: Backward compatible - no breaking changes

Author

  • Developer: Ernad Husremović (hernad@bring.out.ba)
  • Company: bring.out.doo Sarajevo
  • Date: 2025-09-02

This patch resolves the PyPDF2 deprecation error encountered in:

  • Report generation (/report/pdf/ endpoints)
  • PDF merge operations
  • PDF attachment handling
  • Account EDI PDF operations

Future Considerations

While this patch provides immediate compatibility, consider:

  1. Eventually migrating to the new PyPDF2 API directly
  2. Monitoring PyPDF2 changelog for future deprecations
  3. Testing with future PyPDF2 versions

Installation

This patch is automatically applied when using the pdfwrite branch. No additional installation steps required.