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:
PdfFileWriter→PdfWriterPdfFileReader→PdfReaderaddPage()→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:
- Inherit from the new PyPDF2 classes (
PdfWriter,PdfReader) - Provide the old method signatures as compatibility methods
- Gracefully handle both old and new PyPDF2 versions
Files Modified
1. odoo/tools/pdf.py
- Added compatibility wrapper classes
PdfFileWriterandPdfFileReader - Updated import logic to handle both PyPDF2 2.x and 3.x
- Added method aliases for deprecated methods
- Updated
BrandedFileWriterclass 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
numPagesproperty 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)
OdooPdfFileWriterinstantiation- 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
Related Issues
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:
- Eventually migrating to the new PyPDF2 API directly
- Monitoring PyPDF2 changelog for future deprecations
- Testing with future PyPDF2 versions
Installation
This patch is automatically applied when using the pdfwrite branch. No additional installation steps required.