A Python library for creating and manipulating HTML documents using an elegant DOM API
—
Text processing utilities for HTML escaping, URL encoding, raw HTML insertion, file inclusion, and specialized container elements for advanced layouts.
HTML and URL encoding/decoding utilities for safe content handling.
def escape(data, quote=True):
"""
Escape special characters for HTML content.
Parameters:
- data (str): Text to escape
- quote (bool): Whether to escape quote characters
Returns:
- str: HTML-escaped text
Escapes: & < > and optionally "
"""
def unescape(data):
"""
Unescape HTML entities back to original characters.
Parameters:
- data (str): HTML-escaped text
Returns:
- str: Unescaped text
"""
def url_escape(data):
"""
URL-encode special characters.
Parameters:
- data (str): Text to URL-encode
Returns:
- str: URL-encoded text
"""
def url_unescape(data):
"""
Decode URL-encoded characters.
Parameters:
- data (str): URL-encoded text
Returns:
- str: Decoded text
"""from dominate.util import escape, unescape, url_escape, url_unescape
# HTML escaping
user_input = '<script>alert("XSS")</script>'
safe_html = escape(user_input)
# Result: '<script>alert("XSS")</script>'
# HTML unescaping
escaped_text = '<b>Bold</b>'
original = unescape(escaped_text)
# Result: '<b>Bold</b>'
# URL encoding
search_query = 'hello world & more'
encoded = url_escape(search_query)
# Result: 'hello%20world%20%26%20more'
# URL decoding
encoded_url = 'hello%20world%20%26%20more'
decoded = url_unescape(encoded_url)
# Result: 'hello world & more'
# Quote handling
text_with_quotes = 'Say "hello" to the world'
escaped_no_quotes = escape(text_with_quotes, quote=False)
# Result: 'Say "hello" to the world' (quotes not escaped)
escaped_with_quotes = escape(text_with_quotes, quote=True)
# Result: 'Say "hello" to the world'Insert unescaped HTML content and include external files.
def raw(s):
"""
Insert raw HTML without escaping.
Parameters:
- s (str): Raw HTML string
Returns:
- text: Text element with escaping disabled
Warning: Use carefully to avoid XSS vulnerabilities
"""
def include(f):
"""
Include contents of a file as raw HTML.
Parameters:
- f (str): File path to include
Returns:
- text: Text element containing file contents
"""from dominate.util import raw, include
from dominate.tags import div, p
# Raw HTML insertion
container = div(
p('Regular paragraph'),
raw('<em>This HTML will not be escaped</em>'),
p('Another regular paragraph')
)
# Including external files
# Assuming 'snippet.html' contains: '<b>Bold content</b>'
content = div(
h2('Included Content'),
include('snippet.html') # File contents inserted as-is
)
# Combining with other elements
mixed_content = div(
h1('Page Title'),
raw('''
<div class="custom-widget">
<p>This is raw HTML with custom styling</p>
<button onclick="customFunction()">Click Me</button>
</div>
'''),
p('Back to regular content')
)Execute system commands and capture output for dynamic content generation.
def system(cmd, data=None):
"""
Execute system command and return output.
Parameters:
- cmd (str): Command to execute
- data (str|None): Optional input data to pipe to command
Returns:
- str: Command output (decoded as UTF-8)
"""from dominate.util import system, raw
from dominate.tags import div, h2, pre
# Execute command and include output
container = div(
h2('System Information'),
pre(system('date')), # Current date/time
h2('Directory Listing'),
pre(system('ls -la')) # Directory contents
)
# Process markdown with external tool
markdown_content = "# Hello\n\nThis is **markdown**."
html_output = system('markdown', data=markdown_content)
content = div(raw(html_output))Container elements for advanced layout control and content organization.
class container(dom_tag):
"""
Invisible container that groups elements without adding HTML structure.
Properties:
- is_inline = True: Renders children inline without wrapper element
"""
def _render(self, sb, indent_level, indent_str, pretty, xhtml):
"""Custom rendering that outputs only children, no wrapper element."""
class text(dom_tag):
"""
Text node element for inserting plain or raw text content.
Properties:
- is_pretty = False: No pretty printing
- is_inline = True: Inline rendering
"""
def __init__(self, _text, escape=True):
"""
Create text node.
Parameters:
- _text (str): Text content
- escape (bool): Whether to HTML-escape the text
"""
@property
def escape(self) -> bool:
"""Whether text is HTML-escaped."""
class lazy(dom_tag):
"""
Lazy evaluation container that delays function execution until rendering.
"""
def __init__(self, func, *args, **kwargs):
"""
Create lazy evaluation element.
Parameters:
- func (callable): Function to execute during rendering
- *args: Arguments for the function
- **kwargs: Keyword arguments for the function
"""
@property
def func(self) -> callable:
"""Function to execute."""
@property
def args(self) -> tuple:
"""Function arguments."""
@property
def kwargs(self) -> dict:
"""Function keyword arguments."""from dominate.util import container, text, lazy
from dominate.tags import div, p, ul, li
# Container for grouping without HTML wrapper
page_content = div(
h1('Page Title'),
container(
# These elements will be added directly to the div,
# not wrapped in another element
p('First paragraph'),
p('Second paragraph'),
ul(li('Item 1'), li('Item 2'))
),
p('Footer paragraph')
)
# Text nodes with different escaping
content = div(
text('This will be escaped: <b>bold</b>', escape=True),
text('This will NOT be escaped: <b>bold</b>', escape=False)
)
# Using text in context managers
with div() as container:
text('Start of content ')
a('link text', href='/link')
text(' end of content.')
# Lazy evaluation for dynamic content
def get_current_time():
import datetime
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def generate_user_list():
users = ['Alice', 'Bob', 'Charlie']
return ul([li(user) for user in users])
page = div(
h1('Dynamic Content'),
p('Current time: ', lazy(get_current_time)),
h2('User List'),
lazy(generate_user_list)
)
# Lazy with arguments
def format_price(amount, currency='USD'):
return f'{amount} {currency}'
product = div(
h3('Product Name'),
p('Price: ', lazy(format_price, 29.99, currency='EUR'))
)Complex text processing and content management utilities.
# Text elements in context managers
with p() as paragraph:
text('Have a look at our ')
a('other products', href='/products')
text(' for more options.')
# Result: <p>Have a look at our <a href="/products">other products</a> for more options.</p># Advanced container usage
def create_card_layout(title, content, actions):
return container(
div(h3(title), cls='card-header'),
div(p(content), cls='card-body'),
div(actions, cls='card-footer')
)
# Use in larger structure
page = div(
create_card_layout(
'Welcome',
'This is the welcome message.',
[button('Get Started'), button('Learn More')]
),
create_card_layout(
'Features',
'Here are the key features.',
button('View All Features')
),
cls='card-container'
)# Conditional lazy evaluation
def maybe_show_admin_panel(user):
if user.is_admin:
return div(
h2('Admin Panel'),
button('Manage Users'),
button('View Analytics')
)
return ''
# Database-driven content
def load_recent_posts():
# Simulated database call
posts = get_recent_posts_from_db()
return div([
article(
h3(post.title),
p(post.excerpt)
) for post in posts
])
# Template with lazy sections
template = div(
header(h1('My Blog')),
main(lazy(load_recent_posts)),
aside(lazy(maybe_show_admin_panel, current_user)),
footer('© 2023 My Blog')
)from dominate import document
from dominate.tags import *
from dominate.util import *
import datetime
def create_dynamic_page():
"""Create a page with various utility features."""
# Dynamic content functions
def current_stats():
return container(
p(f'Generated at: {datetime.datetime.now()}'),
p(f'System uptime: {system("uptime")}')
)
def load_external_content():
# Simulate loading from external source
return raw('''
<div class="external-widget">
<h4>External Content</h4>
<p>This content was loaded from an external source.</p>
</div>
''')
# Build page
doc = document(title='Utility Demo')
with doc.head:
style('''
.highlight { background-color: yellow; }
.external-widget { border: 1px solid #ccc; padding: 10px; }
''')
with doc:
header(
h1('Dominate Utilities Demo'),
nav(
container(
a('Home', href='/'),
text(' | '),
a('About', href='/about'),
text(' | '),
a('Contact', href='/contact')
)
)
)
main(
section(
h2('Text Processing'),
p('User input: ', code(escape('<script>alert("safe")</script>'))),
p('URL example: ', code(url_escape('hello world & more')))
),
section(
h2('Dynamic Content'),
lazy(current_stats)
),
section(
h2('External Content'),
lazy(load_external_content)
),
section(
h2('Raw HTML'),
raw('<p class="highlight">This HTML is not escaped</p>')
)
)
footer(
container(
text('© 2023 Demo Site | '),
a('Privacy Policy', href='/privacy'),
text(' | '),
a('Terms of Service', href='/terms')
)
)
return doc
# Generate and output the page
page = create_dynamic_page()
print(page)Install with Tessl CLI
npx tessl i tessl/pypi-dominate