v0.5.3
Example document / build (push) Has been cancelled
Python application / build (push) Has been cancelled

- Мелкие исправления увеличивающие работу конвертера
This commit is contained in:
Igor20264
2026-09-10 10:50:15 +03:00
parent 658036f920
commit f7136bd8bd
95 changed files with 7165 additions and 8771 deletions
+163
View File
@@ -0,0 +1,163 @@
"""Оформление листинга и флаг подсветки синтаксиса.
Методичка МИРЭА, табл. 4.1 (`_method_extract.txt`, строки 716-737), блок
«Содержание листинга»: шрифт Courier New, начертание Обычный, размер 10 пт,
цвет текста Авто (чёрный), выравнивание по левому краю, отступы слева/справа
0 см, первая строка 0 см, интервал перед и после 0 мм, междустрочный
одинарный.
Отсюда два независимых требования:
* с выключенной подсветкой (дефолт) содержимое листинга не должно нести
никакого прямого форматирования на уровне run'а;
* если пользователь всё же включил `--syntax-highlighting`, флаг обязан
работать честно — курсив из стиля Pygments должен доезжать до XML, а checker
обязан предупредить об отклонении от табл. 4.1.
"""
import os
import unittest
from contextlib import contextmanager
import docx
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING
from docx.oxml.ns import qn
from docx.shared import Pt
from md2gost import package_dir
from md2gost.checker import check_markdown
from md2gost.renderable.caption import CaptionInfo
from md2gost.renderable.listing import Listing
from md2gost.styles import apply_mirea_styles
CODE = '# комментарий\nprint("hello")\n'
MD_WITH_LISTING = """# *СОДЕРЖАНИЕ
[TOC]
# Раздел
%code1 Пример кода
```python
print(1)
```
См. @Листинг:code1.
"""
@contextmanager
def _syntax_highlighting(enabled: bool):
previous = os.environ.get("SYNTAX_HIGHLIGHTING")
if enabled:
os.environ["SYNTAX_HIGHLIGHTING"] = "1"
else:
os.environ.pop("SYNTAX_HIGHLIGHTING", None)
try:
yield
finally:
if previous is None:
os.environ.pop("SYNTAX_HIGHLIGHTING", None)
else:
os.environ["SYNTAX_HIGHLIGHTING"] = previous
class _ListingTestCase(unittest.TestCase):
def setUp(self) -> None:
self._document = docx.Document(os.path.join(package_dir(), "Template.docx"))
self._document._body.clear_content()
apply_mirea_styles(self._document)
def _listing(self, highlighting: bool) -> Listing:
listing = Listing(self._document._body, "python", CaptionInfo("code1", "Пример"))
with _syntax_highlighting(highlighting):
listing.set_text(CODE)
return listing
@staticmethod
def _runs(listing: Listing):
for paragraph in listing.paragraphs:
for run in paragraph._docx_paragraph.runs:
yield run
class TestListingWithoutHighlighting(_ListingTestCase):
"""Табл. 4.1: содержимое листинга — Обычный, чёрный, Courier New 10 пт."""
def test_runs_carry_no_direct_formatting(self):
listing = self._listing(highlighting=False)
runs = list(self._runs(listing))
self.assertTrue(runs)
for run in runs:
rPr = run._element.find(qn("w:rPr"))
if rPr is None:
continue
self.assertIsNone(rPr.find(qn("w:b")), run.text)
self.assertIsNone(rPr.find(qn("w:i")), run.text)
self.assertIsNone(rPr.find(qn("w:color")), run.text)
def test_code_style_matches_table_4_1(self):
style = self._document.styles["Code"]
self.assertEqual("Courier New", style.font.name)
self.assertEqual(Pt(10), style.font.size)
self.assertFalse(style.font.bold)
self.assertFalse(style.font.italic)
pf = style.paragraph_format
self.assertEqual(WD_ALIGN_PARAGRAPH.LEFT, pf.alignment)
self.assertAlmostEqual(0, pf.first_line_indent.cm, places=3)
self.assertAlmostEqual(0, pf.left_indent.cm, places=3)
self.assertAlmostEqual(0, pf.space_before.mm, places=3)
self.assertAlmostEqual(0, pf.space_after.mm, places=3)
self.assertEqual(WD_LINE_SPACING.SINGLE, pf.line_spacing_rule)
class TestListingWithHighlighting(_ListingTestCase):
"""Включённый флаг обязан реально давать курсив там, где его задаёт Pygments."""
def test_italic_token_reaches_xml(self):
listing = self._listing(highlighting=True)
italic_runs = [run for run in self._runs(listing) if run.italic]
self.assertTrue(
italic_runs,
"ни один run не получил курсив, хотя стиль Pygments задаёт italic "
"для Token.Comment",
)
self.assertTrue(
any("комментарий" in run.text for run in italic_runs),
[run.text for run in italic_runs],
)
class TestSyntaxHighlightingChecker(unittest.TestCase):
"""Подсветка противоречит табл. 4.1 — checker обязан об этом сказать."""
def test_no_issue_when_flag_is_off(self):
issues = check_markdown(MD_WITH_LISTING, "coursework")
self.assertEqual(
[], [i for i in issues if i.id == "listing.syntax_highlighting"]
)
def test_warning_when_flag_is_on(self):
issues = check_markdown(
MD_WITH_LISTING, "coursework", syntax_highlighting=True
)
found = [i for i in issues if i.id == "listing.syntax_highlighting"]
self.assertEqual(1, len(found))
self.assertEqual("warning", found[0].severity)
def test_error_under_strict(self):
issues = check_markdown(
MD_WITH_LISTING, "coursework", syntax_highlighting=True, strict=True
)
found = [i for i in issues if i.id == "listing.syntax_highlighting"]
self.assertEqual(1, len(found))
self.assertEqual("error", found[0].severity)