Last active
January 16, 2024 06:17
-
-
Save o2b-ru/9434e212d1e1fc7db9370c49238ddbbd to your computer and use it in GitHub Desktop.
BigDataTable faster LongTable on the big data (reportlab==3.5.23)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import reportlab | |
from reportlab import platypus | |
from reportlab.lib.utils import annotateException, IdentStr, flatten, isStr, asNative, strTypes | |
class BigDataTable(platypus.Table): | |
def _splitRows(self, availHeight): | |
n = self._getFirstPossibleSplitRowPosition(availHeight) | |
repeatRows = self.repeatRows | |
if n <= (repeatRows if isinstance(repeatRows, int) else (max(repeatRows) + 1)): return [] | |
lim = len(self._rowHeights) | |
if n == lim: return [self] | |
lo = self._rowSplitRange | |
if lo: | |
lo, hi = lo | |
if lo < 0: lo += lim | |
if hi < 0: hi += lim | |
if n > hi: | |
return self._splitRows(availHeight - sum(self._rowHeights[hi:n])) | |
elif n < lo: | |
return [] | |
repeatCols = self.repeatCols | |
splitByRow = self.splitByRow | |
data = self._cellvalues | |
# we're going to split into two superRows | |
ident = self.ident | |
if ident: ident = IdentStr(ident) | |
splitH = self._rowHeights | |
R0 = self.__class__(data[:n], colWidths=self._colWidths, rowHeights=splitH[:n], | |
repeatRows=repeatRows, repeatCols=repeatCols, | |
splitByRow=splitByRow, normalizedData=1, cellStyles=self._cellStyles[:n], | |
ident=ident, | |
spaceBefore=getattr(self, 'spaceBefore', None), | |
longTableOptimize=0) | |
nrows = self._nrows | |
ncols = self._ncols | |
# copy the commands | |
A = [] | |
# hack up the line commands | |
for op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space in self._linecmds: | |
if isinstance(sr, strTypes) and sr.startswith('split'): | |
A.append((op, (sc, sr), (ec, sr), weight, color, cap, dash, join, count, space)) | |
if sr == 'splitlast': | |
sr = er = n - 1 | |
elif sr == 'splitfirst': | |
sr = n | |
er = n | |
if sc < 0: sc += ncols | |
if ec < 0: ec += ncols | |
if sr < 0: sr += nrows | |
if er < 0: er += nrows | |
if op in ('BOX', 'OUTLINE', 'GRID'): | |
if sr < n and er >= n: | |
# we have to split the BOX | |
A.append(('LINEABOVE', (sc, sr), (ec, sr), weight, color, cap, dash, join, count, space)) | |
A.append(('LINEBEFORE', (sc, sr), (sc, er), weight, color, cap, dash, join, count, space)) | |
A.append(('LINEAFTER', (ec, sr), (ec, er), weight, color, cap, dash, join, count, space)) | |
A.append(('LINEBELOW', (sc, er), (ec, er), weight, color, cap, dash, join, count, space)) | |
if op == 'GRID': | |
A.append(('LINEBELOW', (sc, n - 1), (ec, n - 1), weight, color, cap, dash, join, count, space)) | |
A.append(('LINEABOVE', (sc, n), (ec, n), weight, color, cap, dash, join, count, space)) | |
A.append(('INNERGRID', (sc, sr), (ec, er), weight, color, cap, dash, join, count, space)) | |
else: | |
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space)) | |
elif op == 'INNERGRID': | |
if sr < n and er >= n: | |
A.append(('LINEBELOW', (sc, n - 1), (ec, n - 1), weight, color, cap, dash, join, count, space)) | |
A.append(('LINEABOVE', (sc, n), (ec, n), weight, color, cap, dash, join, count, space)) | |
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space)) | |
elif op == 'LINEBELOW': | |
if sr < n and er >= (n - 1): | |
A.append(('LINEABOVE', (sc, n), (ec, n), weight, color, cap, dash, join, count, space)) | |
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space)) | |
elif op == 'LINEABOVE': | |
if sr <= n and er >= n: | |
A.append(('LINEBELOW', (sc, n - 1), (ec, n - 1), weight, color, cap, dash, join, count, space)) | |
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space)) | |
else: | |
A.append((op, (sc, sr), (ec, er), weight, color, cap, dash, join, count, space)) | |
R0._cr_0(n, A, nrows) | |
R0._cr_0(n, self._bkgrndcmds, nrows, _srflMode=True) | |
R0._cr_0(n, self._spanCmds, nrows) | |
R0._cr_0(n, self._nosplitCmds, nrows) | |
for c in self._srflcmds: | |
R0._addCommand(c) | |
if c[1][1] != 'splitlast': continue | |
(sc, sr), (ec, er) = c[1:3] | |
R0._addCommand((c[0],) + ((sc, n - 1), (ec, n - 1)) + tuple(c[3:])) | |
if ident: ident = IdentStr(ident) | |
if repeatRows: | |
if isinstance(repeatRows, int): | |
iRows = data[:repeatRows] | |
nRepeatRows = repeatRows | |
iRowH = splitH[:repeatRows] | |
iCS = self._cellStyles[:repeatRows] | |
else: | |
# we have a list of repeated rows eg (1,3) | |
repeatRows = list(sorted(repeatRows)) | |
iRows = [data[i] for i in repeatRows] | |
nRepeatRows = len(repeatRows) | |
iRowH = [splitH[i] for i in repeatRows] | |
iCS = [self._cellStyles[i] for i in repeatRows] | |
R1 = self.__class__(iRows + data[n:], colWidths=self._colWidths, | |
rowHeights=iRowH + splitH[n:], | |
repeatRows=nRepeatRows, repeatCols=repeatCols, | |
splitByRow=splitByRow, normalizedData=1, | |
cellStyles=iCS + self._cellStyles[n:], | |
ident=ident, | |
spaceAfter=getattr(self, 'spaceAfter', None), | |
longTableOptimize=self._longTableOptimize, | |
) | |
R1._cr_1_1(n, nRepeatRows, A) | |
R1._cr_1_1(n, nRepeatRows, self._bkgrndcmds, _srflMode=True) | |
R1._cr_1_1(n, nRepeatRows, self._spanCmds) | |
R1._cr_1_1(n, nRepeatRows, self._nosplitCmds) | |
else: | |
R1 = self.__class__(data[n:], colWidths=self._colWidths, rowHeights=splitH[n:], | |
repeatRows=repeatRows, repeatCols=repeatCols, | |
splitByRow=splitByRow, normalizedData=1, cellStyles=self._cellStyles[n:], | |
ident=ident, | |
spaceAfter=getattr(self, 'spaceAfter', None), | |
longTableOptimize=self._longTableOptimize, | |
) | |
R1._cr_1_0(n, A) | |
R1._cr_1_0(n, self._bkgrndcmds, _srflMode=True) | |
R1._cr_1_0(n, self._spanCmds) | |
R1._cr_1_0(n, self._nosplitCmds) | |
for c in self._srflcmds: | |
R1._addCommand(c) | |
if c[1][1] != 'splitfirst': continue | |
(sc, sr), (ec, er) = c[1:3] | |
R1._addCommand((c[0],) + ((sc, 0), (ec, 0)) + tuple(c[3:])) | |
R0.hAlign = R1.hAlign = self.hAlign | |
R0.vAlign = R1.vAlign = self.vAlign | |
self.onSplit(R0) | |
self.onSplit(R1) | |
return [R0, R1] |
Performance debugging!
Look at the highlighted values before (left) and after (right):
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey Great work and it saved my day.
Can you please explain it a bit more about why it works so well?