import os import docx from docx.document import Document from .debugger import Debugger from .parser_ import Parser from .toc_processor import TocProcessor from .renderer import Renderer from .styles import apply_document_styles from .profiles import ( preprocess_markdown, find_formula_refs, get_profile, DEFAULT_HEADING_NUMBERING, HEADING_NUMBERING_MODES, DEFAULT_TOC_MODE, TOC_MODES, DEFAULT_TABLE_CONTINUATION, DEFAULT_LISTING_CONTINUATION, TABLE_CONTINUATION_MODES, LISTING_CONTINUATION_MODES, ) from .label_pass import ( assign_numbers, set_active_registry, resolve_reference, resolve_pending_in_renderables, ) from .renderable.heading import Heading from .renderable.toc import ToC from .renderable.table import Table from .renderable.listing import Listing from .renderable.diagram import DiagramFigure class Converter: """Converts markdown file to docx file (MIREA TZ).""" def __init__(self, input_path: str, output_path: str, template_path: str = None, debug: bool = False, doc_type: str = "practice", heading_numbering: str = DEFAULT_HEADING_NUMBERING, emdash_to_hyphen: bool = False, toc_mode: str = DEFAULT_TOC_MODE, table_continuation: str = DEFAULT_TABLE_CONTINUATION, listing_continuation: str = DEFAULT_LISTING_CONTINUATION, hr_pagebreak: bool = False, styles_path: str | None = None, markdown_text: str | None = None): if heading_numbering not in HEADING_NUMBERING_MODES: raise ValueError( f"heading_numbering must be one of {HEADING_NUMBERING_MODES}, " f"got {heading_numbering!r}" ) if toc_mode not in TOC_MODES: raise ValueError( f"toc_mode must be one of {TOC_MODES}, got {toc_mode!r}" ) if table_continuation not in TABLE_CONTINUATION_MODES: raise ValueError( f"table_continuation must be one of {TABLE_CONTINUATION_MODES}, " f"got {table_continuation!r}" ) if listing_continuation not in LISTING_CONTINUATION_MODES: raise ValueError( f"listing_continuation must be one of {LISTING_CONTINUATION_MODES}, " f"got {listing_continuation!r}" ) self._output_path = output_path self._doc_type = doc_type self._heading_numbering = heading_numbering self._emdash_to_hyphen = emdash_to_hyphen self._toc_mode = toc_mode self._table_continuation = table_continuation self._listing_continuation = listing_continuation self._hr_pagebreak = hr_pagebreak self._styles_path = styles_path self._profile = get_profile(doc_type) self._document: Document = docx.Document(template_path) self._document._body.clear_content() md_dir = os.path.dirname(os.path.abspath(input_path)) or "." os.environ["WORKING_DIR"] = md_dir self._style_config = apply_document_styles( self._document, self._profile.style_preset, md_dir=md_dir, styles_path=styles_path, ) self._debugger = Debugger(self._document) if debug else None if markdown_text is not None: raw = markdown_text else: with open(input_path, encoding="utf-8") as f: raw = f.read() self._raw_markdown = raw self._preprocessed = preprocess_markdown(raw, emdash_to_hyphen=emdash_to_hyphen) self.parser = Parser(self._document, self._preprocessed, hr_pagebreak=hr_pagebreak) def convert(self): renderables = list(self.parser.parse()) from .biblio_processor import fold_bibliography renderables = fold_bibliography( renderables, self._document._body, raw_markdown=self._preprocessed ) # Resolve heading numbering mode + TOC mode + table continuation for r in renderables: if isinstance(r, Heading): r.apply_numbering_mode(self._heading_numbering) elif isinstance(r, ToC): r.set_heading_numbering(self._heading_numbering) r.set_toc_mode(self._toc_mode) elif isinstance(r, Table): r.set_continuation_mode(self._table_continuation) elif isinstance(r, Listing): r.set_continuation_mode(self._listing_continuation) elif isinstance(r, DiagramFigure) and r.listing: r.listing.set_continuation_mode(self._listing_continuation) formula_refs = find_formula_refs(self._raw_markdown) registry = assign_numbers( renderables, formula_refs, numbering_scope=self._profile.numbering_scope, ) set_active_registry(registry) resolve_pending_in_renderables(renderables, resolve_reference) renderer = Renderer(self._document, self._debugger, numbered_equations=formula_refs, skip_numbering=True, numbering_scope=self._profile.numbering_scope) renderer.process(renderables) TocProcessor().process(renderables) set_active_registry(None) @property def document(self) -> Document: return self._document @property def style_config(self): return self._style_config @property def raw_markdown(self) -> str: return self._raw_markdown @property def doc_type(self) -> str: return self._doc_type @property def heading_numbering(self) -> str: return self._heading_numbering