A Python library for programmatic HTML generation with type safety and a clean API
Project description
StructFlow
A modern, type-safe Python library for generating HTML documents programmatically. StructFlow provides a clean, Pythonic API for creating HTML with full type hints and comprehensive tag support.
Features
- Type-safe: Full type hints with mypy support
- Complete HTML5 support: All standard HTML5 elements and attributes
- Clean API: Intuitive, Pythonic interface
- Flexible rendering: Pretty-printing and minified output options
- XHTML support: Optional XHTML-compliant output
- Extensible: Easy to extend with custom elements and attributes
Installation
pip install structflow
Or with Poetry:
poetry add structflow
Quick Start
from structflow import Document
from structflow.tags import div, h1, p, a, title, meta
# Create a document with head elements
doc = Document(
title("My Page Title"),
meta(charset="utf-8"),
meta(name="viewport", content="width=device-width, initial-scale=1"),
html_lang="en"
)
# Add content to body
doc.add(
div(
h1("Welcome to StructFlow", class_="hero-title"),
p("A modern HTML generation library for Python."),
a("Learn more", href="https://example.com", class_="btn btn-primary")
)
)
# Render the document
html_output = doc.render()
print(html_output)
Core Concepts
Document Structure
The Document class serves as the root container for your HTML document. Head elements are passed directly to the constructor:
from structflow import Document
from structflow.tags import title, meta, link
doc = Document(
# Head elements passed directly
title("Page Title"),
meta(charset="utf-8"),
meta(name="viewport", content="width=device-width, initial-scale=1"),
link(rel="stylesheet", href="styles.css"),
# Document options
doctype="<!DOCTYPE html>",
html_lang="en",
html_dir="ltr",
pretty=True,
xhtml=False
)
Adding Content
Head elements are specified in the document constructor, while body content is added using the add() method:
from structflow.tags import title, meta, link, div, h1
# Create document with head elements
doc = Document(
title("Page Title"),
meta(charset="utf-8"),
link(rel="stylesheet", href="styles.css")
)
# Add body content
doc.add(
div(
h1("Hello World"),
class_="container"
)
)
HTML Elements
All HTML5 elements are available as classes with proper typing:
from structflow.tags import (
# Structure
div, span, section, article, nav, aside, header, footer, main,
# Text content
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
# Lists
ul, ol, li, dl, dt, dd,
# Forms
form, input, textarea, select, option, button, label,
# Media
img, video, audio, source, picture,
# Tables
table, thead, tbody, tfoot, tr, th, td,
# Head elements
title, meta, link, script, style, base,
# And many more...
)
Attributes
All elements support both common HTML attributes and element-specific ones:
# Common attributes
div(id_="main", class_="container", style="color: blue;")
# Element-specific attributes
img(src="image.jpg", alt="Description", width=300, height=200)
input(type="email", name="email", required=True, placeholder="Enter email")
a(href="https://example.com", target="_blank", rel="noopener")
Class Attribute Handling
The class_ parameter accepts both strings and lists:
# String
div(class_="btn btn-primary")
# List (automatically joined with spaces)
div(class_=["btn", "btn-primary", "btn-large"])
Advanced Usage
Head Elements
StructFlow provides comprehensive support for all head elements with proper typing:
from structflow.tags import title, meta, link, script, style
doc = Document(
# Page metadata
title("My Application"),
meta(charset="utf-8"),
meta(name="description", content="A great web application"),
meta(name="keywords", content="python, html, web"),
meta(name="author", content="Your Name"),
# Viewport for responsive design
meta(name="viewport", content="width=device-width, initial-scale=1"),
# Open Graph metadata
meta(property="og:title", content="My Application"),
meta(property="og:description", content="A great web application"),
meta(property="og:image", content="https://example.com/image.jpg"),
# External resources
link(rel="stylesheet", href="styles.css"),
link(rel="icon", href="favicon.ico", type="image/x-icon"),
link(rel="preconnect", href="https://fonts.googleapis.com"),
# Scripts
script(src="https://cdn.example.com/library.js", defer=True),
# Inline styles
style("""
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
"""),
html_lang="en"
)
Custom Attributes
Use **kwargs for custom or non-standard attributes:
div(
"Content",
data_id="123",
data_toggle="modal",
aria_label="Close button"
)
Nested Elements
Elements can be deeply nested:
nav(
div(
ul(
li(a("Home", href="/")),
li(a("About", href="/about")),
li(a("Contact", href="/contact"))
),
class_="navbar-nav"
),
class_="navbar"
)
Forms
Creating forms with proper structure:
form(
fieldset(
legend("Contact Information"),
div(
label("Name:", for_="name"),
input(type="text", id_="name", name="name", required=True),
class_="form-group"
),
div(
label("Email:", for_="email"),
input(type="email", id_="email", name="email", required=True),
class_="form-group"
),
button("Submit", type="submit", class_="btn btn-primary")
),
action="/submit",
method="post"
)
Tables
Building data tables:
table(
thead(
tr(
th("Name"),
th("Age"),
th("City")
)
),
tbody(
tr(
td("John Doe"),
td("30"),
td("New York")
),
tr(
td("Jane Smith"),
td("25"),
td("Los Angeles")
)
),
class_="data-table"
)
Media Elements
Working with images and multimedia:
# Responsive image
picture(
source(
srcset="image-large.jpg",
media="(min-width: 800px)"
),
source(
srcset="image-medium.jpg",
media="(min-width: 400px)"
),
img(
src="image-small.jpg",
alt="Responsive image",
class_="responsive-img"
)
)
# Video with multiple sources
video(
source(src="video.mp4", type="video/mp4"),
source(src="video.webm", type="video/webm"),
"Your browser doesn't support video.",
controls=True,
width=640,
height=480
)
Rendering Options
Pretty Printing
Enable pretty printing for readable output:
doc = Document(pretty=True)
# or
html_output = doc.render(pretty=True)
XHTML Mode
Generate XHTML-compliant output:
doc = Document(xhtml=True)
# or
html_output = doc.render(xhtml=True)
Custom Doctype
Specify a custom doctype:
doc = Document(doctype="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"")
Complete Example
Here's a comprehensive example showing a complete HTML document:
from structflow import Document
from structflow.tags import *
# Create document with comprehensive head
doc = Document(
# Basic metadata
title("StructFlow Demo - Modern HTML Generation"),
meta(charset="utf-8"),
meta(name="viewport", content="width=device-width, initial-scale=1"),
meta(name="description", content="Demo of StructFlow HTML generation"),
# External resources
link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"),
link(rel="icon", href="favicon.ico"),
# Custom styles
style("""
.hero { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.hero h1 { color: white; }
"""),
html_lang="en"
)
# Build the page content
doc.add(
header(
nav(
div(
a("StructFlow", href="#", class_="navbar-brand"),
ul(
li(a("Home", href="#", class_="nav-link"), class_="nav-item"),
li(a("Docs", href="#", class_="nav-link"), class_="nav-item"),
li(a("GitHub", href="#", class_="nav-link"), class_="nav-item"),
class_="navbar-nav ms-auto"
),
class_="container-fluid"
),
class_="navbar navbar-expand-lg navbar-dark bg-dark"
)
),
main(
section(
div(
div(
div(
h1("Modern HTML Generation", class_="display-4"),
p("Build HTML documents with Python using a clean, type-safe API.",
class_="lead"),
a("Get Started", href="#features", class_="btn btn-light btn-lg"),
class_="col-md-8"
),
class_="row justify-content-center text-center"
),
class_="container py-5"
),
class_="hero py-5"
),
section(
div(
h2("Features", class_="text-center mb-5"),
div(
div(
div(
h3("Type Safe"),
p("Full type hints with mypy support for error-free development."),
class_="card-body"
),
class_="card h-100"
),
div(
div(
h3("Modern API"),
p("Clean, Pythonic interface that feels natural to use."),
class_="card-body"
),
class_="card h-100"
),
div(
div(
h3("Complete"),
p("All HTML5 elements and attributes with proper validation."),
class_="card-body"
),
class_="card h-100"
),
class_="row g-4"
),
class_="container py-5"
),
id_="features"
)
),
footer(
div(
p("© 2025 StructFlow. Built with ❤️ and Python.",
class_="text-center text-muted"),
class_="container py-4"
),
class_="bg-light mt-5"
),
# Bootstrap JavaScript
script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js")
)
# Render the complete document
html_output = doc.render()
Tag Categories
The library organizes tags into logical modules:
head:title,meta,link,script,style,base,noscript,templateedits:ins,del_embedded:img,video,audio,embed,iframe,object,canvas,svgforms:form,input,textarea,select,button,fieldset, etc.grouping:div,p,hr,ul,ol,li,dl,dt,dd, etc.links:a,areascripting:script,noscript,templatesections:section,article,nav,aside,header,footer,maintable:table,thead,tbody,tr,th,td, etc.text:span,strong,em,code,abbr,time, etc.
Type Safety
StructFlow provides comprehensive type hints:
from typing import Optional
from structflow.tags import div, span, meta, link
# Type-safe element creation
container: div = div(
span("Hello", class_="greeting"),
id_="main-container"
)
# Head elements with proper typing
metadata: meta = meta(
name="viewport",
content="width=device-width, initial-scale=1"
)
# Attributes are properly typed
stylesheet: link = link(
rel="stylesheet", # Literal type
href="styles.css", # str
media="screen" # str
)
Best Practices
- Organize head elements logically: Group related metadata together
- Use semantic HTML: Choose elements based on meaning, not appearance
- Leverage type hints: Let your IDE help you with autocompletion
- Structure your code: Break complex layouts into functions
- Separate concerns: Keep head metadata separate from body content
def create_page_head(title: str, description: str) -> tuple:
"""Create standard head elements for a page."""
return (
title(title),
meta(charset="utf-8"),
meta(name="viewport", content="width=device-width, initial-scale=1"),
meta(name="description", content=description),
link(rel="stylesheet", href="styles.css")
)
def create_card(title: str, content: str, image_url: str) -> div:
"""Create a reusable card component."""
return div(
img(src=image_url, alt=title, class_="card-image"),
div(
h3(title, class_="card-title"),
p(content, class_="card-content"),
class_="card-body"
),
class_="card"
)
# Usage
doc = Document(
*create_page_head("My Site", "Welcome to my website"),
html_lang="en"
)
doc.add(
create_card(
title="Product Name",
content="Product description here...",
image_url="product.jpg"
)
)
License
This project is licensed under the MIT License.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
If you encounter any problems or have questions, please open an issue on GitHub.
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
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 structflow-3.0.1.tar.gz.
File metadata
- Download URL: structflow-3.0.1.tar.gz
- Upload date:
- Size: 17.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44cb5a5e9d808e4d31fac8c04ae8ee6a776f9c25573a93b5d471d08d00056673
|
|
| MD5 |
66da4b81a2688ad964a1fa897f2871b0
|
|
| BLAKE2b-256 |
d007ac973193c76e657e02816971709ce321dd0cefabf8051b834b050c12e948
|
File details
Details for the file structflow-3.0.1-py3-none-any.whl.
File metadata
- Download URL: structflow-3.0.1-py3-none-any.whl
- Upload date:
- Size: 24.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6bd272f5dfd6c8496b84956c530c00799cf2ea86f3e3def05d5026d34bc18274
|
|
| MD5 |
7abad8c2e3508dc7de477fbf05b6a855
|
|
| BLAKE2b-256 |
65411f55dad92bd55e3e984a18e2e6ef0670fe17b40f7859c79576dd5091987a
|