Word Documents with python-docx
Phase 4 goal
Write Python that reads messy program data, transforms it with pandas, and generates finished Excel and Word deliverables (the same kind of document automation your coworker builds), reliably and repeatably.
Environment note: Use your organization's approved Python distribution if one exists. Some environments require specific installers, package mirrors, or a pre-approved package list. Packages used:
pandas,openpyxl,python-docx,matplotlib(and optionallydocxtpl). Work only with the fictional dataset while learning.
π― Learning objectives
Tick each one when you can actually do it.
π‘ Key concepts
- Object model:
Documentβ paragraphs β runs (text with the same formatting) and tables β rows β cells. Sections hold headers and footers.from docx import Document from docx.shared import Inches, Pt doc = Document("Status_Report_TEMPLATE.docx") # uses the template's styles doc.add_heading("PRG-002 IRONWOOD Tactical Network: Monthly Status", level=1) p = doc.add_paragraph("Overall cost performance is ") p.add_run("AMBER").bold = True p.add_run(f" (CPI {cpi:.2f}).") table = doc.add_table(rows=1, cols=4) table.style = "Table Grid" # the style must exist in the template for cell, text in zip(table.rows[0].cells, ["Milestone", "Baseline", "Forecast", "Slip (days)"]): cell.text = text for m in late_milestones.itertuples(): row = table.add_row().cells row[0].text, row[1].text, row[2].text, row[3].text = m.MilestoneName, f"{m.BaselineDate:%d %b %Y}", f"{m.ForecastDate:%d %b %Y}", str(m.SlipDays) doc.add_picture("scurve_PRG-002.png", width=Inches(6)) doc.save("PRG-002_Status_2026-09.docx") - Styles come from the template: Build
Status_Report_TEMPLATE.docxin Word with your organization's fonts, heading styles, table styles, header/footer, and portion-marking/banner placeholders as required by your organization's marking guidance. (Use only fictional or unclassified training markings in practice.) - Placeholder replacement gotcha: Word often splits
{{PROGRAM_NAME}}across several runs, so a simple run-level replace misses it. Solutions: type placeholders in one go and clear formatting, replace at paragraph level (then rebuild runs), or use the docxtpl library (Jinja2 templates for docx, built on python-docx). - Cell shading and advanced formatting: Some features (cell background color) need low-level XML (
docx.oxml). Write a small helper function once and reuse it. - Narrative generation from data: rule-based text, e.g.
"CPI declined from 0.96 to 0.91 over 3 months, driven by WBS 1.3 (Hull Integration)."
π Hands-on exercise: One-Program Status Report
Data: EVM snapshot (4.3), milestones (MilestoneName, BaselineDate, ForecastDate, ActualDate, SlipDays, Status), risks (Title, Likelihood, Consequence, Status, Owner), contracts (ContractNumber, Vendor, ContractType, CeilingValue, ObligatedToDate, PoPEnd).
- Create a Word template with styles and a header/footer containing "FICTIONAL TRAINING DATA".
- Generate a document for PRG-002 with: title, "Data as of" line, an executive summary paragraph (rule-based RAG text), an EVM metrics table, an S-curve image (matplotlib β PNG β
add_picture), a late milestones table, top 5 risks, and contract status. - Add page numbers in the footer (python-docx needs a field-code XML snippet. Find it in the docs/community examples and wrap it in a helper.)
π¦ Mini-project: Placeholder Engine
Write fill_template(doc_path, mapping: dict, out_path) that replaces {{KEY}} placeholders across body paragraphs, tables, headers, and footers, including placeholders split across runs. Test it with a template containing 10 placeholders. (Then compare with doing the same in docxtpl and write a short note on when you'd use each.)
π§ Self-check quiz
Answer in your own words, then check. Grade yourself honestly; your score is saved.
{{PROGRAM}} run by run fail?Document()?doc.add_picture(path, width=Inches(6)).