Skip to content

Commit ac070bb

Browse files
committed
Implement support for docm (macros)
python-openxml#1407
1 parent c182d28 commit ac070bb

File tree

4 files changed

+23
-1
lines changed

4 files changed

+23
-1
lines changed

src/docx/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def part_class_selector(content_type: str, reltype: str) -> Type[Part] | None:
5454
PartFactory.part_type_for[CT.WML_COMMENTS_IDS] = CommentsIdsPart
5555
PartFactory.part_type_for[CT.WML_PEOPLE] = PeoplePart
5656
PartFactory.part_type_for[CT.WML_DOCUMENT_MAIN] = DocumentPart
57+
PartFactory.part_type_for[CT.WML_DOCUMENT_MAIN_WITH_MACROS] = DocumentPart
5758
PartFactory.part_type_for[CT.WML_FOOTER] = FooterPart
5859
PartFactory.part_type_for[CT.WML_HEADER] = HeaderPart
5960
PartFactory.part_type_for[CT.WML_NUMBERING] = NumberingPart

src/docx/api.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ def Document(docx: str | IO[bytes] | None = None) -> DocumentObject:
2525
"""
2626
docx = _default_docx_path() if docx is None else docx
2727
document_part = cast("DocumentPart", Package.open(docx).main_document_part)
28-
if document_part.content_type != CT.WML_DOCUMENT_MAIN:
28+
if document_part.content_type not in (
29+
CT.WML_DOCUMENT_MAIN,
30+
CT.WML_DOCUMENT_MAIN_WITH_MACROS,
31+
):
2932
tmpl = "file '%s' is not a Word file, content type is '%s'"
3033
raise ValueError(tmpl % (docx, document_part.content_type))
3134
return document_part.document

src/docx/opc/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class CONTENT_TYPE:
146146
WML_DOCUMENT_MAIN = (
147147
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
148148
)
149+
WML_DOCUMENT_MAIN_WITH_MACROS = "application/vnd.ms-word.document.macroEnabled.main+xml"
149150
WML_ENDNOTES = "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml"
150151
WML_FONT_TABLE = "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"
151152
WML_FOOTER = "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"

tests/test_api.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
import pytest
44

5+
import docx
56
from docx.api import Document as DocumentFactoryFn
67
from docx.document import Document as DocumentCls
78
from docx.opc.constants import CONTENT_TYPE as CT
9+
from docx.opc.part import PartFactory
10+
from docx.parts.document import DocumentPart
811

912
from .unitutil.mock import FixtureRequest, Mock, class_mock, function_mock, instance_mock
1013

@@ -35,12 +38,26 @@ def it_opens_the_default_docx_if_none_specified(
3538
Package_.open.assert_called_once_with("default-document.docx")
3639
assert document is document_
3740

41+
def it_opens_a_docm_file(self, Package_: Mock, document_: Mock):
42+
document_part = Package_.open.return_value.main_document_part
43+
document_part.document = document_
44+
document_part.content_type = CT.WML_DOCUMENT_MAIN_WITH_MACROS
45+
46+
document = DocumentFactoryFn("foobar.docm")
47+
48+
Package_.open.assert_called_once_with("foobar.docm")
49+
assert document is document_
50+
3851
def it_raises_on_not_a_Word_file(self, Package_: Mock):
3952
Package_.open.return_value.main_document_part.content_type = "BOGUS"
4053

4154
with pytest.raises(ValueError, match="file 'foobar.xlsx' is not a Word file,"):
4255
DocumentFactoryFn("foobar.xlsx")
4356

57+
def it_registers_macro_enabled_main_document_parts_with_the_package_reader(self):
58+
assert docx is not None
59+
assert PartFactory.part_type_for[CT.WML_DOCUMENT_MAIN_WITH_MACROS] is DocumentPart
60+
4461
# -- fixtures --------------------------------------------------------------------------------
4562

4663
@pytest.fixture

0 commit comments

Comments
 (0)