Build HTML documents programmatically using Python objects.
Project description
luk
Create static HTML inside Python. No templates, just Python. Create objects directly or use the context manager to use control flow like if/else, add objects in loops, etcetera.
Installation
pip install luk
Quick Start
import luk
page = luk.Html(
luk.Head(luk.Title("My Page")),
luk.Body(
luk.H1("Welcome"),
luk.Div(
luk.P("Hello, ", luk.A("world", href="https://example.com"), "!"),
class_="container",
),
),
)
print(page.serialize())
Output:
<!DOCTYPE html><html><head><title>My Page</title></head><body><h1>Welcome</h1><div class="container"><p>Hello, <a href="https://example.com">world</a>!</p></div></body></html>
Features
Nested Elements
Pass child elements as positional arguments:
import luk
menu = luk.Ul(
luk.Li("Home"),
luk.Li("About"),
luk.Li("Contact"),
)
Attributes
Pass attributes as keyword arguments:
import luk
# Use trailing underscore for reserved words (class, for, etc.)
luk.Div(class_="container", id="main")
# Underscores in names become hyphens
luk.Div(data_user_id="123") # renders as data-user-id="123"
# Boolean attributes
luk.Input(type="checkbox", checked=True) # renders: <input type="checkbox" checked />
luk.Input(type="checkbox", checked=False) # renders: <input type="checkbox" />
Context Manager
Build nested structures using with statements. Elements created inside a with block are automatically appended as children:
import luk
with luk.Html() as page:
with luk.Head():
luk.Title("My Page")
with luk.Body():
with luk.Div(class_="header"):
luk.H1("Welcome")
with luk.Div(class_="content"):
luk.P("Here are some items:")
with luk.Ul():
for e in ["First", "Second", "Third"]:
luk.Li(f"{e} item")
print(page.serialize())
This produces the same output as the nested constructor style, but can be more readable for complex structures.
Self-Closing Elements
Void elements like <br>, <img>, <input>, and <meta> are self-closing and cannot have children:
import luk
luk.Img(src="photo.jpg", alt="A photo") # <img src="photo.jpg" alt="A photo" />
luk.Br() # <br />
luk.Input(type="text", name="email") # <input type="text" name="email" />
luk.Meta(charset="utf-8") # <meta charset="utf-8" />
Script and Style Elements
Content inside <script> and <style> tags is not escaped:
import luk
luk.Script("console.log('Hello, world!');")
# <script>console.log('Hello, world!');</script>
luk.Style("body { margin: 0; }")
# <style>body { margin: 0; }</style>
Trusted Content
Use Trusted to insert pre-built HTML without escaping:
import luk
# Useful for embedding HTML from trusted sources (e.g., markdown renderers)
luk.Div(luk.Trusted("<strong>Already formatted</strong> content"))
Warning: Only use Trusted with content you control. Never use it with user input.
HTML Escaping
Text content and attribute values are automatically escaped to prevent XSS:
import luk
luk.Span("<script>alert('xss')</script>")
# <span><script>alert('xss')</script></span>
luk.Div(title='He said "hello"')
# <div title="He said "hello""></div>
Writing to Files
Save the rendered HTML directly to a file:
import luk
page = luk.Html(
luk.Head(luk.Title("My Page")),
luk.Body(luk.H1("Hello!")),
)
page.write("index.html")
Serialization Options
page.serialize() # Includes <!DOCTYPE html> prefix
page.serialize(prepend_doctype=False) # Without doctype
Available Elements
Document
Html, Head, Body, Title, Meta, Link, Script, Style
Sections
Div, Section, Article, Nav, Header, Footer, Main, Aside
Headings
H1, H2, H3, H4, H5, H6
Text
P, Span, A, Strong, Em, B, I, Br, Hr, Pre, Code, Blockquote
Lists
Ul, Ol, Li
Tables
Table, Thead, Tbody, Tr, Th, Td
Forms
Form, Input, Button, Label, Select, Option, Textarea
Media
Img, Video, Audio, Source
Interactive
Details, Summary
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file luk-0.1.0.tar.gz.
File metadata
- Download URL: luk-0.1.0.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d85121bb068a9c330f0546d60badb0200b8c91904ca1823bfe9e99dc9414bda4
|
|
| MD5 |
d416aed23c3c9b122b5f576426144ca6
|
|
| BLAKE2b-256 |
3b90a3b2e1430188f4e7c875fe18d2cb6ab1865158cb0760c7b3e98ad879fb46
|
Provenance
The following attestation bundles were made for luk-0.1.0.tar.gz:
Publisher:
release.yml on sebasv/luk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
luk-0.1.0.tar.gz -
Subject digest:
d85121bb068a9c330f0546d60badb0200b8c91904ca1823bfe9e99dc9414bda4 - Sigstore transparency entry: 955551789
- Sigstore integration time:
-
Permalink:
sebasv/luk@53fb324f0a779e2a908303561e944923a5ddef4d -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/sebasv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@53fb324f0a779e2a908303561e944923a5ddef4d -
Trigger Event:
push
-
Statement type:
File details
Details for the file luk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: luk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ac106e89a5db81c98f174680c160a5b5426110b23c5412207e7413ebf8e8567
|
|
| MD5 |
3b98d9c89e7aaf221da4ec4d1234ab50
|
|
| BLAKE2b-256 |
56cbc491babf515917ec4eb69a96e8ad8ecdfaec4aa6c8d19b44dbe0b8feba10
|
Provenance
The following attestation bundles were made for luk-0.1.0-py3-none-any.whl:
Publisher:
release.yml on sebasv/luk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
luk-0.1.0-py3-none-any.whl -
Subject digest:
0ac106e89a5db81c98f174680c160a5b5426110b23c5412207e7413ebf8e8567 - Sigstore transparency entry: 955551790
- Sigstore integration time:
-
Permalink:
sebasv/luk@53fb324f0a779e2a908303561e944923a5ddef4d -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/sebasv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@53fb324f0a779e2a908303561e944923a5ddef4d -
Trigger Event:
push
-
Statement type: