Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/docx/parts/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ def numbering_part(self) -> NumberingPart:
try:
return cast(NumberingPart, self.part_related_by(RT.NUMBERING))
except KeyError:
numbering_part = NumberingPart.new()
assert self.package is not None
numbering_part = NumberingPart.new(self.package)
self.relate_to(numbering_part, RT.NUMBERING)
return numbering_part

Expand Down
34 changes: 29 additions & 5 deletions src/docx/parts/numbering.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,41 @@
"""|NumberingPart| and closely related objects."""

from ..opc.part import XmlPart
from ..shared import lazyproperty
from __future__ import annotations

import os
from typing import TYPE_CHECKING, cast

from docx.opc.constants import CONTENT_TYPE as CT
from docx.opc.packuri import PackURI
from docx.opc.part import XmlPart
from docx.oxml.parser import parse_xml
from docx.shared import lazyproperty

if TYPE_CHECKING:
from docx.oxml.numbering import CT_Numbering
from docx.package import Package


class NumberingPart(XmlPart):
"""Proxy for the numbering.xml part containing numbering definitions for a document
or glossary."""

@classmethod
def new(cls) -> "NumberingPart":
"""Newly created numbering part, containing only the root ``<w:numbering>`` element."""
raise NotImplementedError
def new(cls, package: Package) -> "NumberingPart":
"""Return a newly created numbering part, containing only the root ``<w:numbering>``
element."""
partname = PackURI("/word/numbering.xml")
content_type = CT.WML_NUMBERING
element = cast("CT_Numbering", parse_xml(cls._default_numbering_xml()))
return cls(partname, content_type, element, package)

@classmethod
def _default_numbering_xml(cls) -> bytes:
"""Return a bytestream containing XML for a default numbering part."""
path = os.path.join(os.path.split(__file__)[0], "..", "templates", "default-numbering.xml")
with open(path, "rb") as f:
xml_bytes = f.read()
return xml_bytes

@lazyproperty
def numbering_definitions(self):
Expand Down
5 changes: 5 additions & 0 deletions src/docx/templates/default-numbering.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:numbering
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
/>
2 changes: 1 addition & 1 deletion tests/parts/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def and_it_creates_a_numbering_part_if_not_present(

numbering_part = document_part.numbering_part

NumberingPart_.new.assert_called_once_with()
NumberingPart_.new.assert_called_once_with(package_)
relate_to_.assert_called_once_with(document_part, numbering_part_, RT.NUMBERING)
assert numbering_part is numbering_part_

Expand Down
16 changes: 16 additions & 0 deletions tests/parts/test_numbering.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import pytest

from docx.opc.constants import CONTENT_TYPE as CT
from docx.oxml.numbering import CT_Numbering
from docx.package import Package
from docx.parts.numbering import NumberingPart, _NumberingDefinitions

from ..oxml.unitdata.numbering import a_num, a_numbering
Expand All @@ -21,6 +23,20 @@ def it_provides_access_to_the_numbering_definitions(self, num_defs_fixture):
_NumberingDefinitions_.assert_called_once_with(numbering_elm_)
assert numbering_definitions is numbering_definitions_

def it_constructs_a_default_numbering_part_to_help(self):
package = Package()

numbering_part = NumberingPart.new(package)

assert isinstance(numbering_part, NumberingPart)
assert numbering_part.partname == "/word/numbering.xml"
assert numbering_part.content_type == CT.WML_NUMBERING
assert numbering_part.package is package
assert numbering_part.element.tag == (
"{http://schemas.openxmlformats.org/wordprocessingml/2006/main}numbering"
)
assert len(numbering_part.element) == 0

# fixtures -------------------------------------------------------

@pytest.fixture
Expand Down