agentsclimarketplace

Run2 python docx split placeholders

Skill cxcscmu/SkillLearnBench/skills/b2-self-feedback-claude-opus-4-6/offer-letter-generator/run2_python-docx-split-placeholders

[COLM'26] SkillLearnBench is the first benchmark for evaluating continual learning methods that automatically generate agent skills.

Install
npx -y skills add cxcscmu/SkillLearnBench --skill run2_python-docx-split-placeholders

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Robust python-docx template filling that handles split runs, conditional sections, nested tables, headers, and footers.

SKILL.md

3.3 KB, as published. Nobody here has run it

Robust python-docx Template Filling

Core Problem

python-docx stores paragraph text in "runs" (spans with uniform formatting). Placeholders like {{COMPANY_NAME}} often get split across runs (e.g., ['{{COMP', 'ANY_NAME}}']), making naive per-run replacement fail.

Recommended Approach

1. Paragraph-level replacement function

import re

def replace_in_paragraph(para, replacements, keep_relocation=True):
    full_text = ''.join(run.text for run in para.runs)
    if not full_text:
        return

    # Handle conditional blocks BEFORE placeholder substitution
    if '{{IF_RELOCATION}}' in full_text:
        if keep_relocation:
            full_text = full_text.replace('{{IF_RELOCATION}}', '')
            full_text = full_text.replace('{{END_IF_RELOCATION}}', '')
        else:
            full_text = re.sub(
                r'\{\{IF_RELOCATION\}\}.*?\{\{END_IF_RELOCATION\}\}',
                '', full_text, flags=re.DOTALL
            )

    for placeholder, value in replacements.items():
        full_text = full_text.replace(placeholder, value)

    # Preserve first run's formatting, clear others
    if para.runs:
        para.runs[0].text = full_text
        for run in para.runs[1:]:
            run.text = ''

2. Process ALL text locations in the document

Locations that can contain placeholders:

  • Body paragraphs: doc.paragraphs
  • Headers/Footers: section.header.paragraphs, section.footer.paragraphs
  • Table cells: table.rows[i].cells[j].paragraphs
  • Nested tables: cells can contain sub-tables (recurse!)
def process_table(table, replacements, keep_relocation):
    for row in table.rows:
        for cell in row.cells:
            for para in cell.paragraphs:
                replace_in_paragraph(para, replacements, keep_relocation)
            for nested in cell.tables:
                process_table(nested, replacements, keep_relocation)

3. Conditional sections spanning multiple paragraphs

If {{IF_RELOCATION}} and {{END_IF_RELOCATION}} are in separate paragraphs (not same paragraph), you need a multi-paragraph approach: find the start/end paragraph indices and either remove content between them or just strip the markers. In this template they're in the same paragraph, but for robustness consider both cases.

4. Formatting note

Putting all text in runs[0] loses formatting differences between runs (e.g., bold words within a sentence). For templates where each paragraph has uniform formatting, this is fine. For mixed-formatting paragraphs, a more sophisticated approach is needed: walk through runs tracking character positions and only modify runs that contain placeholder characters.

Quick Reference

from docx import Document
import json, re

with open('data.json') as f:
    data = json.load(f)

doc = Document('template.docx')
replacements = {f'{{{{{k}}}}}': v for k, v in data.items()}
keep_reloc = data.get('RELOCATION_PACKAGE') == 'Yes'
# Remove non-placeholder keys from replacements
for key in ['{{RELOCATION_PACKAGE}}']:
    replacements.pop(key, None)

# Process body, headers, footers, tables (including nested)

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.