Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python-docx restart list numbering

I am using python-docx and I am able to generate number lists. How do I have the numbers restart for those lists?

I want the lists to look like this.

List 1

  1. List 1 Item 1
  2. List 1 Item 2
  3. List 1 Item 3

List 2

  1. List 2 Item 1
  2. List 2 Item 2
  3. List 3 Item 3

Python-docx generates the items like this

  1. List 1 Item 1
  2. List 1 Item 2
  3. List 1 Item 3
  4. List 2 Item 1
  5. List 2 Item 2
  6. List 3 Item 3

I would appreciate help with fixing this issue.

like image 974
CJ Conti Avatar asked Nov 22 '25 13:11

CJ Conti


1 Answers

Numbering in Microsoft Word document and what python-docx supports

To be numbered, a paragraph is linked to a numbering. This can be done using a style that stores paragraph properties linked to a numbering or using paragraph properties linked to a numbering directly in paragraph.

Python-docx provides styles storing paragraph properties linked to a numbering. Those styles can be assigned to paragraphs. But each of the styles links to one numbering. That's why the numbering gets continued for each paragraph having this style.

How to solve?

Simplest would be using another list-style assigned to paragraphs in second list. Example:

from docx import Document
from docx.shared import Inches

document = Document()

paragraph = document.add_paragraph()
paragraph.add_run('List 1').bold = True

for i in range(1, 4):
    document.add_paragraph(
        f'List 1 Item {i}', style='List Number'
    )
    
paragraph = document.add_paragraph()
paragraph.add_run('List 2').bold = True

for i in range(1, 4):
    paragraph = document.add_paragraph(
            f'List 2 Item {i}', style='List Number 2'
        )        
    paragraph.paragraph_format.left_indent = Inches(.25)
    paragraph.paragraph_format.tab_stops.add_tab_stop(Inches(.25))

document.save('test.docx')

But, of course, this is limited to 3, as python-docx only provides 3 "List Number" styles per default. And each of those styles will have other different format settings too, which then needs to changed.

The more Word-like solution would be to prepare the numberings to have a new numbering, which points to the same abstract numbering, the style "List Number" also points to but has start override set. This new numbering then can be set to paragraph properties of first paragraph in second list then.

Unfortunately python-docx not provides much for numbering. Thus code will get lengthy because of the nee to use the low level CT_*classes directly. Example:

from docx import Document

document = Document()

paragraph = document.add_paragraph()
paragraph.add_run('List 1').bold = True

for i in range(1, 4):
    document.add_paragraph(
        f'List 1 Item {i}', style='List Number'
    )
    
paragraph = document.add_paragraph()
paragraph.add_run('List 2').bold = True

#prepare the numberings to have a new numbering, which points to the same abstract numbering, 
#the style "List Number" also points to but has start override set
styles = document.styles
#get numId to which style 'List Number' links
num_id_list_number = -1
for style in styles:
    if (style.name == 'List Number'):
        num_id_list_number = style._element.pPr.numPr.numId.val
#add new numbering linking to same abstractNumId but has startOverride 
#and get new numId
num_id_list_number_new = -1
if (num_id_list_number > -1):        
    ct_numbering = document.part.numbering_part.numbering_definitions._numbering
    ct_num = ct_numbering.num_having_numId(num_id_list_number)
    abstractNumId = ct_num.abstractNumId.val
    ct_num = ct_numbering.add_num(abstractNumId)
    num_id_list_number_new = ct_num.numId
    startOverride = ct_num.add_lvlOverride(0)._add_startOverride()
    startOverride.val = 1

for i in range(1, 4):
    paragraph = document.add_paragraph(
            f'List 2 Item {i}', style='List Number'
        )
    
    #first paragraph in new list links to new numId having startOverride
    if ( i == 1 and num_id_list_number_new > -1):
        numPr = paragraph._element.pPr._add_numPr()
        numPr._add_numId().val = num_id_list_number_new

document.save('test.docx')
like image 93
Axel Richter Avatar answered Nov 25 '25 04:11

Axel Richter