Skip to main content

The artless and minimalist templating for Python server-side rendering.

Project description

artless-template

PyPI Version Development Status PyPI - Python Version Downloads PyPI - License

The artless and minimalist templating for Python server-side rendering.

artless-template is a tiny (under 200 lines), dependency-free template engine, designed for generating HTML using either template files or native Python objects.

Perfect for modern, clean server-side rendering with a focus on simplicity, performance, and patterns like HTMX and No-JS.

Why artless-template?

  • 🪶 Tiny: Single module, no dependencies, no magic, no bloat
  • ⚡ Fast & Small: Under 200 LOC, built for speed (see benchmarks)
  • 🧹 Functional style: Mostly pure functions, no side effects, fully type-annotated
  • 🐍 Modern: Python 3.11+ only
  • ✅ Tested: 100% test coverage.
  • 📚 Well-documented: With usage examples.

Quickstart

Installation

From PyPI:

$ pip install artless-template

From source:

$ git clone https://git.peterbro.su/peter/py3-artless-template
$ cd py3-artless-template
$ pip install .

Template and tags usage

Create templates/index.html with contents:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>@title</title>
  </head>
  <body>
    <main>
        <section>
            <h1>@header</h1>
            <table>
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Email</th>
                        <th>Admin</th>
                    </tr>
                </thead>
                @users
            </table>
        </section>
    </main>
  </body>
</html>
from typing import final
from pathlib import Path
from random import randint
from dataclasses import dataclass
from artless_template import read_template, Tag as t

TEMPLATES_DIR: Path = Path(__file__).resolve().parent / "templates"

@final
@dataclass(frozen=True, slots=True, kw_only=True)
class UserModel:
    name: str
    email: str
    is_admin: bool


users = [
    UserModel(
        name=f"User_{_}", email=f"user_{_}@gmail.com", is_admin=bool(randint(0, 1))
    )
    for _ in range(10_000)
]


users_markup = t(
    "tbody",
    [
        t(
            "tr",
            [
                t("td", user.name),
                t("td", user.email),
                t("td", "+" if user.is_admin else "-"),
            ],
        )
        for user in users
    ],
)

context = {
    "title": "Artless-template example",
    "header": "Users list",
    "users": users_markup,
}

template = read_template(TEMPLATES_DIR / "index.html").render(**context)

Template and components usage

<!DOCTYPE html>
<html lang="en">
  ...
  <body>
    <main>
      @main
    </main>
  </body>
</html>
from artless_template import read_template, Component, Tag as t

...

class UsersTableComponent:
    def __init__(self, count: int):
        self.users = [
            UserModel(
                name=f"User_{_}", email=f"user_{_}@gmail.com", is_admin=bool(randint(0, 1))
            )
            for _ in range(count)
        ]

    def view(self):
        return t(
            "table",
            [
                t(
                    "thead",
                    [
                        t(
                            "tr",
                            [
                                t("th", "Name"),
                                t("th", "Email"),
                                t("th", "Admin"),
                            ]
                        )
                    ]
                ),
                t(
                    "tbody",
                    [
                        t(
                            "tr",
                            [
                                t("td", user.name),
                                t("td", user.email),
                                t("td", "+" if user.is_admin else "-"),
                            ],
                        )
                        for user in self.users
                    ]
                )
            ]
        )

template = read_template(TEMPLATES_DIR / "index.html").render(main=UsersTableComponent(100500))

Asynchronous functions

The library provides async version of io-bound function - read_template. An asynchronous function has a prefix and called aread_template.

from artless_template import aread_template

template = await aread_template("some_template.html")
...

Read detailed reference documentation.

Performance

Performance comparison of the most popular template engines and artless-template library. The benchmark render a HTML document with table of 10 thousand user models.

Run benchmark:

$ python -m bemchmarks

Sorted results on i5 laptop (smaller is better):

{
    'mako': 0.05319607999990694,
    'jinja2': 0.27525966498069465,
    'artless': 0.5908581139810849,
    'dtl': 1.034598412021296,
    'fasthtml': 12.420113595988369
}
  1. Mako (0.05319 sec.)
  2. Jinja2 (0.27525 sec.)
  3. Artless-template (0.59085 sec.)
  4. Django templates (1.03459 sec.)
  5. FastHTML (12.42011 sec.)

The performance of artless-template is better than the Django template engine, and much better than FastHTML, but worse than Jinja2 and Mako.

Roadmap

  • Simplify the Tag constructor.
  • Write detailed documentation with Sphinx.
  • Create async version of read_template() - aread_template().
  • Cythonize CPU/RAM-bound of code.

Related projects

  • artless-core - the artless and ultralight web framework for building minimal APIs and apps.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

artless_template-0.6.1.tar.gz (8.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

artless_template-0.6.1-py3-none-any.whl (6.5 kB view details)

Uploaded Python 3

File details

Details for the file artless_template-0.6.1.tar.gz.

File metadata

  • Download URL: artless_template-0.6.1.tar.gz
  • Upload date:
  • Size: 8.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.11

File hashes

Hashes for artless_template-0.6.1.tar.gz
Algorithm Hash digest
SHA256 bd40c8f4c49c704d6550cabb01a826f07b44ec1d9b303c6a9f2a9419a176ccb3
MD5 3996a4d40a30ca7c2e0c6a75e23b5c6e
BLAKE2b-256 ecd8d1392b745070aebb1ff178b8702b0907ae3d34aac8a8a2d092c1d01d1e57

See more details on using hashes here.

File details

Details for the file artless_template-0.6.1-py3-none-any.whl.

File metadata

File hashes

Hashes for artless_template-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fdc90620534af01549943515a331eff09a3d1a1b3ec6c8de30509f25f5f3c962
MD5 3599ab8ee0e6f0ce782fad0abc439d90
BLAKE2b-256 24d863b0850278c26dda6d7bb01675b7bd55893033cebc4052f873768479323d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page