question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Restart numbering of an ordered list in document.

See original GitHub issue

We can easily add ordered list with document.add_paragraph(style='ListNumber') code. But how can we restart its numbering?

Issue Analytics

  • State:open
  • Created 10 years ago
  • Reactions:4
  • Comments:35 (3 by maintainers)

github_iconTop GitHub Comments

8reactions
madphysicistcommented, Jul 11, 2018

So I’ve made a thing that searches the existing abstract numbering schemes for the style of the current paragraph, and sets a reasonable abstract style based on that if possible:

def list_number(doc, par, prev=None, level=None, num=True):
    """
    Makes a paragraph into a list item with a specific level and
    optional restart.

    An attempt will be made to retreive an abstract numbering style that
    corresponds to the style of the paragraph. If that is not possible,
    the default numbering or bullet style will be used based on the
    ``num`` parameter.

    Parameters
    ----------
    doc : docx.document.Document
        The document to add the list into.
    par : docx.paragraph.Paragraph
        The paragraph to turn into a list item.
    prev : docx.paragraph.Paragraph or None
        The previous paragraph in the list. If specified, the numbering
        and styles will be taken as a continuation of this paragraph.
        If omitted, a new numbering scheme will be started.
    level : int or None
        The level of the paragraph within the outline. If ``prev`` is
        set, defaults to the same level as in ``prev``. Otherwise,
        defaults to zero.
    num : bool
        If ``prev`` is :py:obj:`None` and the style of the paragraph
        does not correspond to an existing numbering style, this will
        determine wether or not the list will be numbered or bulleted.
        The result is not guaranteed, but is fairly safe for most Word
        templates.
    """
    xpath_options = {
        True: {'single': 'count(w:lvl)=1 and ', 'level': 0},
        False: {'single': '', 'level': level},
    }

    def style_xpath(prefer_single=True):
        """
        The style comes from the outer-scope variable ``par.style.name``.
        """
        style = par.style.style_id
        return (
            'w:abstractNum['
                '{single}w:lvl[@w:ilvl="{level}"]/w:pStyle[@w:val="{style}"]'
            ']/@w:abstractNumId'
        ).format(style=style, **xpath_options[prefer_single])

    def type_xpath(prefer_single=True):
        """
        The type is from the outer-scope variable ``num``.
        """
        type = 'decimal' if num else 'bullet'
        return (
            'w:abstractNum['
                '{single}w:lvl[@w:ilvl="{level}"]/w:numFmt[@w:val="{type}"]'
            ']/@w:abstractNumId'
        ).format(type=type, **xpath_options[prefer_single])

    def get_abstract_id():
        """
        Select as follows:

            1. Match single-level by style (get min ID)
            2. Match exact style and level (get min ID)
            3. Match single-level decimal/bullet types (get min ID)
            4. Match decimal/bullet in requested level (get min ID)
            3. 0
        """
        for fn in (style_xpath, type_xpath):
            for prefer_single in (True, False):
                xpath = fn(prefer_single)
                ids = numbering.xpath(xpath)
                if ids:
                    return min(int(x) for x in ids)
        return 0

    if (prev is None or
            prev._p.pPr is None or
            prev._p.pPr.numPr is None or
            prev._p.pPr.numPr.numId is None):
        if level is None:
            level = 0
        numbering = doc.part.numbering_part.numbering_definitions._numbering
        # Compute the abstract ID first by style, then by num
        anum = get_abstract_id()
        # Set the concrete numbering based on the abstract numbering ID
        num = numbering.add_num(anum)
        # Make sure to override the abstract continuation property
        num.add_lvlOverride(ilvl=level).add_startOverride(1)
        # Extract the newly-allocated concrete numbering ID
        num = num.numId
    else:
        if level is None:
            level = prev._p.pPr.numPr.ilvl.val
        # Get the previous concrete numbering ID
        num = prev._p.pPr.numPr.numId.val
    par._p.get_or_add_pPr().get_or_add_numPr().get_or_add_numId().val = num
    par._p.get_or_add_pPr().get_or_add_numPr().get_or_add_ilvl().val = level

This is in no way comprehensive or particularly robust, but it works pretty well for what I am trying to do.

2reactions
scannycommented, Jul 7, 2015

@downtown12 I don’t have time to develop step-by-step instructions for you, but if you’re looking for the right direction to start looking for yourself, these might be helpful:

  • The document object provides access to the numbering part for the document (numbering.xml). This call should get you there: document.part.numbering_part
  • The NumberingPart object provides access to a sequence of NumberingDefinition objects: numbering_part.numbering_definitions
  • The NumberingDefinitions class looks like where API support ends at the moment. You can get the w:numbering element from it though, which is the parent of all the numbering definitions: numbering_definitions._numbering. From there you’ll need to work with lxml calls to get it’s children using XPath and so on.
Read more comments on GitHub >

github_iconTop Results From Across the Web

Methods for restarting list numbering - Word MVP site
The most reliable way of creating numbered paragraphs is to use paragraph styles to apply the numbering. This makes all paragraphs with the...
Read more >
How to create a list with restarting and continuing numbering
Restart numbering from 1 · Right-click the selected number and choose Restart at 1 in the popup menu: Restart at 1 in the...
Read more >
How to Restart Numbering in Numbered List Word - YouTube
https://www.youtube.com/channel/UCmV5uZQcAXUW7s4j7rM0POg?sub_confirmation=1How to Restart Numbering in Numbered List Word.
Read more >
Restarting a Numbered List Easily - Word Ribbon Tips
The field braces, remember, are inserted in your document by pressing Ctrl+F9. The first field code inserts a sequence number, started at 1....
Read more >
Two Ways to Restart Numbered Lists in TX Text Control
Create an new style, name it Restart and select the preferred numbering. Since you want to restart the list, choose Restart numbering this...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found