Generate HTML with Python.
Pythoml provides a set of classes which render into HTML tags, allowing you to define HTML in code.
⚠️ CAUTION
It is important to sanitise any strings from an external source (e.g. a user input or database) which are used to render anything in a browser (e.g. HTML).
Pythoml does not provide any sanitisation. It is up to the developer to include that where necessary.
Pythonml can be installed from PyPI:
pip install pythomlAlternatively, you can download a specific version from the Releases.
The Pythoml.html module contains Tag classes for each HTML5 tag.
The class names match their respective HTML tags, for example: html.A for <a>...</a> and html.Div for <div>...</div>.
For the complete list please see html.py.
Creating a Tag:
from Pythoml import html
ex = html.P("This is a paragraph")Calling render() on a Tag will return the HTML string:
print(ex.render())Will print the following:
<p>
This is a paragraph
</p>A Tag constructor accepts any number of arguments and keyword arguments (i.e. *args, **kwargs).
Arguments (*args) are used for "content" which is nested inside the HTML tag.
For example, in the code above we passed the string "This is a paragraph" to html.P, so it was rendered inside the HTML tag <p>...</p>.
Keyword Arguments (**kwargs) are used for the HTML tag attributes and flags.
When a keyword argument value is a string, it will be used as an attribute of the HTML tag. For example setting an attribute name on a Div:
ex = html.Div(name="myDiv")
print(ex.render())
"""
<div name="myDiv">
</div>
"""ℹ️ INFO
There are some special keys to avoid collisions with Python keywords (most notablyclass_for setting a tag class attribute).
Below is a list of the special keys, listed asPython->HTML:
class_->classfor_->forid_->idtype_->type
When a keyword argument value is a boolean, it will be used as a flag on the HTML tag. For example setting a dialog as open:
ex = html.Dialog(open=True)
print(ex.render())
"""
<dialog open>
</dialog>
"""Tags can be added to the "content" of other Tags to achieve the typical nesting of HTML:
ex = html.Html(
html.Body(
html.H1("This is my Site"),
html.Hr(),
html.Div(
html.P("Welcome to my website!")
)
)
)
print(ex.render())
"""
<html>
<body>
<h1>
This is my Site
</h1>
<hr>
<div>
<p>
Welcome to my website!
</p>
</div>
</body>
</html>
"""ℹ️ INFO
Tagswhich represent "void elements" do not support adding content.
If you add content to such aTag, you will recieve a warning.
You can lazily add content or set attributes on a Tag:
ex = html.Div()
ex.add("Some content")
ex.set(name="myDiv")
print(ex.render())
"""
<div name="myDiv">
Some content
</div>
"""The add and set methods both return Self, which allows you to chain them:
ex = html.Div()
ex.add("Some content").set(name="myDiv")
print(ex.render())
"""
<div name="myDiv">
Some content
</div>
"""Alternatively, you can also call the instanciated Tag to update the content and attributes simultaneously:
ex = html.Div()
ex("Some content", name="myDiv")
print(ex.render())
"""
<div name="myDiv">
Some content
</div>
"""The syntax shown up until now only uses the constructor to populate the Tag content and attributes. Since the examples have been relatively simple, it does not highlight a minor grievance (at least to me...) with this approach.
Consider the following:
ex = html.Div(
html.H1("Title", class_="display-4")
html.Div(
html.H3("Subtitle"),
html.Div(
html.P("Some content"),
class_="card"
),
),
class_="container p-3" # <-- who does this belong to?
)With big ugly nests like this, it gets difficult to determine which Tag the attributes are associated with.
Since we can lazily add content, an alternative to the above is:
ex = html.Div(class_="container p-3")(
html.H1("Title", class_="display-4"),
html.Div(
html.H3("Subtitle"),
html.Div(class_="card")(
html.P("Some content"),
),
),
)