Fill Word document templates using YAML configs with a powerful expression language, built-in functions, and SQLite integration.
Project description
📄 DocumentPlaceholder
Automatically fill Word templates using YAML configs, expressions, and SQL.
Generate invoices, reports, statements, and any other documents with a single command.
Features • Installation • Quick Start • Configuration • Functions • GUI
🚀 Features
DocumentPlaceholder turns .docx templates into ready-to-use documents based on YAML configs with a powerful expression language.
- 📝 Word templates — placeholders like
{KEY}in text, tables, and headers/footers. - ⚡ Expression language — arithmetic, comparisons, nested function calls, and template strings.
- 🛢 SQLite out of the box — run database queries directly inside configs for counters, lookups, and client data.
- 📅 59 built-in functions — date/time, strings, math, logic, and conditions.
- 📤 PDF export — automatic conversion through LibreOffice.
- 🖥 GUI with syntax highlighting — config editor, live preview, SQL manager.
- 🔌 Extensible — add your own functions with a single decorator.
📦 Installation
pip install document-placeholder
Optional extras:
| Extra | Includes |
|---|---|
document-placeholder[gui] |
GUI interface (CustomTkinter) |
document-placeholder[dev] |
Development tools (pytest) |
document-placeholder[all] |
Everything |
⚡ Quick Start
1. Create a Word template (template.docx)
Insert placeholders into the document:
Invoice #{INVOICE_NUM}
Date: {DAY_NUM}.{MONTH_STR}.{YEAR_NUM}
Amount: ${PRICE}
{DESCRIPTION}
2. Write a config (template.yaml)
ON_START:
- SQL('CREATE TABLE IF NOT EXISTS doc (num INTEGER DEFAULT 0)')
- SQL('INSERT OR IGNORE INTO doc (rowid, num) VALUES (1, 0)')
INVOICE_NUM:
SQL('SELECT num FROM doc WHERE rowid = 1') + 1
MONTH_STR:
CURRENT_DATE_STR(month)
DAY_NUM:
CURRENT_DATE_NUM(day)
YEAR_NUM:
CURRENT_DATE_NUM(year)
PRICE:
500
DESCRIPTION:
"Software Development Services
(Period: {CURRENT_DATE_NUM(day, month, year) - DAYS(7)} — {CURRENT_DATE_NUM(day, month, year)})"
OUTPUT_NAME:
"Invoice-{INVOICE_NUM}"
OUTPUT_FORMAT:
- docx
- pdf
ON_END:
SQL('UPDATE doc SET num = num + 1 WHERE rowid = 1')
3. Run
docplaceholder -c template.yaml -t template.docx
INVOICE_NUM = 2026-2-5
MONTH_STR = February
DAY_NUM = 16
YEAR_NUM = 2026
PRICE = 500
DESCRIPTION = Software Development Services (Period: 09.02.2026 — 16.02.2026)
Output: Invoice-2026-2-5 [docx, pdf]
-> Invoice-2026-2-5.docx
-> Invoice-2026-2-5.pdf
🎨 Expression Language
A config is not just key-value mapping. Every value is an expression that gets evaluated.
Arithmetic and comparisons
TAX: ROUND(PRICE * 0.2, 2)
TOTAL: PRICE + TAX
IS_PREMIUM: TOTAL > 1000
Template strings
Inside "...", expressions like {expr} are interpolated into the final string:
PERIOD: "{CURRENT_DATE_NUM(day, month, year) - DAYS(30)} — {CURRENT_DATE_NUM(day, month, year)}"
Nested calls
INVOICE_NUM:
"{CURRENT_DATE_NUM(year)}-{SQL('SELECT num FROM doc WHERE rowid = 1') + 1}"
Conditional logic
STATUS: IF(TOTAL > 1000, 'Premium', 'Standard')
DISCOUNT: IF(TOTAL >= 500, TOTAL * 0.1, 0)
LABEL: SWITCH(STATUS, 'Premium', '⭐ Premium', 'Standard', '📋 Standard')
Supported operators: + - * / % > < >= <= == != ()
⚙️ Configuration
CLI arguments
docplaceholder [-c CONFIG] [-t TEMPLATE] [-o OUTPUT] [--db DATABASE]
| Argument | Default | Description |
|---|---|---|
-c, --config |
template.yaml |
Path to YAML config |
-t, --template |
template.docx |
Path to Word template |
-o, --output |
output.docx |
Path to output file |
--db |
data.db |
Path to SQLite database |
-V, --version |
Print program version |
Special YAML keys
| Key | Description |
|---|---|
ON_START |
Expressions executed before processing (table creation, initialization) |
ON_END |
Expressions executed after processing (increment counters, cleanup) |
OUTPUT_NAME |
Output filename template: "Invoice-{INVOICE_NUM}" |
OUTPUT_FORMAT |
List of output formats: [docx, pdf] |
All other keys are treated as placeholders and replaced in the document.
🧰 Built-in Functions
59 functions in 5 categories. Full reference: FUNCTIONS.md
📅 Date and time
TODAY: TODAY() # 16.02.2026
YEAR: CURRENT_DATE_NUM(year) # 2026
MONTH: CURRENT_DATE_STR(month) # February
CUSTOM: DATE_FORMAT(DATE(2026, 3, 8), '%d %B %Y') # 08 March 2026
WEEK_AGO: "{TODAY() - DAYS(7)}" # 09.02.2026
DIFF: DAYS_BETWEEN(DATE(2026, 1, 1), TODAY()) # 46
🔤 Strings
UPPER('hello') # HELLO
TITLE('john doe') # John Doe
PAD_LEFT('42', 6, '0') # 000042
JOIN(', ', 'a', 'b', 'c') # a, b, c
REPLACE('foo bar', 'bar', 'baz') # foo baz
SPLIT('user@mail.com', '@', 1) # mail.com
🔢 Math
ROUND(19.956, 2) # 19.96
FORMAT_NUM(1234567, 2) # 1,234,567.00
MIN(3, 1, 4, 1, 5) # 1
AVG(10, 20, 30) # 20.0
SQRT(144) # 12.0
🧠 Logic
IF(PRICE > 1000, 'expensive', 'cheap')
COALESCE(SQL('SELECT name FROM clients'), 'Unknown')
DEFAULT(value, 'N/A')
SWITCH(status, 'draft', 'Draft', 'sent', 'Sent', 'Unknown')
🛢 SQL
SQL('SELECT count(*) FROM orders WHERE user_id = 1')
SQL('INSERT INTO log (event) VALUES ("generated")')
🖥 Graphical Interface
pip install document-placeholder[gui]
docplaceholder-gui
The GUI includes:
- Config editor with YAML and custom syntax highlighting (
SQL(...),{expressions}) - Live preview of evaluated values
- SQL manager for running queries and viewing tables/schema
- Keyboard shortcuts —
Ctrl+Ssave,Ctrl+Fsearch,F5refresh
🔌 Extending Functions
Add a custom function with a single decorator:
from document_placeholder.functions import FunctionRegistry
@FunctionRegistry.register("MY_FUNC")
def my_func(arg1, arg2):
"""Your custom logic."""
return f"{arg1}-{arg2}"
After importing the module, the function becomes available in config expressions:
VALUE: MY_FUNC('hello', 'world') # hello-world
📁 Library Usage
from document_placeholder.config import Config
from document_placeholder.evaluator import Evaluator
from document_placeholder.processor import DocumentProcessor
config = Config.from_string("""
NAME: UPPER('john doe')
DATE: TODAY()
""")
evaluator = Evaluator()
values = {k: evaluator.evaluate_value(v) for k, v in config.placeholders.items()}
# {'NAME': 'JOHN DOE', 'DATE': DateValue(2026-02-16)}
processor = DocumentProcessor("template.docx")
processor.replace_placeholders(values)
processor.save("output.docx")
🧪 Testing
pip install document-placeholder[dev]
pytest
295 passed in 0.36s
🤝 Contributing
- Fork the repository
- Create a feature branch
- Commit your changes
- Open a Pull Request
Bugs and feature requests → Issues
📄 License
This project is released under the MIT license. See LICENSE for details.
Developed with ❤️ by FlacSy
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 document_placeholder-1.1.0.tar.gz.
File metadata
- Download URL: document_placeholder-1.1.0.tar.gz
- Upload date:
- Size: 53.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
affc1e099a46a5126834f87dfc5525231184262394cff392f6825ee8a6048c3c
|
|
| MD5 |
87348fc8e129c202a92b2d1a929b6654
|
|
| BLAKE2b-256 |
e5d6c80a7366b7ca9e9009705ad080eb2caf372f554710d6bb3bedd2608382c4
|
Provenance
The following attestation bundles were made for document_placeholder-1.1.0.tar.gz:
Publisher:
release.yml on FlacSy/DocumentPlaceholder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
document_placeholder-1.1.0.tar.gz -
Subject digest:
affc1e099a46a5126834f87dfc5525231184262394cff392f6825ee8a6048c3c - Sigstore transparency entry: 1020494214
- Sigstore integration time:
-
Permalink:
FlacSy/DocumentPlaceholder@e0243f3ae35b1474e7d76890734df9019fdcbc34 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/FlacSy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e0243f3ae35b1474e7d76890734df9019fdcbc34 -
Trigger Event:
release
-
Statement type:
File details
Details for the file document_placeholder-1.1.0-py3-none-any.whl.
File metadata
- Download URL: document_placeholder-1.1.0-py3-none-any.whl
- Upload date:
- Size: 32.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb2d9ea93af49167c9ec9b735f62146d870fd9510ab7d9949af6710f9915fce5
|
|
| MD5 |
4143cfc2afb9346bdfec4f4aee18c981
|
|
| BLAKE2b-256 |
4782051c791661c5710113b066fdf7abfa78174d512de08b5a68059605760340
|
Provenance
The following attestation bundles were made for document_placeholder-1.1.0-py3-none-any.whl:
Publisher:
release.yml on FlacSy/DocumentPlaceholder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
document_placeholder-1.1.0-py3-none-any.whl -
Subject digest:
fb2d9ea93af49167c9ec9b735f62146d870fd9510ab7d9949af6710f9915fce5 - Sigstore transparency entry: 1020494257
- Sigstore integration time:
-
Permalink:
FlacSy/DocumentPlaceholder@e0243f3ae35b1474e7d76890734df9019fdcbc34 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/FlacSy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e0243f3ae35b1474e7d76890734df9019fdcbc34 -
Trigger Event:
release
-
Statement type: