pdj_sitegen
Pandoc and Jinja Site Generator
- docs:
miv.name/pdj_sitegen/ - demo site:
miv.name/pdj_sitegen/demo_site/ - source:
github.com/mivanit/pdj-sitegen
Installation:
pip install pdj-sitegen
you should either have Pandoc installed, or you can run
python -m pdj_sitegen.install_pandoc
which will install pandoc using pypandoc
Usage
Quick Start
Scaffold a new site with all default files:
python -m pdj_sitegen.setup_site [directory]
This creates:
config.yml- default configurationtemplates/default.html.jinja2- default HTML templatecontent/index.md- sample index pagecontent/resources/style.css- basic stylesheetcontent/resources/syntax.css- code syntax highlighting
Manual Setup
- create a config file. For an example, see
pdj_sitegen.config.DEFAULT_CONFIG_YAML, or print a copy of it via
python -m pdj_sitegen.config
- adjust the config file to your needs. most importantly:
# directory with markdown content files and resources, relative to cwd
content_dir: content
# templates directory, relative to cwd
templates_dir: templates
# default template file, relative to `templates_dir`
default_template: default.html.jinja2
# output directory, relative to cwd
output_dir: docs
-
populate the
contentdirectory with markdown files and resources (images, css, etc.), and adjust templates in thetemplatesdirectory. See the demo site for usage examples. -
run the generator
python -m pdj_sitegen your_config.yaml
CLI Arguments
python -m pdj_sitegen your_config.yaml [-q] [-s]
-q, --quiet: Disable verbose output (suppress progress messages)-s, --smart-rebuild: Only rebuild files modified since last build
Smart Rebuild
The smart rebuild feature (-s flag) enables incremental builds by tracking file modification times:
- A
.build_timefile in your project root stores the timestamp of the last successful build - Source files are compared against this timestamp; only newer files are rebuilt
- Ideal for large sites during development - significantly speeds up iteration
# Full rebuild (always safe)
python -m pdj_sitegen config.yml
# Smart rebuild (faster, for content-only changes)
python -m pdj_sitegen config.yml -s
When to use full rebuild: After modifying templates or config, since these changes affect all pages. The .build_time file is automatically created and updated.
Configuration
Config File Formats
pdj-sitegen supports multiple configuration file formats:
- YAML (
.yml,.yaml) - recommended, human-friendly - TOML (
.toml) - also supported - JSON (
.json) - for programmatic generation
python -m pdj_sitegen config.yml # YAML
python -m pdj_sitegen config.toml # TOML
python -m pdj_sitegen config.json # JSON
Complete Configuration Examples
YAML Configuration
content_dir: content
templates_dir: templates
default_template: default.html.jinja2
output_dir: docs
copy_include: []
copy_exclude:
- "*.md"
prettify: false
pandoc_fmt_from: markdown+smart
pandoc_fmt_to: html
__pandoc__:
mathjax: true
toc: true
jinja_env_kwargs: {}
globals_:
site_name: "My Site"
author: "Your Name"
TOML Configuration
content_dir = "content"
templates_dir = "templates"
default_template = "default.html.jinja2"
output_dir = "docs"
copy_include = []
copy_exclude = ["*.md"]
prettify = false
pandoc_fmt_from = "markdown+smart"
pandoc_fmt_to = "html"
[__pandoc__]
mathjax = true
toc = true
[jinja_env_kwargs]
[globals_]
site_name = "My Site"
author = "Your Name"
JSON Configuration
{
"content_dir": "content",
"templates_dir": "templates",
"default_template": "default.html.jinja2",
"output_dir": "docs",
"copy_include": [],
"copy_exclude": ["*.md"],
"prettify": false,
"pandoc_fmt_from": "markdown+smart",
"pandoc_fmt_to": "html",
"__pandoc__": {
"mathjax": true,
"toc": true
},
"jinja_env_kwargs": {},
"globals_": {
"site_name": "My Site",
"author": "Your Name"
}
}
Content Mirroring
Files from content_dir are automatically copied to output_dir, excluding markdown files (which are processed into HTML). Control this with copy_include and copy_exclude:
# Default: copy everything except .md files
copy_include: []
copy_exclude:
- "*.md"
# Also exclude temp files and .git
copy_exclude:
- "*.md"
- "*.tmp"
- ".git*"
# Copy only specific file types
copy_include:
- "*.css"
- "*.js"
- "*.png"
- "*.jpg"
copy_exclude: []
# Force copy .md files too (include wins over exclude)
copy_include:
- "*.md"
copy_exclude:
- "*.md"
Additional Options
# Global template variables accessible in all templates
globals_:
site_name: "My Site"
author: "Your Name"
# Directory to save intermediate processing files (for debugging)
intermediates_dir: null # or "_intermediates"
# Prettify HTML output (uses BeautifulSoup)
prettify: false
# Pandoc format settings
pandoc_fmt_from: "markdown+smart"
pandoc_fmt_to: "html"
# Global Pandoc options (can be overridden per-file in frontmatter)
__pandoc__:
mathjax: true
# Jinja2 environment customization
jinja_env_kwargs: {}
Debugging with Intermediates
Setting intermediates_dir saves intermediate processing stages for debugging template and Pandoc issues:
intermediates_dir: _intermediates
This creates the following structure:
_intermediates/
frontmatter_txt/ # Raw frontmatter as parsed
frontmatter_json/ # Frontmatter as JSON (for inspection)
md/ # Rendered Markdown (after Jinja2, before Pandoc)
html/ # Pandoc output (before template wrapping)
Useful for debugging Jinja2 template rendering in content, inspecting what Pandoc receives vs. outputs, and understanding frontmatter parsing issues.
HTML Prettification
When prettify: true is set, the final HTML output is reformatted using BeautifulSoup for readable, indented HTML:
prettify: true
Considerations: Increases build time and output file size slightly. Useful for debugging or when HTML readability matters. For production, false (default) produces more compact output.
Jinja2 Environment Customization
The jinja_env_kwargs option allows you to customize the Jinja2 environment:
jinja_env_kwargs:
# Trim whitespace around blocks
trim_blocks: true
lstrip_blocks: true
# Change template delimiters (useful if content conflicts with {{ }})
variable_start_string: "[["
variable_end_string: "]]"
For the full list of options, see the Jinja2 Environment documentation.
Error Reporting
pdj-sitegen provides detailed error handling with actionable error messages:
Terminal Output
When a build error occurs, you'll see a terse, actionable error message showing:
- The file path and line number where the error occurred
- The problematic source line (when available)
- The root cause of the error
Example output:
on content/blog/post.md:6:
{{ undefined_variable }}
UndefinedError: 'undefined_variable' is undefined
1/15 files failed to convert
Full details: .pdj-sitegen/2024-01-27_14-30-45/
Detailed Error Dumps
For debugging complex errors, full context is saved to .pdj-sitegen/<timestamp>/:
traceback_<file>.txt- Full Python stack tracecontext_<file>.json- Template context (all variables available)template_<file>.txt- The template content that failed
This directory is created automatically when build errors occur. Add .pdj-sitegen/ to your .gitignore:
# pdj-sitegen error dumps
.pdj-sitegen/
Content Organization
pdj-sitegen supports both flat and nested content structures:
Flat structure (using dot notation):
content/
index.md
blog.md
blog.post-1.md
blog.post-2.md
Outputs: index.html, blog.html, blog.post-1.html, blog.post-2.html
Nested structure (using directories):
content/
index.md
blog/
index.md
post-1.md
post-2.md
Outputs: index.html, blog/index.html, blog/post-1.html, blog/post-2.html
Both approaches work with child_docs_dotlist (path prefix matching) and child_docs_folder (same directory) in templates for hierarchical navigation.
Pandoc Filters
pdj-sitegen includes two built-in pandoc filters:
links_md2html
Converts links ending in .md to .html during conversion. Enable in frontmatter or global config:
__pandoc__:
filter: links_md2html
csv_code_table
Converts fenced code blocks with class csv_table to HTML tables.
In your markdown, use a fenced code block with the csv_table class and options:
'''{.csv_table header=1 aligns=LCR caption="My Table"}
Name,Count,Status
Alice,42,Active
Bob,17,Pending
'''
NOTE: in the above, use backticks (`) instead of single quotes (') for the fenced code block; single quotes are used here to avoid rendering issues.
Options:
header: Number of header rows (default: 1)source: Path to external CSV filealigns: Column alignments (L=left, C=center, R=right, D=default)caption: Table caption
Template Variables
The following variables are available in templates:
| Variable | Description | Example |
|---|---|---|
frontmatter |
Full frontmatter dict from the current document | {"title": "My Page"} |
file_meta.path |
Relative path without extension | blog/post-1 |
file_meta.path_html |
HTML output path | blog/post-1.html |
file_meta.path_raw |
Original file path | content/blog/post-1.md |
file_meta.path_to_root |
Relative path prefix to site root (no trailing slash) | . or .. or ../.. |
file_meta.modified_time |
Unix timestamp of last modification | 1706380800.0 |
file_meta.modified_time_str |
Human-readable modification time | 2024-01-27 12:00:00 |
config |
Serialized site configuration | {"output_dir": "docs"} |
docs |
Dictionary of all documents in the site | {"index": {...}} |
child_docs_dotlist |
Documents matching by path prefix | {"blog.post-1": {...}} |
child_docs_folder |
Documents in the same directory | {"about": {...}} |
dir_files |
List of all filenames in the directory | ["index.md", "about.md"] |
dir_subdirs |
List of subdirectory names | ["images", "posts"] |
dir_contents_recursive |
List of all files recursively (relative paths) | ["images/logo.png"] |
content |
Rendered HTML content (in final template only) | <p>Hello</p> |
All frontmatter fields are also available directly (e.g., {{ title }}).
Frontmatter Formats
Frontmatter can be written in YAML, JSON, or TOML:
YAML (recommended):
---
title: My Page
tags: [foo, bar]
---
JSON:
;;;
{"title": "My Page", "tags": ["foo", "bar"]}
;;;
TOML:
+++
title = "My Page"
tags = ["foo", "bar"]
+++
Per-file Overrides
Override global settings in frontmatter:
---
title: My Page
__template__: custom.html.jinja2 # Use different template
__pandoc__:
toc: true # Override pandoc options
number-sections: true
---
similar tools/resources
This project is a descendant of my old project pandoc-sitegen, which was very similar but used mustache templates instead of jinja2.
Some other similar projects:
- https://github.com/brianbuccola/brianbuccola.github.io
- https://runningcrocodile.fi/pandoc_static_site/
- http://pdsite.org/installing/
- https://github.com/locua/pandoc-python-static-site-gen
- https://github.com/lukasschwab/pandoc-blog
- https://github.com/fcanas/bake
if you end up using this script for your site and would me to list it here, email me or submit a PR :)
Metadata
Release files for pdj-sitegen 0.0.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pdj_sitegen-0.0.7.tar.gz | 40.8 kB | Without provenance | Details for pdj_sitegen-0.0.7.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pdj_sitegen-0.0.7-py3-none-any.whl | Python 3 | none | any | Details for pdj_sitegen-0.0.7-py3-none-any.whl |
Total release size: 87.3 kB
Release files / pdj_sitegen-0.0.7.tar.gz
| Download URL | pdj_sitegen-0.0.7.tar.gz |
|---|---|
| Size | 40.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e04709a7015c4554b80b1c92d2a5881308b76493d4aa7a0e67f53bbbf6df6758
|
|
BLAKE2b-256 checksum How to use checksums |
89ff189f4cb3b9ef37fd4fbd1b83891f86f8073a535900b4a44c3d8845821f90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.2
|
Release files / pdj_sitegen-0.0.7-py3-none-any.whl
| Download URL | pdj_sitegen-0.0.7-py3-none-any.whl |
|---|---|
| Size | 46.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ca1be63cfa347359a5340566aa2c8b6d17a4719a6cae35d31a5413e9ac415f18
|
|
BLAKE2b-256 checksum How to use checksums |
61cb64e9e1815d792275b9ccee7ba4eceb62fddccab1a88cf723464cd994da2f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.2
|
Security for pdj-sitegen 0.0.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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.