0.4.1
Python application / build (push) Has been cancelled

- fix Не собиралось само список всех приложений
This commit is contained in:
Igor20264
2026-09-04 22:48:33 +03:00
parent b38661f588
commit 2ba6fe2673
3 changed files with 113 additions and 3 deletions
+3 -1
View File
@@ -42,7 +42,9 @@ CLI (тот же движок)
# *ЗАКЛЮЧЕНИЕ
# *СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
# *ПРИЛОЖЕНИЯ
(после ПРИЛОЖЕНИЯ — перечень основным текстом, затем ## Приложение А Название)
(перечень «Приложение А — …» собирается сам из ## Приложение А Название;
можно написать вручную — тогда автосписок не дублируется)
## Приложение А Название
Нумерованные разделы: # 1 Название ## 1.1 Подраздел
Точку в конце заголовка не ставить.
+72 -2
View File
@@ -121,8 +121,9 @@ class Renderer:
self._layout_tracker.set_page_size(max_height, max_width)
def process(self, renderables: list[Renderable]):
for i in range(len(renderables)):
self.render(renderables[i])
items = self._ensure_appendix_index(list(renderables))
for i in range(len(items)):
self.render(items[i])
self._flush_to_new_screen()
# If document had no TOC, still add page numbers to the only section
@@ -132,6 +133,75 @@ class Renderer:
if self._debugger:
self._debugger.after_rendered()
def _ensure_appendix_index(self, renderables: list[Renderable]) -> list[Renderable]:
"""Insert «Приложение X — Title» list after # *ПРИЛОЖЕНИЯ if missing (method guide §6)."""
sec_i = None
first_app_i = None
entries: list[tuple[str, str]] = []
for i, r in enumerate(renderables):
if not isinstance(r, Heading):
continue
text = (r.text or "").strip()
upper = text.upper().replace("Ё", "Е")
if upper in ("ПРИЛОЖЕНИЯ", "ПРИЛОЖЕНИЕ") and sec_i is None:
sec_i = i
continue
m = re.match(r"(?i)^Приложение\s+([А-ЯA-ZЁ])(?:\s+(.+))?$", text)
if not m:
continue
letter = m.group(1).upper().replace("Ё", "Е")
title = (m.group(2) or "").strip()
if first_app_i is None:
first_app_i = i
entries.append((letter, title))
if sec_i is None or first_app_i is None or not entries:
return renderables
if self._has_appendix_list_between(renderables, sec_i, first_app_i):
return renderables
from .profiles import dash_separator
dash = dash_separator()
index_paras: list[Renderable] = []
for letter, title in entries:
line = f"Приложение {letter}"
if title:
line = f"{line} {dash} {title}"
index_paras.append(self._make_appendix_index_paragraph(line))
return renderables[: sec_i + 1] + index_paras + renderables[sec_i + 1 :]
@staticmethod
def _has_appendix_list_between(
renderables: list[Renderable], sec_i: int, first_app_i: int
) -> bool:
"""True if author already put a list/prose between ПРИЛОЖЕНИЯ and first appendix."""
for r in renderables[sec_i + 1 : first_app_i]:
if isinstance(r, Heading):
continue
text = ""
if isinstance(r, Paragraph):
text = (r._docx_paragraph.text or "").strip()
elif hasattr(r, "text"):
text = (getattr(r, "text", None) or "").strip()
if not text:
continue
if re.search(r"(?i)приложение\s+[А-ЯA-ZЁ]", text):
return True
if re.search(r"[А-Яа-яA-Za-z]{3,}", text):
return True
return False
def _make_appendix_index_paragraph(self, text: str) -> Paragraph:
"""Body-text line in the appendix list under ПРИЛОЖЕНИЯ (no first-line indent)."""
p = Paragraph(self._document._body)
p.add_run(text)
p.style = "Normal"
p.first_line_indent = Cm(0)
pf = p._docx_paragraph.paragraph_format
pf.left_indent = Cm(0)
return p
@staticmethod
def _rewrite_heading_text(heading: Heading, text: str) -> None:
runs = heading._docx_paragraph.runs
+38
View File
@@ -428,6 +428,44 @@ def test_appendix_item_becomes_h3_plus_title():
assert title_p._docx_paragraph.alignment == WD_ALIGN_PARAGRAPH.CENTER
def test_appendix_index_auto_inserted():
import docx
from md2gost.renderable.heading import Heading
from md2gost.renderer import Renderer
from md2gost.styles import apply_mirea_styles
doc = docx.Document(r"md2gost/Template.docx")
doc._body.clear_content()
apply_mirea_styles(doc)
renderer = Renderer(doc, skip_numbering=True)
sec = Heading(doc._body, 1, False)
sec.add_run("ПРИЛОЖЕНИЯ")
a = Heading(doc._body, 2, True)
a.add_run("Приложение А Графический материал")
b = Heading(doc._body, 2, True)
b.add_run("Приложение Б Листинг")
out = renderer._ensure_appendix_index([sec, a, b])
assert len(out) == 5 # sec + 2 index lines + a + b
assert out[0] is sec
t0 = out[1]._docx_paragraph.text
t1 = out[2]._docx_paragraph.text
assert t0.startswith("Приложение А")
assert "Графический материал" in t0
assert t1.startswith("Приложение Б")
assert "Листинг" in t1
assert out[3] is a
assert out[4] is b
# If list already present — do not duplicate
from md2gost.renderable.paragraph import Paragraph
manual = Paragraph(doc._body)
manual.add_run("Приложение А — вручную")
out2 = renderer._ensure_appendix_index([sec, manual, a, b])
assert out2 == [sec, manual, a, b]
def test_caption_table_keep_with_next_and_toc_styles():
import docx
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING