v0.5.2
Python application / build (push) Waiting to run

Что то сделал
This commit is contained in:
Igor20264
2026-09-08 19:37:54 +03:00
parent 1a5b35eb54
commit 510f7e7adf
90 changed files with 11720 additions and 5547 deletions
+5 -3
View File
@@ -293,7 +293,9 @@ class Paragraph(Renderable):
yield SubRenderable(image, False)
layout_state.add_height(rendered_image_height)
else:
# Defer this image and any remaining siblings to the next page
# (as SubRenderable — bare Image objects break the renderer).
yield SubRenderable(image, True)
break
yield from images
for rest in images:
yield SubRenderable(rest, True)
return
+93 -11
View File
@@ -113,6 +113,10 @@ class Table(Renderable, RequiresNumbering):
cell_height = 0
if not (apply_merge and merge_v == "continue"):
for paragraph in row[col]:
# Method guide §3: do not leave caption + column headers alone
# at page bottom — glue header row to the following data row.
if row_idx == 0:
paragraph._docx_paragraph.paragraph_format.keep_with_next = True
cell_layout_state = LayoutState(
layout_state.max_height, layout_state.max_width
)
@@ -133,6 +137,62 @@ class Table(Renderable, RequiresNumbering):
)
return docx_row, row_height
def _peek_row_height(self, row_idx: int, layout_state: LayoutState) -> Length:
"""Estimate row height without attaching cell paragraphs to a table."""
from .paragraph_sizer import ParagraphSizer
row = self._rows[row_idx]
merge_row = self._merge[row_idx]
row_height = 0
col_w = self._col_width(layout_state)
col = 0
while col < self._cols:
merge_v, merge_h = merge_row[col]
if merge_h == "continue":
col += 1
continue
span = self._grid_span(merge_row, col)
if span < 1:
span = 1
cell_height = 0
if merge_v != "continue":
max_w = col_w * span - CELL_OFFSET
for paragraph in row[col]:
cell_height += ParagraphSizer(
paragraph._docx_paragraph, None, max_w
).calculate_height().full
row_height = max(cell_height, row_height)
col += span
row_height += Pt(0.5) + (
ROW_HEIGHT_SLACK if self._continuation_mode not in _WORD_PAGED_MODES else Pt(0)
)
return row_height
def _start_block_height(
self, previous_rendered: RenderedInfo | None, layout_state: LayoutState
) -> Length:
"""Caption + header + first data row (method: no orphan title/header)."""
from docx.text.paragraph import Paragraph as DocxParagraph
from .paragraph_sizer import ParagraphSizer
# Dry-run caption sizing (temporary Caption; not yielded into the body).
cap = Caption(
self._parent, "Таблица", self._caption_info, self._number, True
)
prev_p = (
previous_rendered.docx_element
if previous_rendered and isinstance(previous_rendered.docx_element, DocxParagraph)
else None
)
total = ParagraphSizer(
cap._docx_paragraph, prev_p, layout_state.max_width
).calculate_height().full
if self._rows:
total += self._peek_row_height(0, layout_state)
if len(self._rows) > 1:
total += self._peek_row_height(1, layout_state)
return total
def _should_split_fragment(
self, row_height: Length, layout_state: LayoutState, rows_in_fragment: int
) -> bool:
@@ -169,10 +229,29 @@ class Table(Renderable, RequiresNumbering):
def render(self, previous_rendered: RenderedInfo, layout_state: LayoutState) \
-> Generator[RenderedInfo, None, None]:
# Method guide: never leave only «Таблица N» or «Таблица N» + column
# headers at the bottom of a page. If caption+header+first data row do
# not fit, push the whole block to the next page (layout leftover;
# Word also gets keep_with_next on caption/header).
leftover = Pt(0)
start_h = self._start_block_height(previous_rendered, layout_state)
if (
layout_state.current_page_height > 0
and start_h > layout_state.remaining_page_height
):
leftover = layout_state.remaining_page_height
layout_state.add_height(leftover)
previous_rendered = None
caption_rendered_infos = list(
Caption(self._parent, "Таблица", self._caption_info, self._number, True)
.render(previous_rendered, copy(layout_state))
)
if leftover and caption_rendered_infos:
first = caption_rendered_infos[0]
caption_rendered_infos[0] = RenderedInfo(
first.docx_element, first.height + leftover
)
layout_state.add_height(sum(info.height for info in caption_rendered_infos))
yield from caption_rendered_infos
@@ -190,19 +269,22 @@ class Table(Renderable, RequiresNumbering):
)
if self._should_split_fragment(row_height, layout_state, rows_in_fragment):
yield RenderedInfo(docx_table, table_height)
yield from self._emit_page_break_and_optional_caption(layout_state)
# Never cut after the header alone (method: no title+column headers
# without a data row). Prefer slight overflow over an orphan fragment.
if rows_in_fragment >= 2:
yield RenderedInfo(docx_table, table_height)
yield from self._emit_page_break_and_optional_caption(layout_state)
docx_table = create_table(
self._parent, 0, self._cols, self._table_width(layout_state)
)
apply_merge = False
rows_in_fragment = 0
table_height = Pt(0.5)
docx_table = create_table(
self._parent, 0, self._cols, self._table_width(layout_state)
)
apply_merge = False
rows_in_fragment = 0
table_height = Pt(0.5)
docx_row, row_height = self._build_docx_row(
docx_table, row_idx, apply_merge, layout_state
)
docx_row, row_height = self._build_docx_row(
docx_table, row_idx, apply_merge, layout_state
)
docx_table._element.append(docx_row._element)
layout_state.add_height(row_height)