Skip to main content

Palestine

A Python library for building and rendering HTML using a DOM and component model.

Installation

pip install git+https://github.com/u84u/palestine.git

Or clone and install locally:

git clone https://github.com/u84u/palestine
cd palestine
pip install -e .

Requires Python 3.9+.

Quick start

from palestine import Document, Html, Body, Div, Text

doc = Document()
html = Html()
body = Body()
doc.append_child(html)
html.append_child(body)

page = Div(class_="container")
page.append_child(Text("Hello from Palestine"))
body.append_child(page)

print(doc)

Output:

<!DOCTYPE html>
<html><body><div class="container">Hello from Palestine</div></body></html>

What it looks like

Build a DOM tree

from palestine import Div, Text, Button

card = Div(class_="card")
card.append_child(Text("Title"))
card.append_child(Button(type="submit").append_child(Text("Click")))

# Move nodes between parents automatically
other = Div()
other.append_child(card)  # Detaches from previous parent

Render HTML

from palestine import Div, Text, RawText

# Text is escaped automatically
div = Div()
div.append_child(Text("<script>"))  # Renders as &lt;script&gt;

# RawText is for trusted markup
div.append_child(RawText("<svg>...</svg>"))  # Renders as-is

Compose components

from palestine import Div, H1, P, Text

def Card(title, content):
    card = Div(class_="card")
    card.append_child(H1().append_child(Text(title)))
    card.append_child(P().append_child(Text(content)))
    return card

page = Div()
page.append_child(Card("First", "Content here"))
page.append_child(Card("Second", "More content"))

Parse and manipulate HTML

from palestine import parse_html

doc = parse_html('<div class="box"><p>Hello</p></div>')
div = doc.query_selector(".box")
div.append_child(parse_html("<span>World</span>"))

Templates

from palestine import Template

tmpl = Template("<h1>{{ title }}</h1><p>{{ content }}</p>")
html = tmpl.render(title="My Page", content="Hello world")

Forms and validation

from palestine import FormBuilder, FormValidator, Required, Email

form = FormBuilder(action="/submit", method="post")
form.add_text("name", "Name", required=True)
form.add_email("email", "Email", required=True)
form.add_submit("Register")

validator = FormValidator({
    "name": [Required()],
    "email": [Required(), Email()],
})
errors = validator.validate({"name": "", "email": "invalid"})

Features

  • DOM primitives: Node, Element, Text, RawText, Comment, Document
  • HTML elements: All standard HTML5 elements
  • Rendering: HTML serialization, pretty printing, minification, streaming
  • Parsing: HTML to DOM conversion
  • Templates: Variable substitution and control flow
  • Components: Reusable UI composition
  • Forms: Form building and validation
  • Security: HTML sanitization, escaping, URL validation
  • VDOM: Virtual DOM with diff/patch

Architecture

Palestine is built around a mutable DOM tree:

Node
  ├── Element (tag, attributes, children)
  ├── Text (escaped content)
  ├── RawText (trusted markup)
  ├── Comment
  └── Document (root node)

Components are functions that compose elements. The renderer serializes the tree to HTML.

Performance

Palestine's renderer is optimized around direct DOM traversal, string accumulation, and bounded selector caching.

Reproducible benchmarks, profiling scripts, and historical baseline comparisons live in the GitHub repository under benchmarks/.

From a Git checkout:

python -m benchmarks.benchmark
python -m benchmarks.benchmark_memory
python benchmarks/profile_hotpaths.py

See benchmarks/REPORT.md for detailed results and methodology.

Status

Early-stage project. The core DOM, rendering, and template engine are functional and tested.

The parser is built on Python's html.parser and does not implement the full WHATWG HTML parsing algorithm. It handles common cases but may differ from browser parsing on malformed input.

The API may change between versions.

Why Palestine?

Most Python HTML generation falls into two camps: template languages (Jinja2, Mako) that treat HTML as strings, or minimal builder libraries (dominate, htpy) with a narrow API.

Palestine is different in that it gives you a mutable, traversable DOM tree — the same conceptual model as the browser — with querySelector, classList, event dispatch, innerHTML, closest, and clone. If you are building a server-side rendering pipeline, a static site generator, or an email renderer where you need to inspect and mutate the tree after construction (not just write it once), Palestine is designed for that.

It has no runtime dependencies and works on Python 3.9+.

Examples

Two runnable examples are in the examples/ directory:

  • hello_world.py — minimal HTTP server
  • file_explorer.py — file browser showing table building, conditional DOM construction, and safe path handling

Run either with: python examples/file_explorer.py Then open http://localhost:8000

License

MIT

Metadata

Release files for palestine 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for palestine 0.2.3
File Size Uploaded Provenance Actions
palestine-0.2.3.tar.gz 38.2 kB Without provenance Details for palestine-0.2.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for palestine 0.2.3
File Interpreter ABI Platform Actions
palestine-0.2.3-py3-none-any.whl Python 3 none any Details for palestine-0.2.3-py3-none-any.whl

Total release size: 81.4 kB

Release files / palestine-0.2.3.tar.gz

Download URL palestine-0.2.3.tar.gz
Size 38.2 kB
Tags Source
SHA-256 checksum
How to use checksums
904673f13fa48f1c3af4e7061ac9837d791da75b670883153e1db20a4783790c
BLAKE2b-256 checksum
How to use checksums
11a66457a7cbf045c8b793a802e4c0dc594b50e03106cb014ca266bfd9f10c2b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.25

Release files / palestine-0.2.3-py3-none-any.whl

Download URL palestine-0.2.3-py3-none-any.whl
Size 43.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
16232829a8a3e7ec03c1b979ec3a1809ce36068060d4ce5e4e067d6a8e2c981d
BLAKE2b-256 checksum
How to use checksums
4b67ba2f4cd90282c9fe3141d9fbb1d3bca900ae1caf7eb3d2628e26c2a75b27
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.25

Security for palestine 0.2.3

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page