Module fpdf.recorder
Expand source code
import types, warnings
from copy import deepcopy
from .errors import FPDFException
class FPDFRecorder:
"""
The class is aimed to be used as wrapper around fpdf.FPDF:
pdf = FPDF()
recorder = FPDFRecorder(pdf)
Its aim is dual:
* allow to **rewind** to the state of the FPDF instance passed to its constructor,
reverting all changes made to its internal state
* allow to **replay** again all the methods calls performed
on the recorder instance between its creation and the last call to rewind()
Note that method can be called on a FPDFRecorder instance using its .pdf attribute
so that they are not recorded & replayed later, on a call to .replay().
Note that using this class means to duplicate the FPDF `bytearray` buffer:
when generating large PDFs, doubling memory usage may be troublesome.
"""
def __init__(self, pdf, accept_page_break=True):
self.pdf = pdf
self._initial = deepcopy(self.pdf.__dict__)
self._calls = []
if not accept_page_break:
self.accept_page_break = False
def __getattr__(self, name):
attr = getattr(self.pdf, name)
if callable(attr):
return CallRecorder(attr, self._calls)
return attr
def rewind(self):
self.pdf.__dict__ = self._initial
self._initial = deepcopy(self.pdf.__dict__)
def replay(self):
for call in self._calls:
func, args, kwargs = call
try:
result = func(*args, **kwargs)
if isinstance(result, types.GeneratorType):
warnings.warn(
"Detected usage of a context manager inside an unbreakable() section, which is not supported"
)
# The results of other methods can also be invalidated: .pages_count, page_no(), get_x() / get_y(), will_page_break()
except Exception as error:
raise FPDFException(
f"Failed to replay FPDF call: {func}(*{args}, **{kwargs})"
) from error
self._calls = []
class CallRecorder:
def __init__(self, func, calls):
self._func = func
self._calls = calls
def __call__(self, *args, **kwargs):
self._calls.append((self._func, args, kwargs))
return self._func(*args, **kwargs)
Classes
class CallRecorder (func, calls)
-
Expand source code
class CallRecorder: def __init__(self, func, calls): self._func = func self._calls = calls def __call__(self, *args, **kwargs): self._calls.append((self._func, args, kwargs)) return self._func(*args, **kwargs)
class FPDFRecorder (pdf, accept_page_break=True)
-
The class is aimed to be used as wrapper around fpdf.FPDF:
pdf = FPDF() recorder = FPDFRecorder(pdf)
Its aim is dual: * allow to rewind to the state of the FPDF instance passed to its constructor, reverting all changes made to its internal state * allow to replay again all the methods calls performed on the recorder instance between its creation and the last call to rewind()
Note that method can be called on a FPDFRecorder instance using its .pdf attribute so that they are not recorded & replayed later, on a call to .replay().
Note that using this class means to duplicate the FPDF
bytearray
buffer: when generating large PDFs, doubling memory usage may be troublesome.Expand source code
class FPDFRecorder: """ The class is aimed to be used as wrapper around fpdf.FPDF: pdf = FPDF() recorder = FPDFRecorder(pdf) Its aim is dual: * allow to **rewind** to the state of the FPDF instance passed to its constructor, reverting all changes made to its internal state * allow to **replay** again all the methods calls performed on the recorder instance between its creation and the last call to rewind() Note that method can be called on a FPDFRecorder instance using its .pdf attribute so that they are not recorded & replayed later, on a call to .replay(). Note that using this class means to duplicate the FPDF `bytearray` buffer: when generating large PDFs, doubling memory usage may be troublesome. """ def __init__(self, pdf, accept_page_break=True): self.pdf = pdf self._initial = deepcopy(self.pdf.__dict__) self._calls = [] if not accept_page_break: self.accept_page_break = False def __getattr__(self, name): attr = getattr(self.pdf, name) if callable(attr): return CallRecorder(attr, self._calls) return attr def rewind(self): self.pdf.__dict__ = self._initial self._initial = deepcopy(self.pdf.__dict__) def replay(self): for call in self._calls: func, args, kwargs = call try: result = func(*args, **kwargs) if isinstance(result, types.GeneratorType): warnings.warn( "Detected usage of a context manager inside an unbreakable() section, which is not supported" ) # The results of other methods can also be invalidated: .pages_count, page_no(), get_x() / get_y(), will_page_break() except Exception as error: raise FPDFException( f"Failed to replay FPDF call: {func}(*{args}, **{kwargs})" ) from error self._calls = []
Methods
def replay(self)
-
Expand source code
def replay(self): for call in self._calls: func, args, kwargs = call try: result = func(*args, **kwargs) if isinstance(result, types.GeneratorType): warnings.warn( "Detected usage of a context manager inside an unbreakable() section, which is not supported" ) # The results of other methods can also be invalidated: .pages_count, page_no(), get_x() / get_y(), will_page_break() except Exception as error: raise FPDFException( f"Failed to replay FPDF call: {func}(*{args}, **{kwargs})" ) from error self._calls = []
def rewind(self)
-
Expand source code
def rewind(self): self.pdf.__dict__ = self._initial self._initial = deepcopy(self.pdf.__dict__)