Hi, the autofit method is broken in 0.8.5. Tables behave like if the columns have fixed width.
When autofit is set, tag(s) <w:tcW/> for the table(s) in document.xml should be set to something like <w:tcW w:type="auto" w:w="0"/> and not <w:tcW w:type="dxa" w:w="13606"/> (for example)
@SebastienGutierrez did you find a way around this perhaps or did you set table widths manually? Apologies for commenting on such an old post, however, I'm working on a project and this functionality would make it much easier.
Thank you in advance :)
yes I iterate and fix widths manually
Okay, thank you for the quick reply. I am doing the same as I can't find another way to accomplish this. Thank you again.
What XML do you get for the table object in question after setting autofit True?
tbl = table._tbl
print(tbl.xml)
I think you'll find this is a limitation on how Word behaves rather than the XML not being to spec.
If I remember correctly, autofit only comes into things when you're adjusting the columns with the UI. Word still records the actual width it ended up with in the XML and doesn't recalculate it when the document is loaded.
Might be worth some investigation though. If there's a way to improve the behavior I'd be keen to know about it and get it into an enhancement request.
Hi,
Word's autofit is triggered when the document is opened ;-)
You can do this single test :
create a new document with a signe table with some content, change its property to "autofit", save the doc.
unzip the doc, modify document.xml in subdirectory "word" -> find an existing cell with some content, add a bigger string.
zip again the whole directory with a .docx name
open it again in Word and Tada !
;-)
How does the XML compare between what works in Word and what doesn't in python-docx?
@scanny the difference in the XML is
```XML
@SebastienGutierrez is absolutely right, I created a small script to create a .docx-file demonstrating the problem for tables with and without autofit.
- **Whitespaces contribute to the problem and have to be included in test cases when trying to fix the problem**.
- The expected *autofit-behaviour* is achieved by replacing type="dxa"'with 'type="auto" in word/document.xml
- `table.autofit =False` allways works as expected
Obviously this is not a proper solution, since there are several other occurences of 'dxa' in the code, thus replacing might destroy files other than my very simple test case (I have tried some other files without any problems).
I think CT_tbl._tcs_xml() in table.py has to be adjusted, but I just couldn't figure out how all the classes work together.
```python
from docx import Document
from zipfile import ZipFile
document_file = 'AutofitTest.docx'
fixed_document_file = 'AutofitTest_fixed.docx'
doc = Document()
for autofit in [True, False]:
doc.add_heading('Table with autofit = ' + str(autofit), 1)
for text in ['NoWhiteSpaces', ' whitespaces ']:
doc.add_heading('Test table: ' + text, 2)
table = doc.add_table(2,2)
table.autofit = autofit
for row in table.rows:
for cell, cell_text in zip(row.cells, ['A', 5 * text]):
cell.text = cell_text
doc.add_paragraph()
doc.save(document_file)
# Replacing type="dxa"'with 'type="auto" in word/document.xml
with ZipFile(document_file, 'r') as myzip:
with ZipFile(fixed_document_file, 'w') as myzip_out:
for f in myzip.namelist():
data = myzip.read(f)
if f == 'word/document.xml':
data = data.replace(b'type="dxa"', b'type="auto"')
myzip_out.writestr(f, data)
The cells in a column can be set to have w:type="auto" using this code:
for cell in column.cells:
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
tcW = tcPr.get_or_add_tcW()
tcW.type = 'auto'
If you're willing to depend on the w:tcPr and w:tcW elements already being there, it can be shortened to:
for cell in column.cells:
cell._tc.tcPr.tcW.type = 'auto'
If someone has a proposal for when that should be done automatically, I'm willing to consider it, just clearly state the behavior you propose.
@Schleehauf can you elaborate on what you mean by "whitespace contributes to the problem"?
@scanny when you look at the 'AutofitTest.docx' file created by the code I posted above, you will notice, that the colums containing NoWhiteSpaces are autofitted correctly. Only when you insert text with whitespaces (and maybe other magical characters?) autofit in the current version does not have an effect.
I will have a look at the solution you posted over the weekend. Thanks!
Hi,
I am generating my docs using pandoc from Markdown and then using python-docx to apply/fixup some formatting. I am not getting autofit to work correctly and this is the XML for
If I go in and manually edit the
The tables sort themselves out wen the doc is opened. Is there an easy way that i can use the python-docx module to change just this element?
Or even is it possible using OxmlElement to edit an element?
Thanks!
Here is a snippet to the autofit works. It load every tables and set tblW and cells width to type auto.
Any idea how to implement it to the library core library? Adding a tblW children to tblPr and update the autofit setter?
def set_autofit(doc: Document) -> Document:
"""
Hotfix for autofit.
"""
for t_idx, table in enumerate(doc.tables):
doc.tables[t_idx].autofit = True
doc.tables[t_idx].allow_autofit = True
doc.tables[t_idx]._tblPr.xpath("./w:tblW")[0].attrib["{http://schemas.openxmlformats.org/wordprocessingml/2006/main}type"] = "auto"
for row_idx, r_val in enumerate(doc.tables[t_idx].rows):
for cell_idx, c_val in enumerate(doc.tables[t_idx].rows[row_idx].cells):
doc.tables[t_idx].rows[row_idx].cells[cell_idx]._tc.tcPr.tcW.type = 'auto'
doc.tables[t_idx].rows[row_idx].cells[cell_idx]._tc.tcPr.tcW.w = 0
return doc
Most helpful comment
Here is a snippet to the autofit works. It load every tables and set tblW and cells width to type auto.
Any idea how to implement it to the library core library? Adding a tblW children to tblPr and update the autofit setter?