Logan's Analytics Bootcamp
Dashboard β€Ί Phase 4: Python for Report Automation
M4.5

Word Documents with python-docx

⏱ 6 hoursπŸ“… Weeks 24–25❓ 4 quiz questions
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 optionally docxtpl). 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.docx in 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

⬇ Practice data for this module
D2 milestonesMilestones (~150 rows)CSVXLSX
D3 evm_monthlyMonthly EVM by control account (~2,000 rows)CSVXLSX
D4 contractsContracts (30 rows)CSVXLSX
D7 risksRisk register (80 rows)CSVXLSX

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).

  1. Create a Word template with styles and a header/footer containing "FICTIONAL TRAINING DATA".
  2. 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.
  3. 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.

Q4.5.1
What's the difference between a paragraph and a run in python-docx?
Write at least a few words to unlock.
Q4.5.2
Why might replacing {{PROGRAM}} run by run fail?
Write at least a few words to unlock.
Q4.5.3
Why start from a Word template instead of Document()?
Write at least a few words to unlock.
Q4.5.4
How do you add a chart to a Word report with Python?
Write at least a few words to unlock.