sssimp 🐍
The Static Site Solution In Modern Python
It's simp with 3 s!
A simple tool to generate a static website while being able to use powerful HTML templates (Jinja2), Markdown files converted to HTML, and other preprocessors.
Why?
I wanted a simple way to generate static websites and I like Jinja2. I had previous experiences working with Jekyll but it seemed like too much work to setup everytime and overkill for the job as it supports many features I don't necessarily use.
One of the main goals with sssimp is being able to generate a usable website without any configuration file or dependency. You only install the sssimp package and run it.
Installing
Requirement: Python 3.8 or later
pip install --user sssimp
How to use
Create a folder called input, it will hold the data to generate the site.
Running sssimp will generate content in the output folder.
Input and output destination can be changed:
sssimp --input ../some-other/input-dir ~/some-other/output-dir
Use python -m sssimp --help for more details.
Generators
-
Files placed in
input/contentwill be directly copied to theoutputfolderExample:
input/content/favicon.png->output/favicon.png -
HTML files with the suffix .html placed in
input/contentwill be parsed as Jinja2 templates, they can use templates defined ininput/templates. See the Jinja2 documentationExample:
input/content/index.html->output/index.htmlStarting with content{% extends "base.html" %} ...Will use the template
input/templates/base.html -
CSS files in
input/csswill be merged together in a single fileoutput/bundle.css -
Markdown files with the suffix .md placed in
input/contentwill be parsed to HTML and passed to a template with the same name as their parent folder as the parametermarkdownExample:
./input/content/post/hello-world.md->./output/post/hello-world.htmlUsing the template./input/templates/post.htmlGenerated with context{'markdown': 'the markdown file converted to HTML'}The template name can be overriden using the markdown meta argument "template"
Example:
./input/content/post/special.md->./output/post/special.htmlStarting with content--- template: special.html --- ...
Will use the template
./input/templates/special.htmlinstead ofpost.html -
Files placed in
input/datawill exposes their content in templates inside thedatavariable. They can be in either YAML, JSON, or Markdown. The path is part of their position in the data structure tree.Example:
./input/data/categories/tech.ymlWith contentdescription: Nerdy stuff color: #121212 related: - computers - dev
Will populate the
datavariable in templates as so:{ "categories": [ { "tech": { "description": "Nerdy stuff", "color": "#121212", "related": ["computers", "dev"] } } ] }
-
Images placed in
input/imagesmust have a size specified in their filename using the syntaxname@size.ext. They will be resized and saved tooutput/images/name@size.ext.Size must be in the format
[width]x[height]. If bothwidthandheightare specified, the converter will ensure both dimensions are under the size, but aspect ratio will be preserved. For example, using size "200x200" on an image of resolution1200x1920will produce an image of size125x200.If only one size is specified, the other size will be able to be greater than the specified size. For example, using a size
200xon an image of resolution1200x1920will produce an image of size200x320.The following shorthands can be used:
thumb: 128x128small: 256x256medium: 512x512large: 1024x1024
You can specify multiple sizes, for example, a file named
input/images/name@thumb,large,700x,1200x1200.pngwill create the following files inoutput/images/:name@thumb.png,name@large.png,name@700x.png, andname@1200x1200.png.Full path will be honored, so a file at
input/images/1/2/3/4/name@thumb.pngwill be saved tooutput/images/1/2/3/4/name@thumb.png.
Examples
See the examples directory for per-feature examples, or my
personal website https://github.com/Tina-otoge/tina-simp for a real-world
example.
Additional Jinja2 filters
-
|amakes any relative path point to the top of the output folder.Example:
input/content/blog/post/tech/2021/11/some-post.html->output/blog/post/tech/2021/11/some-post.htmlWith content<link rel="stylesheet" href="{{ "style.css"|a }}">
Will be rendered as
"../../../../style.css"See also the
<base>element -
|markdowntransforms Markdown content to HTML using the same process that for Markdown files. -
|jsontransforms any object to a formatted JSON.
Additional Jinja2 variables
-
pageis asssimp.generators.html.Page, it contains many information about the current document. Markdown files are an instance ofsssimp.generators.markdown.MarkdownPageinstead, which inherits fromPageThis variable itself contains many useful variables:
-
page.modified_atandpage.created_at(modified_atforcibly set toNoneif same ascreated_at) -
page.href: The path to the file relative to the output folder -
page.src: Apathlib.Pathobject of the source file in the input folder -
page.targetApathlib.Pathobject of the target file in the output folder -
page.name: Shortcut forpage.target.name, the filename of the outputed file -
page.parent: Shortcut forpage.target.parent, the name of the parent directory in the output folder file -
page.meta: The Markdown meta variables, prefixing a var with=will interpret it as raw JSON Example--- some_var: some value something_else: 42 some_tags:= ["tag1", "tag2"] --- My cool blog post ...
The meta variable will always contain a
templatewhich will resolve to the parent directory name with .html appended if none is set in the meta fields.The
page.metavariable isNonefor raw HTML pages, this avoids KeyErrors when trying to filter pages by a specific meta variable.
-
-
plain_text1: A plain text representation of the Markdown file -
markdown1: The Markdown content converted to HTML -
meta1: A shortcut forpage.meta -
title1: Returnspage.meta.titleif it exists, else the filename with the characters-and_replaced by whitespaces, the suffix removed and the first letter capitalized.Example:
input/content/some-cool-page.md's title is "Some cool page" -
BUNDLE_FILEalways evaluates to"bundle.css"for now -
BUNDLE_TIMEmodification time of the latest updated file ininput/css, very useful to make the browser refresh the file only if any of the CSS files changed.Example:
<link rel="stylesheet" href="{{ BUNDLE_FILE}}?{{ BUNDLE_TIME }}">
-
PAGESa list ofsssimp.generators.html.Pageobjects containing every HTML and Markdown files sourced by the site. You can loop over it to generate an index. In conjunction with looking up meta values it can be used to filter by content type.Example:
{% for page in PAGES if page.meta.template == 'post.html' %} <a href="{{ page.href }}">{{ page.title }}</a> <div class="tags"> {% for tag in page.meta.tags %} <span class="tag">{{ tag }}</span> {% endfor %} </div> Posted on <time>{{ page.created_at }}</time> {% endfor %}
Release files for sssimp 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sssimp-0.2.0.tar.gz | 138.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sssimp-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 154.1 kB
Release files / sssimp-0.2.0.tar.gz
| Download URL | sssimp-0.2.0.tar.gz |
|---|---|
| Size | 138.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fdf9aca87ee5083ba075aa97f8bfa948acf4d907ef6450a62076d83bbfc4be96
|
|
BLAKE2b-256 checksum How to use checksums |
dd7aa2ccae6b4567c7d5f0e573df3b0a40cea6d21d3786fb34475dbe4c7122aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 8, 2026.
Transparency logRelease files / sssimp-0.2.0-py3-none-any.whl
| Download URL | sssimp-0.2.0-py3-none-any.whl |
|---|---|
| Size | 16.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1972d313806a15a11c1a3d05297ac8f5c42653aa83fc5357cde44a27a60b37cc
|
|
BLAKE2b-256 checksum How to use checksums |
a7e4b8ce4202fd80f1c6d6ac56ac586d43295c79fe1a94deee4c57772f19546a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 8, 2026.
Transparency log