Block-based Word document builder with simple, predictable newline and inline text handling.
Project description
DocxBlocks
A Python library for building Word documents using a block-based API. Create complex documents with simple, readable code.
🚀 Quick Start
from docxblocks import DocxBuilder
# Create blocks
blocks = [
{"type": "heading", "text": "Report Title", "level": 1},
{"type": "text", "text": "This is the first paragraph."},
{"type": "text", "text": "This continues inline."},
{"type": "text", "text": "\nThis starts a new paragraph."},
{"type": "table", "content": {
"headers": ["Name", "Value"],
"rows": [["Item 1", "100"], ["Item 2", "200"]]
}}
]
# Build document
builder = DocxBuilder("template.docx")
builder.insert("{{content}}", blocks)
builder.save("output.docx")
📋 Features
- Block-based API: Each piece of content is a simple dictionary
- Smart text grouping: Consecutive text blocks are grouped inline
- Simple newlines: Every
\ncreates a new paragraph - Rich styling: Bold, italic, colors, alignment, and more
- Table support: Headers, rows, column widths, cell styling
- Image handling: Automatic sizing with DPI calculation
- Template support: Use existing Word templates as starting points
- Error handling: Graceful fallbacks for missing content
📖 Installation
pip install docxblocks
🎯 Basic Usage
Template Setup
Create a Word document with placeholders:
{{header}}
{{main}}
{{footer}}
Block-Based API (Core Concept)
Each piece of content is a block:
{
"type": "text",
"text": "All systems operational.",
"style": {
"bold": True,
"italic": False,
"font_color": "007700",
"align": "center",
"style": "Normal"
}
}
Text Block Behavior
Text blocks have simple, predictable behavior:
- Every
\n: Always starts a new paragraph - Inline grouping: Consecutive text blocks without
\nare grouped together spacing: Adds extra blank paragraphs after the block
{"type": "text", "text": "Line 1\nLine 2\nLine 3"}
# Renders as three paragraphs: Line 1, Line 2, Line 3
{"type": "text", "text": "First paragraph\n\nSecond paragraph"}
# Renders as: First paragraph, [blank paragraph], Second paragraph
{"type": "text", "text": "First", "spacing": 1}
# Renders as a new paragraph, then one blank paragraph after
Table Cell Behavior
Table cells and headers follow the same rules:
- Every
\n: Always starts a new paragraph within the cell - Inline grouping: Consecutive cell blocks without
\nare grouped together
{
"type": "table",
"content": {
"headers": ["Name", "Description\nDetails"],
"rows": [
["Item 1", "First paragraph.\nSecond paragraph."],
["Item 2", "Line 1\n\nLine 2 with empty line above"]
]
}
}
# Each '\n' creates a new paragraph, each '\n\n' creates paragraph with empty line before
Block types:
| Type | Required Keys | Optional Keys |
|---|---|---|
text |
text |
style, spacing |
heading |
text, level |
style |
bullets |
items |
style |
table |
content |
style |
image |
path |
style |
page_break |
- | - |
header |
content |
apply_to |
footer |
content |
apply_to |
🎨 Styling
Text Styling
{
"type": "text",
"text": "Styled text",
"style": {
"bold": True,
"italic": False,
"font_color": "FF0000", # Red
"align": "center", # "left", "center", "right", "justify"
"style": "Normal"
}
}
Alignment Options
All block types support four alignment options:
# Text alignment examples
{"type": "text", "text": "Left aligned", "style": {"align": "left"}}
{"type": "text", "text": "Centered text", "style": {"align": "center"}}
{"type": "text", "text": "Right aligned", "style": {"align": "right"}}
{"type": "text", "text": "Justified text that adjusts spacing for clean edges", "style": {"align": "justify"}}
# Works with all block types
{"type": "heading", "text": "Centered Heading", "level": 1, "style": {"align": "center"}}
{"type": "bullets", "items": ["Item 1", "Item 2"], "style": {"align": "right"}}
Table Styling
{
"type": "table",
"content": {"headers": ["A", "B"], "rows": [["1", "2"]]},
"style": {
"column_widths": [0.3, 0.7],
"header_styles": {"bold": True, "bg_color": "f2f2f2"},
"column_styles": {0: {"font_color": "FF0000"}}
}
}
Image Styling
{
"type": "image",
"path": "logo.png",
"style": {
"max_width": "4in",
"max_height": "300px"
}
}
📄 Headers and Footers
DocxBlocks supports customizable headers and footers that can contain any combination of supported block types.
Basic Headers and Footers
blocks = [
# Header for all pages
{
"type": "header",
"apply_to": "all",
"content": [
{
"type": "text",
"text": "Company Name\tDocument Title\tPage {{page}}",
"style": {"align": "center", "font_color": "666666"}
}
]
},
# Footer for all pages
{
"type": "footer",
"apply_to": "all",
"content": [
{
"type": "text",
"text": "© 2024 Company. All rights reserved.",
"style": {"align": "center", "italic": True}
}
]
},
# Your main content...
{"type": "heading", "text": "Report Title", "level": 1}
]
Page-Specific Headers and Footers
Control which pages display specific headers and footers:
blocks = [
# Special header for first page only
{
"type": "header",
"apply_to": "first",
"content": [
{
"type": "text",
"text": "CONFIDENTIAL REPORT",
"style": {"align": "center", "bold": True}
}
]
},
# Different headers for odd/even pages (useful for books)
{
"type": "header",
"apply_to": "odd",
"content": [
{
"type": "text",
"text": "Chapter Title\t\tPage {{page}}",
"style": {"align": "left"}
}
]
},
{
"type": "header",
"apply_to": "even",
"content": [
{
"type": "text",
"text": "Page {{page}}\t\tBook Title",
"style": {"align": "right"}
}
]
}
]
Complex Header/Footer Content
Headers and footers can contain any block type:
{
"type": "header",
"apply_to": "all",
"content": [
# Table in header
{
"type": "table",
"content": {
"headers": ["Company", "Document", "Date"],
"rows": [["ACME Corp", "Annual Report", "2024"]]
},
"style": {"column_widths": [0.3, 0.4, 0.3]}
},
# Image in header
{
"type": "image",
"path": "logo.png",
"style": {"max_height": "0.5in"}
}
]
}
Apply To Options
| Option | Description |
|---|---|
"all" |
Apply to all pages (default) |
"all_except_first" |
Apply to all pages except the first (great for cover pages) |
"first" |
Apply only to the first page |
"odd" |
Apply to odd-numbered pages |
"even" |
Apply to even-numbered pages |
Note: Using "odd" or "even" automatically enables different odd/even headers throughout the document.
Cover Page Example
Perfect for reports with clean cover pages:
blocks = [
{
"type": "header",
"apply_to": "all_except_first",
"content": [
{
"type": "text",
"text": "Company Report\tConfidential\tPage {{page}}",
"style": {"align": "center"}
}
]
},
# Page 1: Clean cover page (no header/footer)
{"type": "heading", "text": "ANNUAL REPORT 2024", "level": 1, "style": {"align": "center"}},
{"type": "page_break"},
# Page 2+: Content with headers/footers
{"type": "heading", "text": "Executive Summary", "level": 1}
]
🔧 Advanced Features
Mixed Content
blocks = [
{"type": "heading", "text": "Section 1", "level": 2},
{"type": "text", "text": "Introduction "},
{"type": "text", "text": "with ", "style": {"bold": True}},
{"type": "text", "text": "inline styling."},
{"type": "bullets", "items": ["Point 1", "Point 2"]},
{"type": "table", "content": {...}},
{"type": "page_break"},
{"type": "heading", "text": "Section 2", "level": 2}
]
Template Variables
# Template.docx contains: "Hello {{name}}, here is your {{report_type}} report."
builder = DocxBuilder("template.docx")
builder.insert("{{name}}", [{"type": "text", "text": "John"}])
builder.insert("{{report_type}}", [{"type": "text", "text": "monthly"}])
builder.save("output.docx")
📚 Examples
See the examples/ directory for complete working examples:
text_block_example.py- Basic text blocks and stylingtable_block_example.py- Table creation and stylingheader_footer_example.py- Headers and footers with various configurationsall_except_first_example.py- Cover page example with clean first page and headers on content pagesnewline_example.py- Newline handling and paragraph behaviorinline_text_example.py- Inline text groupingalignment_example.py- Text alignment with left, center, right, and justifycombined_example.py- Mixed block types
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
📄 License
MIT License - see LICENSE file for details.
🐛 Issues
Found a bug? Have a feature request? Please open an issue on GitHub.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file docxblocks-1.5.1.tar.gz.
File metadata
- Download URL: docxblocks-1.5.1.tar.gz
- Upload date:
- Size: 28.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ab21e310c98206fdecb84cd733d01579e03233949a38a715105abe239c7d8dc
|
|
| MD5 |
e1ed3af95ab2e34b0ae413a2012abc9e
|
|
| BLAKE2b-256 |
4fa4d80b16d6558e8ff1ce260f1088df389e74d4dcce3714a738fd990e7bf5fc
|
Provenance
The following attestation bundles were made for docxblocks-1.5.1.tar.gz:
Publisher:
release.yml on frank-895/docxblocks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
docxblocks-1.5.1.tar.gz -
Subject digest:
8ab21e310c98206fdecb84cd733d01579e03233949a38a715105abe239c7d8dc - Sigstore transparency entry: 253222054
- Sigstore integration time:
-
Permalink:
frank-895/docxblocks@07a8fd81aa8e5bd4f953032ceca918789868a33f -
Branch / Tag:
refs/tags/v1.5.1 - Owner: https://github.com/frank-895
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@07a8fd81aa8e5bd4f953032ceca918789868a33f -
Trigger Event:
push
-
Statement type:
File details
Details for the file docxblocks-1.5.1-py3-none-any.whl.
File metadata
- Download URL: docxblocks-1.5.1-py3-none-any.whl
- Upload date:
- Size: 24.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a91b21663d94faa65ff440101840fc7315a9cfb7ef1faca5940f5f4325792284
|
|
| MD5 |
3e0a139bd9d13e087b568b19ced1bc17
|
|
| BLAKE2b-256 |
f282e28ecac1f28dce8d6c07503aabea42f05fe67cb987d02c0f21faa3b86cf8
|
Provenance
The following attestation bundles were made for docxblocks-1.5.1-py3-none-any.whl:
Publisher:
release.yml on frank-895/docxblocks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
docxblocks-1.5.1-py3-none-any.whl -
Subject digest:
a91b21663d94faa65ff440101840fc7315a9cfb7ef1faca5940f5f4325792284 - Sigstore transparency entry: 253222060
- Sigstore integration time:
-
Permalink:
frank-895/docxblocks@07a8fd81aa8e5bd4f953032ceca918789868a33f -
Branch / Tag:
refs/tags/v1.5.1 - Owner: https://github.com/frank-895
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@07a8fd81aa8e5bd4f953032ceca918789868a33f -
Trigger Event:
push
-
Statement type: