hyperscribe
A small, dependency-free HTML templating engine for Python.
You write markup as ordinary Python code with context managers,
and hyperscribe streams indented HTML to any file-like object,
escaping what you pass through escape.
from io import StringIO
from hyperscribe import DocWriter, escape
output = StringIO()
doc, t, v = DocWriter(output).parts
with t.html(lang="en"):
with t.body.main:
t.h1(escape("Hello & welcome"))
with t.ul:
for name in ("one", "two"):
t.li(escape(name))
print(output.getvalue())
<html lang="en">
<body>
<main>
<h1>Hello & welcome</h1>
<ul>
<li>one</li>
<li>two</li>
</ul>
</main>
</body>
</html>
Features
- Templates are plain Python: use loops, functions, and
@contextmanagerlayouts. - Attribute values follow the same rules as content:
literal strings,
escaped strings and numbers are written verbatim. doc(...)and tag content, as int.p(...), write trustedLiteralString,__html__objects, and numeric values verbatim while preserving indentation;escapeandtrustmark other strings as safe for them.- On Python 3.14 and newer, template strings (
t"...") are accepted too: literal parts are trusted and interpolated values are escaped. - Output is streamed to anything with a
write(str)method. - Fully typed, and supports Python 3.10 and newer.
- No dependencies apart from
typing_extensionsfor Python 3.10–3.12.
Installation
pip install hyperscribe
Documentation
Full documentation is available at https://septatrix.github.io/hyperscribe/.
Development
make sync # install dependencies
make check # lint, type-check, check formatting, and test
make format # format the code with ruff
make docs # build the documentation
make doctest # run the examples in the documentation
Run make help to list all targets.
Use uv run sphinx-autobuild docs docs/_build/html to preview the docs while editing.
The benchmarks compare hyperscribe with other Python HTML templating libraries
using pytest-benchmark.
Their dependencies live in the optional benchmarks dependency group
and need Python 3.14:
uv run --group benchmarks pytest benchmarks
Releasing
The version is derived from git tags by hatch-vcs.
To release, publish a GitHub release whose tag is v plus the version, such as v0.2.0.
The Publish workflow builds the package
and uploads it to PyPI through
trusted publishing.
Copy the files in contrib/workflows/ to .github/workflows/ once,
using a credential that may edit workflows.
Roadmap
These gaps showed up
when porting real Jinja and bottle templates to hyperscribe.
Attribute handling, content conversion, comments,
doc.voids for void elements, and the guide's loop idioms
have been dealt with since.
Two larger items remain.
- Element registry.
hyperscribe does not know anything about individual elements.
A registry with metadata per element
should cover the following:
- Void elements such as
<br>and<img>should be written without going throughdoc.voidsexplicitly. - Whitespace-sensitive elements such as
<pre>and<textarea>should switch to inline mode automatically. Today the caller has to know to usedoc.inline(). - The contents of
<style>and<script>should be written verbatim. - The set of permitted attributes could be checked.
- Void elements such as
- Trusted content.
DocWriter.__call__and tag content have preliminary support for trusted content:LiteralString,SafeStrfromescapeandtrust, objects implementing__html__(such as MarkupSafe'sMarkup), and numeric values are written verbatim with indentation. Broader safe string support for CSS, JavaScript, or prepared markup, perhaps built on template strings, remains future work.
Status
hyperscribe is in early development and its API may change between minor releases.
Metadata
Release files for hyperscribe 0.5.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 | |
|---|---|---|---|
| hyperscribe-0.5.0.tar.gz | 21.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hyperscribe-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.0 kB
Release files / hyperscribe-0.5.0.tar.gz
| Download URL | hyperscribe-0.5.0.tar.gz |
|---|---|
| Size | 21.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5d57c4e77797162b1dce932ef172fc7189253b61f8d2d1a3f54bb587f88aac7e
|
|
BLAKE2b-256 checksum How to use checksums |
2ac2a08d73a7c127a3be47c91478aee39972886a0cec5b8385e2e8e87fa6637a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 5, 2026.
Transparency logRelease files / hyperscribe-0.5.0-py3-none-any.whl
| Download URL | hyperscribe-0.5.0-py3-none-any.whl |
|---|---|
| Size | 8.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0f7715f2f5a2961ed76d051b411e8a6d1fa62f939a592a51350bdd7a2a65e86d
|
|
BLAKE2b-256 checksum How to use checksums |
d546248ec64ca64124944339e449309c7523716d4bf5555a5e909b023f3ecd2f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 5, 2026.
Transparency log