Skip to main content

📄 DocumentPlaceholder

Automatically fill Word templates using YAML configs, expressions, and SQL.

Generate invoices, reports, statements, and any other documents with a single command.

PyPI Version Python Versions License Tests

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+S save, Ctrl+F search, F5 refresh

🔌 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

  1. Fork the repository
  2. Create a feature branch
  3. Commit your changes
  4. 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

Metadata

Release files for document-placeholder 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for document-placeholder 1.1.0
File Size Uploaded
document_placeholder-1.1.0.tar.gz 53.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for document-placeholder 1.1.0
File Interpreter ABI Platform
document_placeholder-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 86.0 kB

Release files / document_placeholder-1.1.0.tar.gz

Download URL document_placeholder-1.1.0.tar.gz
Size 53.7 kB
Tags Source
SHA-256 checksum
How to use checksums
affc1e099a46a5126834f87dfc5525231184262394cff392f6825ee8a6048c3c
BLAKE2b-256 checksum
How to use checksums
e5d6c80a7366b7ca9e9009705ad080eb2caf372f554710d6bb3bedd2608382c4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 3, 2026.

Transparency log

Release files / document_placeholder-1.1.0-py3-none-any.whl

Download URL document_placeholder-1.1.0-py3-none-any.whl
Size 32.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fb2d9ea93af49167c9ec9b735f62146d870fd9510ab7d9949af6710f9915fce5
BLAKE2b-256 checksum
How to use checksums
4782051c791661c5710113b066fdf7abfa78174d512de08b5a68059605760340
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page