Basics
from docx import Document
doc = Document()
doc.add_heading("Weekly Report", level=1)
doc.add_paragraph("This report was generated automatically.")
table = doc.add_table(rows=1, cols=2)
hdr = table.rows[0].cells
hdr[0].text = "Item"
hdr[1].text = "Value"
for item, value in [("Users", "120"), ("Errors", "3")]:
row_cells = table.add_row().cells
row_cells[0].text = item
row_cells[1].text = value
doc.save("report.docx")Tips
- start from a template .docx for complex formatting
- docx is not the same as PDF (convert separately if needed)
Visualize it
Generating a Word document means turning raw data into structured content and saving it to disk.
flowchart LR
A["Read data (list or spreadsheet)"] --> B["Build document (headings, paragraphs, tables)"]
B --> C["Save as .docx file"]
How python-docx models a document
A .docx file is a zip of XML. python-docx hides the XML behind objects that match how you think about a document.
- A Document holds a list of body elements.
- A paragraph holds runs. A run is a stretch of text with one style, such as bold or a font size.
- A table holds rows, and rows hold cells. Each cell holds paragraphs.
Install it with pip install python-docx, but import it as docx. The names differ, which trips up many beginners. Installing a package called docx gives you a different, broken library.
Formatting text
add_paragraph returns the paragraph, and add_run lets you style parts of it.
from docx import Document
from docx.shared import Pt, RGBColor
doc = Document()
doc.add_heading("Weekly Report", level=1)
p = doc.add_paragraph("Status: ")
run = p.add_run("on track")
run.bold = True
run.font.size = Pt(12)
run.font.color.rgb = RGBColor(0x1B, 0x7F, 0x3B)
doc.add_paragraph("First point", style="List Bullet")
doc.add_paragraph("Second point", style="List Bullet")
table = doc.add_table(rows=1, cols=2)
table.style = "Table Grid"
table.rows[0].cells[0].text = "Item"
table.rows[0].cells[1].text = "Value"
doc.save("formatted.docx")Built-in style names such as "List Bullet" and "Table Grid" exist in the default template. If you use a name that is not in the template you get a KeyError.
Filling a template
For letters, invoices, and contracts, do not build the layout in code. Design the document in Word, with the fonts, logo, and margins you want, and put markers like {{name}} in the text. Open it with Document("template.docx"), loop over doc.paragraphs, and replace the markers. One catch: Word may split a marker across several runs (for example if you edited part of it), so a replace on run.text can miss it. Type the marker in one go and check the result.
Common mistakes
- Installing the wrong package. Use
python-docx. - Overwriting the source file. Save to a new name until you trust the script.
- Expecting PDF output.
python-docxwrites.docxonly. To get a PDF, open the file with Word or LibreOffice and export it. - Setting
cell.texton merged cells without checking. Merged cells share content. - Reading a
.doc(old format) file. Only.docxis supported.
Adapting it
Loop over rows from a CSV to create one document per customer, or one document with a table of everything. Save with a timestamp in the name, then attach the file to an email (see the communication phase).
Check your understanding
Which command installs the library that you import as docx?
The package is python-docx but the module is docx. The package named docx on PyPI is a different, unrelated project.
Show answer
B — pip install python-docx — The package is python-docx but the module is docx. The package named docx on PyPI is a different, unrelated project.
You want one word in a paragraph to be bold. What do you use?
Character formatting belongs to runs. Split the paragraph text into runs and set bold on the one you want.
Show answer
A — A separate run with run.bold = True — Character formatting belongs to runs. Split the paragraph text into runs and set bold on the one you want.
You need a polished invoice layout. What is the most maintainable approach?
Layout is easier to design in Word than in code. Python then only replaces markers or fills tables, so a designer can change the look without touching the script.
Show answer
B — Design a template in Word, then fill in the values from Python — Layout is easier to design in Word than in code. Python then only replaces markers or fills tables, so a designer can change the look without touching the script.