Skip to content

Bulk style import and extract, on top of copy_style_from() #116

Closed

Description

@toxicphreAK

Styles.copy_style_from() (#87) moves one style between documents, resolving its w:basedOn / w:next / w:link closure and carrying numbering across. That is the hard part and it is done. What is missing is everything built on it.

Two operations, both currently written by hand by anyone doing document generation from a corporate template:

Import

document.styles.import_from("house-template.dotx")                      # everything
document.styles.import_from(other_document, names=["Quote", "Caption"])
document.styles.import_from(tmpl, overwrite=True)                       # replace same-named
  • Styles.import_from(source, names=None, *, overwrite=False, include_latent=False)
  • source accepting a path, a file-like object or an open Document — a .dotx is the common case and already opens
  • names=None meaning every style defined in the source
  • overwrite=False skipping names already present, True replacing them; returning what it did either way, because "why is my heading still the wrong colour" is otherwise unanswerable

The naive loop over copy_style_from() is O(n) full closure resolutions with repeated work and repeated numbering imports. Bulk import should resolve the whole closure once.

Extract

document.styles.extract("styles-only.docx", names=["Quote", "Caption"])
xml = document.styles.extract_xml(names=[...])

Write the selected styles, with their closure, to a standalone document — a styles-only .docx or .dotx that is a valid Word template. That makes the round trip work: pull the styles you like out of a document someone sent you, keep them as a template, apply them to everything you generate.

extract_xml() returning the styles.xml bytes covers the case where the caller wants to diff or version-control them.

Why this matters here

It is the practical answer to the part of #23 that needs Word. If a caller has any Word-authored document containing the styles they need, import_from() gets those authentic definitions into their document without anyone hand-authoring w:style elements or guessing at Word's default spacing values.

The same trick applies to the library's own gap: the repo already contains Word-authored definitions of Hyperlink, CommentText and CommentReference in features/steps/test_files/comments-rich-para.docx — see #117.

Watch out for

  • w:styleId collisions between source and destination when the names differ — two documents can each have a Style1 meaning different things. Remap ids on import; do not assume they are stable.
  • Numbering: importing a style whose w:pPr/w:numPr names a numId requires importing the w:num and its w:abstractNum, renumbered into the destination's id space. copy_style_from() does this for one style; make sure the bulk path does not double-import shared abstract numbering.
  • Theme-dependent values. A style specifying w:asciiTheme="minorHAnsi" renders with the destination's theme after import, which may not be what the caller saw in the source. Worth a documented note; resolving it properly needs Expose the theme part and resolve theme typefaces to real font names #96.
  • include_latent defaulting to False: importing the source's w:latentStyles block wholesale changes which styles appear in Word's gallery for the destination, which is rarely what was asked for.

Activity

  1. toxicphreAK commented on Aug 5, 2026

    @toxicphreAK
    OwnerAuthor

    Landed in #139. Styles.import_from(), Styles.extract() and Styles.extract_xml(). import_from() takes a path, a stream or an open Document and reports added/replaced/skipped per name. The extract prunes the bundled template's own styles first, or the result would be mostly those. include_latent defaults to False. The theme-font caveat is documented on the method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions