Numbered and bulleted lists¶
A list number is nowhere in the document body. Word stores which list a paragraph belongs
to and computes "1.", "a)" or "iii." from numbering.xml at display time, which is why
reading a document gives you paragraph text with the numbers missing.
This library computes them the same way Word does.
Reading the numbers¶
Document.list_numbers pairs every list paragraph
in the body with the number a reader sees:
from docx import Document
document = Document("report.docx")
for paragraph, number in document.list_numbers:
print(number, paragraph.text)
Paragraphs inside tables are included, because they count towards the same lists.
Paragraph.list_number gives the number for
a single paragraph, and None when it is not in a list:
Warning
A list number depends on every paragraph before it, so reading
Paragraph.list_number in a loop is
quadratic. Use Document.list_numbers, which
walks the document once.
Which list a paragraph is in¶
Paragraph.numbering returns a
ParagraphNumbering, or None when the paragraph
is not in a list:
item = document.add_paragraph("first item", style="List Number")
numbering = item.numbering
numbering.num_id # -> the list this paragraph belongs to
numbering.level # -> indent level, 0 for the outermost
numbering.from_style # -> True when the style applies it, not the paragraph
numbering.level_definition # -> the NumberingLevel, for format and start value
The level definition is where the appearance lives:
level = item.numbering.level_definition
level.number_format # -> WD_NUMBER_FORMAT.DECIMAL
level.start # -> 1
level.is_bullet # -> False
level.format_number(3) # -> "3."
format_number() applies the level's own
template, so a level written as %1) in lower letters gives "c)" for the same input.
WD_NUMBER_FORMAT lists the formats.
Creating a list¶
The simplest lists are the built-in styles, which carry their own numbering:
document.add_paragraph("first item", style="List Bullet")
document.add_paragraph("first item", style="List Number")
To put further paragraphs in the same list as an existing one, take its num_id:
first = document.add_paragraph("one", style="List Number")
second = document.add_paragraph("two")
second.set_numbering(first.numbering.num_id)
set_numbering() also takes a level, so
nesting is a matter of saying which:
Numbering applied directly like this overrides whatever the paragraph's style would
apply. remove_numbering() takes it
off again.
Restarting numbering¶
This paragraph and every later one in the same list start a new sequence; paragraphs before it keep the original one. That is what Word's own "Restart at 1" does.
It is worth knowing what happens underneath, because it explains the return value. OOXML
has no counter to reset. A second w:num is created against the same abstract
definition, carrying a w:startOverride, and the affected paragraphs are pointed at it —
so restart_numbering() returns the
num_id of that new list:
new_num_id = item.restart_numbering()
later = document.add_paragraph("still in the restarted list")
later.set_numbering(new_num_id)
It raises ValueError when the paragraph is not in a list.
The numbering part¶
Document.numbering is the whole of
numbering.xml, for finding a list to join or inspecting one:
definition = document.numbering.get(item.numbering.num_id)
definition.num_id
definition.abstract_num_id
definition.levels # -> the NumberingLevel objects, one per level
definition.level(0)
Numbering.restart() creates the overriding
definition directly, when you want the new list without repointing any paragraphs:
Defining a list from scratch¶
Everything above joins or restarts a list the numbering part already defines. When the format you want is not in the template — Roman numerals at the top level, a bullet character of your own, a particular indent step — define one:
definition = document.numbering.add_numbered_definition()
document.add_paragraph("one").set_numbering(definition.num_id)
add_numbered_definition() and
add_bulleted_definition() are the
two common cases. Both take a depth (nine levels by default, which is what Word writes)
and an indent_step:
from docx.enum.numbering import WD_NUMBER_FORMAT
from docx.shared import Inches
legal = document.numbering.add_numbered_definition(
depth=3,
formats=[
WD_NUMBER_FORMAT.UPPER_ROMAN,
WD_NUMBER_FORMAT.UPPER_LETTER,
WD_NUMBER_FORMAT.DECIMAL,
],
indent_step=Inches(0.3),
)
bullets = document.numbering.add_bulleted_definition(bullets=["—", "·"])
add_definition() is the general form, taking
a level specification directly. Both shorthands are built on it:
definition = document.numbering.add_definition([
{"number_format": WD_NUMBER_FORMAT.DECIMAL, "level_text": "%1.", "start": 1},
{"number_format": WD_NUMBER_FORMAT.LOWER_LETTER, "level_text": "%2)"},
])
In a level_text, %1 interpolates the counter of level 0, %2 that of level 1, and so
on — "%1.%2." is what produces "2.3.". A definition has at most nine levels; more raises
ValueError.
Each returns a NumberingDefinition, whose num_id
is what set_numbering() takes.
Note
w:nsid and w:tmpl are deliberately not written. They are the identifiers Word uses
to recognise a definition as one of its own and to match it against a gallery entry;
inventing values would make Word treat unrelated lists as the same list, and they are
optional.
Changing a level¶
NumberingLevel.set() changes an existing level in
place, and returns the level so calls chain:
definition.level(0).set(
number_format=WD_NUMBER_FORMAT.UPPER_ROMAN,
level_text="%1.",
suffix="tab",
alignment="left",
indent=Inches(0.5),
hanging_indent=Inches(0.25),
start=1,
)
suffix is what follows the number — "tab", "space" or "nothing" — and
restart_after_level is what makes a sub-list start over when the level above it advances.
Every argument is keyword-only and optional; the ones you leave out are left alone.