Profiling generate_doc(selections, DEFAULT_DOC_VERSION) with cProfile:
79820 calls β docx get_style() 12.2s cumulative
53092 calls β Styles.default() 10.4s cumulative (70% of total runtime)
Root cause: python-docx's Styles.default() has no internal caching β every time you access run.style.name (or paragraph.style.name) for a run/paragraph with no explicitly applied style, it re-walks the entire style tree in the document's XML to find the default. mogrifier.py's create_control_structures() and remove_toggles() call run.style.name on every single run in the document (tens of thousands of them) just to check == 'Toggle', and most runs don't have an explicit style, so nearly every call triggered a full style-tree rescan.
Fix: Add two small memoizing wrappers in mogrifier.py β get_run_style_name() / get_paragraph_style_name() β keyed on (part, style_id) (the raw XML style id, read directly off the element, which is cheap). Since the style-idβname mapping can't change while we're processing a doc, this eliminates the redundant rescans. Caches are cleared at the top of mogrify_doc() alongside the existing elements_to_delete reset.
Profiling
generate_doc(selections, DEFAULT_DOC_VERSION)with cProfile:Root cause:
python-docx'sStyles.default()has no internal caching β every time you accessrun.style.name(orparagraph.style.name) for a run/paragraph with no explicitly applied style, it re-walks the entire style tree in the document's XML to find the default.mogrifier.py'screate_control_structures()andremove_toggles()callrun.style.nameon every single run in the document (tens of thousands of them) just to check== 'Toggle', and most runs don't have an explicit style, so nearly every call triggered a full style-tree rescan.Fix: Add two small memoizing wrappers in
mogrifier.pyβget_run_style_name()/get_paragraph_style_name()β keyed on(part, style_id)(the raw XML style id, read directly off the element, which is cheap). Since the style-idβname mapping can't change while we're processing a doc, this eliminates the redundant rescans. Caches are cleared at the top ofmogrify_doc()alongside the existingelements_to_deletereset.