Search code examples
pythonpython-docx

Using Python's docx library, how can a table be indented?


How can a docx table be indented? I am trying to line a table up with a tab stop set at 2cm. The following script creates a header, some text and a table:

import docx
from docx.shared import Cm

doc = docx.Document()

style = doc.styles['Normal']
style.paragraph_format.tab_stops.add_tab_stop(Cm(2))

doc.add_paragraph('My header', style='Heading 1')
doc.add_paragraph('\tText is tabbed')

# This indents the paragraph inside, not the table
# style = doc.styles['Table Grid']
# style.paragraph_format.left_indent = Cm(2)

table = doc.add_table(rows=0, cols=2, style="Table Grid")

for rowy in range(1, 5):
    row_cells = table.add_row().cells

    row_cells[0].text = 'Row {}'.format(rowy)
    row_cells[0].width = Cm(5)

    row_cells[1].text = ''
    row_cells[1].width = Cm(1.2)

doc.save('output.docx')

It produces a table with no ident as follows:

no indent

How can the table be indented as follows?
(preferably without having to load an existing document):

Desired output

If for example left-indent is added to the Table Grid style (by uncommenting the lines), it will be applied at the paragraph level, not the table level resulting in the following (which is not wanted):

indented at paragraph level

In Microsoft Word, this can be done on the table properties by entering 2.0 cm for Indent from left.


Solution

  • Based on Fred C's answer, I came up with this solution:

    from docx.oxml import OxmlElement
    from docx.oxml.ns import qn
    
    def indent_table(table, indent):
        # noinspection PyProtectedMember
        tbl_pr = table._element.xpath('w:tblPr')
        if tbl_pr:
            e = OxmlElement('w:tblInd')
            e.set(qn('w:w'), str(indent))
            e.set(qn('w:type'), 'dxa')
            tbl_pr[0].append(e)