ГОСТ
This commit is contained in:
Mikan
2025-12-08 19:49:15 +03:00
parent cc98c9cf03
commit 4a48e8de85
4 changed files with 176 additions and 3 deletions

View File

@@ -67,4 +67,4 @@ styles:
line_spacing: 1.0
colors:
LinkColor: "0000FF"
LinkColor: "000"

View File

@@ -14,6 +14,13 @@ def process_document(
template_path: Optional[Path] = None, theme_name: Optional[str] = None,
plugins_dir: Optional[Path] = None, dry_run: bool = False
):
if theme_name:
theme_path = Path("resources/themes") / f"{theme_name}.yaml"
if theme_path.exists():
style_config_path = theme_path
else:
logger.warning(f"Тема {theme_name} не найдена, используем стандартный стиль")
if plugins_dir and plugins_dir.exists():
load_plugins_from_path(plugins_dir)
@@ -42,6 +49,7 @@ def process_document(
style_reg = StyleRegistry(style_config_path)
style_reg.ensure_styles_in_doc(doc)
style_reg.apply_page_layout(doc) # ✅ применяем поля
render_markdown_to_docx(doc, md_content, images_dir, style_reg)
output_path = output_dir / f"{doc_name}.docx"

View File

@@ -1,9 +1,8 @@
import yaml
from docx import Document
from docx.enum.style import WD_STYLE_TYPE
from docx.shared import Pt, RGBColor
from docx.shared import Pt, Cm, RGBColor
from docx.enum.text import WD_LINE_SPACING, WD_ALIGN_PARAGRAPH
from docx.styles.style import ParagraphStyle
class StyleRegistry:
def __init__(self, config_path):
@@ -20,6 +19,24 @@ class StyleRegistry:
style = doc.styles.add_style(name, WD_STYLE_TYPE.PARAGRAPH)
self.apply_style(style, name)
def apply_page_layout(self, doc: Document):
"""Применяет настройки страницы (поля)."""
page_cfg = self.config.get("page", {})
margins = page_cfg.get("margins", {})
if not margins:
return
sections = doc.sections
for section in sections:
if "top" in margins:
section.top_margin = Cm(margins["top"])
if "bottom" in margins:
section.bottom_margin = Cm(margins["bottom"])
if "left" in margins:
section.left_margin = Cm(margins["left"])
if "right" in margins:
section.right_margin = Cm(margins["right"])
def apply_style(self, style, style_name: str):
cfg = self.config["styles"].get(style_name)
if not cfg:
@@ -50,6 +67,9 @@ class StyleRegistry:
align = alignment_map.get(para_cfg["alignment"])
if align:
pf.alignment = align
if "first_line_indent" in para_cfg:
from docx.shared import Mm
pf.first_line_indent = Mm(para_cfg["first_line_indent"])
def get_color(self, key: str):
hex_color = self.config.get("colors", {}).get(key, "000000")

145
tests/test_page_layout.py Normal file
View File

@@ -0,0 +1,145 @@
import pytest
from pathlib import Path
from docx import Document
from src.core.style_registry import StyleRegistry
def test_apply_page_layout_all_margins():
"""Тест: все поля заданы."""
yaml_content = """
page:
margins:
top: 2.0
bottom: 2.0
left: 3.0
right: 1.0
styles:
Normal:
font:
name: "Arial"
size: 12
"""
yaml_path = Path("tests/fixtures/test_layout_all.yaml")
yaml_path.parent.mkdir(exist_ok=True)
yaml_path.write_text(yaml_content, encoding="utf-8")
doc = Document()
style_reg = StyleRegistry(yaml_path)
style_reg.apply_page_layout(doc)
section = doc.sections[0]
assert abs(section.top_margin.cm - 2.0) < 0.01
assert abs(section.bottom_margin.cm - 2.0) < 0.01
assert abs(section.left_margin.cm - 3.0) < 0.01
assert abs(section.right_margin.cm - 1.0) < 0.01
yaml_path.unlink(missing_ok=True)
def test_apply_page_layout_partial_margins():
"""Тест: заданы не все поля."""
yaml_content = """
page:
margins:
top: 1.5
left: 2.5
styles:
Normal:
font:
name: "Arial"
size: 12
"""
yaml_path = Path("tests/fixtures/test_layout_partial.yaml")
yaml_path.parent.mkdir(exist_ok=True)
yaml_path.write_text(yaml_content, encoding="utf-8")
doc = Document()
style_reg = StyleRegistry(yaml_path)
style_reg.apply_page_layout(doc)
section = doc.sections[0]
assert abs(section.top_margin.cm - 1.5) < 0.01
assert abs(section.left_margin.cm - 2.5) < 0.01
# Остальные поля не должны измениться (остаются по умолчанию)
# У docx по умолчанию: top=2.54, bottom=2.54, left=3.17, right=3.17
# Но мы их не трогаем, если в YAML нет
yaml_path.unlink(missing_ok=True)
def test_apply_page_layout_no_page_section():
"""Тест: в YAML нет секции page."""
yaml_content = """
styles:
Normal:
font:
name: "Arial"
size: 12
"""
yaml_path = Path("tests/fixtures/test_layout_no_page.yaml")
yaml_path.parent.mkdir(exist_ok=True)
yaml_path.write_text(yaml_content, encoding="utf-8")
doc = Document()
style_reg = StyleRegistry(yaml_path)
style_reg.apply_page_layout(doc)
section = doc.sections[0]
# Поля не должны измениться (остаются по умолчанию)
# top=2.54 cm по умолчанию
assert abs(section.top_margin.cm - 2.54) < 0.01
yaml_path.unlink(missing_ok=True)
def test_apply_page_layout_no_margins():
"""Тест: в YAML есть page, но нет margins."""
yaml_content = """
page:
other_option: value
styles:
Normal:
font:
name: "Arial"
size: 12
"""
yaml_path = Path("tests/fixtures/test_layout_no_margins.yaml")
yaml_path.parent.mkdir(exist_ok=True)
yaml_path.write_text(yaml_content, encoding="utf-8")
doc = Document()
style_reg = StyleRegistry(yaml_path)
style_reg.apply_page_layout(doc)
section = doc.sections[0]
# Поля не должны измениться
assert abs(section.top_margin.cm - 2.54) < 0.01
yaml_path.unlink(missing_ok=True)
def test_apply_page_layout_zero_margins():
"""Тест: нулевые поля."""
yaml_content = """
page:
margins:
top: 0.0
bottom: 0.0
left: 0.0
right: 0.0
styles:
Normal:
font:
name: "Arial"
size: 12
"""
yaml_path = Path("tests/fixtures/test_layout_zero.yaml")
yaml_path.parent.mkdir(exist_ok=True)
yaml_path.write_text(yaml_content, encoding="utf-8")
doc = Document()
style_reg = StyleRegistry(yaml_path)
style_reg.apply_page_layout(doc)
section = doc.sections[0]
assert abs(section.top_margin.cm - 0.0) < 0.01
assert abs(section.bottom_margin.cm - 0.0) < 0.01
assert abs(section.left_margin.cm - 0.0) < 0.01
assert abs(section.right_margin.cm - 0.0) < 0.01
yaml_path.unlink(missing_ok=True)