leptris (Python) — lxml-shaped bindings for libleptris
leptris wraps the libleptris
C API (XML 1.0 parsing, XPath 1.0) using cffi in ABI mode, with a
required C accelerator for Element allocation and the hot accessors
(tag, text, attrib, get, indexing, sibling navigation and
plain-path XPath evaluation). Wheels ship it compiled; sdist builds
require a C compiler.
The pinned libleptris version lives in libleptris-version.txt
(lockstep releases); CI builds it from the release tarball. The
binding loads the shared library from LEPTRIS_LIB_PATH or the
loader path.
Requirements
- Python 3.9+
cffi(installed automatically)- libleptris 1.9.3+ as a shared library (1.9.1 has an options-struct ABI break — leptris/leptris#568)
- libleptris as a shared library (
libleptris.dylib/.so/.dll) on the loader path, or pointed to byLEPTRIS_LIB_PATH(which must name the library file — the loaderdlopens it verbatim). For a development checkout:
cmake -B build -S /path/to/leptris -DLEPTRIS_BUILD_SHARED=ON
cmake --build build --target leptris_shared
export LEPTRIS_LIB_PATH=/path/to/leptris/build/src/libleptris.dylib
Quick start
from leptris import fromstring, tostring
root = fromstring("<library><book id='1' lang='en'>Ulysses</book></library>")
root.tag # "library"
root[0].get("id") # "1"
root[0].attrib # {"id": "1", "lang": "en"}
root[0].text # "Ulysses"
root.xpath("count(//book)") # 1.0
[b.text for b in root.findall("book")] # ["Ulysses"]
tostring(root[0], encoding="unicode") # "<book id=\"1\" lang=\"en\">Ulysses</book>"
Documents own the tree; use the context manager or close():
from leptris import parse
with parse("catalog.xml") as doc:
doc.xpath("//book[@lang='en']")
Namespaces, variables, canonical XML and streaming:
root.xpath("//x:item", namespaces={"x": "urn:ex"})
root.xpath("//book[@id=$id]", variables={"id": "2"})
c14n(root, exclusive=True)
from leptris import sax
sax.parse(xml, handler) # one-shot
with sax.StreamingParser(handler) as parser: # push, constant memory
parser.feed(chunk, final=last)
XSLT and XPath version support
leptris.XSLT(stylesheet) compiles once, applies to any Document, and
returns a Document; leptris.XPath(expression) compiles an XPath for
repeated evaluation. Which language constructs work is decided by the
engine — the matrix below is measured against libleptris 1.9.32
(audited through this binding; the upstream gap ledger is
leptris/leptris#685).
| language | status | notes |
|---|---|---|
| XSLT 1.0 | full | libxslt conformance suite 205/205 upstream; EXSLT math/set/str/date included |
| XSLT 2.0 | partial | ✓ for-each-group, analyze-string + regex-group(), xsl:number formats, xsl:assert, xsl:sequence (multi-item), xsl:perform-sort · ✗ xsl:function, tunnel parameters, shadow attributes, xsl:result-document, @separator |
| XSLT 3.0 | increments | ✓ try/catch (with $err:description), accumulator (gated by xsl:mode use-accumulators), iterate + break + on-completion, on-empty, evaluate, grouping, modes, where-populated, on-non-empty, next-match, fork, @start-at, composite keys, tunnel params, copy/@select, xsl:namespace, xsl:document, @default, merge, result-document (writes the href target), character maps · ✗ package, xsl:map, xsl:evaluate with-params, next-iteration chaining |
| XPath 1.0 | full | complete core function library |
| XPath 2.0 | grammar complete | ✓ quantified (some/every), set algebra (union/intersect/except), node comparisons (is, <<, >>), (), ends-with, deep-equal, value comparisons, cast/castable/treat/instance of, function items + HOFs (1.9.73+) · function slices by group (sequences, regex, math:, strings/QNames/URIs, dates, xs: constructors); remaining: format-date/format-time, JSON, map:/array: constructors · format-number works in plain XPath since 1.9.80 |
| XPath 3.1 | lane 0 | ✓ let, simple map !, arrow =>, string concat || — through both XPath() and XSLT · ✗ function items, inline functions, maps, arrays, string constructors |
| XQuery | 1.0 core + 3.x increments | leptris.XQuery(query) — FLWOR (for/let/where/order by/return/group by, positional at, tumbling/sliding windows), prolog (declare variable/namespace/function local:*), constructors, doc()/collection(), try/catch, typeswitch — libleptris 1.9.68+; 3.1 remainder (maps/arrays, modules) tracked in #684 |
XQuery 1.0 core is a first-class API since libleptris 1.9.64:
from leptris import Document, XQuery
with Document.parse("<r><item v='1'>alpha</item><item v='5'>beta</item></r>") as doc:
XQuery("for $i in //item where $i/@v > 1 return string($i)")(doc) # ['beta']
XQuery("declare variable $n := 3; <out>{$n * 2}</out>")(doc) # '<out>6</out>'
XQuery("declare function local:dbl($x) { $x * 2 }; local:dbl(4)")(doc) # 8.0
XPath 3.1 composition and XSLT 3.0 instructions flow through the existing API with zero binding change:
from leptris import Document, XPath, XSLT, tostring
with Document.parse("<r><item v='1'>alpha</item><item v='5'>beta</item></r>") as doc:
doc.getroot().xpath("let $n := //item[2] return $n/@v") # ['5']
doc.getroot().xpath("(//item ! string(.)) => count()") # 2.0
style = XSLT("""<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode use-accumulators="depth"/>
<xsl:accumulator name="depth" initial-value="0">
<xsl:accumulator-rule match="*" phase="start" select="$value + 1"/>
<xsl:accumulator-rule match="*" phase="end" select="$value - 1"/>
</xsl:accumulator>
<xsl:template match="/"><o>
<xsl:iterate select="//item">
<i d="{accumulator-before('depth')}"/>
</xsl:iterate>
</o></xsl:template>
</xsl:stylesheet>""")
print(tostring(style(doc), encoding="unicode"))
# <o><i d="2"/><i d="2"/></o> # items sit at depth 2 (r → item)
Unsupported constructs fail at XSLT() compile time or at evaluation
with LeptrisError — except two instructions that still produce
empty output instead of an error (xsl:map/xsl:map-entry, and
xsl:value-of/@separator is ignored); tracked in the
#685/#690 ledgers above.
HTML parsing
leptris.html (libleptris 1.9.75+) — tolerant HTML in the shape of
lxml's etree.HTMLParser: implied end tags, void elements,
case-insensitive names, unquoted attributes, the named-entity
table, and a synthesized <html>/<head>/<body> wrapper:
from leptris import html
r = html.fromstring("<p>hello <b>world") # <html><head/><body><p>hello <b>world</b></p></body></html>
with html.document("<td>c") as doc:
doc.xpath("count(//td)") # 1.0
Since libleptris 1.9.76 the output is byte-exact with lxml's
etree.HTMLParser (minimized attributes are empty strings; no
empty <head/> is emitted) — leptris/leptris#813.
Migrating from lxml
| lxml | leptris | Notes |
|---|---|---|
etree.fromstring / etree.XML |
fromstring / XML |
|
etree.parse |
parse |
paths and file-likes; no URLs |
etree.tostring(elem, …) |
tostring(elem, …) |
bytes by default, encoding="unicode" for str |
elem.tag / .text / .tail |
same | tag uses {uri}local Clark notation; CDATA merges into text (lxml's default parser behavior) |
elem.attrib / .get() / .keys() / .items() |
same | attrib is a read-only Mapping |
elem.getparent/getnext/getprevious |
same | |
elem[i], len(elem), iteration, slices |
same | indexing is child indexing, never attribute lookup |
elem.iter() / .iterdescendants() / .itertext() |
same | elements only (ElementTree semantics); lxml's iter() also yields comments/PIs |
elem.find/findall/findtext |
same | accepts full XPath 1.0 — a superset of ElementPath — including {uri}local names |
elem.xpath(expr, namespaces=…) |
same | plus variables={…} (leptris extension) |
etree.c14n / etree.XInclude |
c14n(…) / doc.process_xinclude() |
|
etree.XMLSyntaxError |
ParseError |
XPath failures raise XPathError; both subclass LeptrisError |
etree.Element, SubElement, append, set, remove |
not exposed | libleptris has partial mutation upstream (node content setters, set_root, remove_children) — not surfaced here; build trees elsewhere |
| document-level comments / PIs | doc.toplevel_comments() / doc.toplevel_pis() |
prolog then epilog; requires libleptris 1.9.3+ |
etree.iterparse |
leptris.iterparse(source, full_document=False) |
bounded by the largest subtree; yields ("end", element); elements borrowed until the next yield; tags resolve namespaces (Clark notation, libleptris 1.9.4+). Truncated or malformed input raises ParseError (both modes, libleptris 1.9.15+). full_document=True yields every element in completion order |
| smart strings | plain str |
XPath string/attribute results |
elem.nsmap |
absent | use elem.namespace / elem.prefix and xpath(namespaces=…) |
etree.XPath compiled objects |
leptris.XPath(expression) |
compile once, evaluate many; contexts, namespaces, and variables supported |
etree.XSLT |
leptris.XSLT(stylesheet) |
compile once, apply to any Document — see the version support matrix above |
parser options (resolve_entities, …) |
absent | libleptris 1.2.0 has no per-parse options |
elem.sourceline |
same | requires libleptris 1.3.0+ |
| undeclared XPath prefix | raises in lxml | evaluates to an empty nodeset here |
| ATTLIST default attributes | applied by lxml's default parser | excluded by default (ElementTree-like; XML 1.0 §5 permits either) — Document.parse(xml, attribute_defaults=True) opts in |
| declared non-UTF-8 bytes (UTF-16, latin-1, …) | auto-detected | auto-detected — declared encodings route through the converter, others retry on failure (libleptris 1.9.15+) |
parser options (remove_blank_text, …) |
etree.XMLParser(remove_blank_text=True) |
Document.parse(xml, remove_blank_text=True) — ~35% faster on pretty-printed input; also attribute_defaults=True, recover=True |
Layout
leptris/_ffi.py— cdef mirror of the public headers + loader (the only place libleptris is declared)leptris/_leptrisaccel.c— the C accelerator (abi3): allocates Elements and runs the hot accessors, subtree iteration, the parse and serialization seams, and the per-document element registry; bound to libleptris by the positional protocol inelement.pyleptris/element.py,document.py,node.py,xpath.py— the Python surface: queries, walks, documents;node.pyexposes the full DOM (comments, CDATA, PIs) beneath the ElementTree shapeleptris/api.py—fromstring/parse/tostring/c14n/iterparseleptris/sax.py— SAX one-shot and streamingtests/— pytest suite (pytestwithLEPTRIS_LIB_PATHset)benchmarks/— matrix vs lxml/ElementTree/minidom (pip install .[bench], thenpython -m benchmarks.matrix)
Memory model
The Document owns the whole tree and its pool. Accessor strings
are copied into Python str at the boundary, so nothing depends on
document lifetime after a call returns. Elements keep a reference to
their Document, so the pool cannot be freed while any wrapper is
alive. Prefer explicit close() / the context manager; __del__ is
a refcounting safety net, not a contract. Using an element after its
document is closed raises LeptrisError.
Versioning
libleptris-version.txt pins the library release the binding is
built and tested against. Since 1.9.76.0 the package version is
{c-full-semver}.{patch} — the pinned libleptris version plus
a binding-local patch counter: lib 1.9.76 → 1.9.76.0, then
1.9.76.1 for binding-only fixes against the same pin, resetting
the patch whenever the pin moves. (1.2.0–1.27.1 were the interim
own-semver line.) pyproject.toml and leptris/__init__.py must
agree at release time.
Publishing
Releases publish to PyPI via .github/workflows/release.yml, using
PyPI trusted publishing (no stored credentials). The workflow
runs on manual dispatch (ships the version in pyproject.toml) and
is called by the libleptris release flow (publish: true), so every
libleptris release ships the wheel.
Local development
python3 -m venv .venv
./.venv/bin/pip install --upgrade build pytest cffi
./.venv/bin/pip install -e .[test,bench]
LEPTRIS_LIB_PATH=/path/to/libleptris.dylib ./.venv/bin/python -m pytest tests/ -q
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 leptris-1.9.86.0.tar.gz.
File metadata
- Download URL: leptris-1.9.86.0.tar.gz
- Upload date:
- Size: 69.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22a1f7b51045cd9ffd8cb90f12165dd82df351eb93e3ec2ede19077c7b2710e1
|
|
| MD5 |
23d09669fb83f445dd54874b634c9bd8
|
|
| BLAKE2b-256 |
4dacfbdec200d63c6d0b756c1c60d10c86e619b207dcbef24b238bd49ba4f199
|
Provenance
The following attestation bundles were made for leptris-1.9.86.0.tar.gz:
Publisher:
release.yml on leptris/leptris-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leptris-1.9.86.0.tar.gz -
Subject digest:
22a1f7b51045cd9ffd8cb90f12165dd82df351eb93e3ec2ede19077c7b2710e1 - Sigstore transparency entry: 2722394569
- Sigstore integration time:
-
Permalink:
leptris/leptris-py@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/leptris
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file leptris-1.9.86.0-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: leptris-1.9.86.0-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 49.3 kB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87edd2f0947cf8fbe45702b8ede61336e10a7a059d4303b191765ab2c67f7223
|
|
| MD5 |
4f9bb83dd82f32360c40a8023af3dcdc
|
|
| BLAKE2b-256 |
d621fee4b186cd03833fc496f20f8e40d683dc5cfdcf8b9ce1214ad6864fd4f9
|
Provenance
The following attestation bundles were made for leptris-1.9.86.0-cp39-abi3-win_amd64.whl:
Publisher:
release.yml on leptris/leptris-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leptris-1.9.86.0-cp39-abi3-win_amd64.whl -
Subject digest:
87edd2f0947cf8fbe45702b8ede61336e10a7a059d4303b191765ab2c67f7223 - Sigstore transparency entry: 2722395553
- Sigstore integration time:
-
Permalink:
leptris/leptris-py@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/leptris
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file leptris-1.9.86.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: leptris-1.9.86.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 105.6 kB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9d98c2d48db44d7ad6cb2ebe3b477d940062e3721c1ad085911cb160c3c489e
|
|
| MD5 |
eb1b08494d6ac630295adc2936ad71c1
|
|
| BLAKE2b-256 |
024aa958fadbc4aa3c5822d21b61ebe7ce455b01c22e9956afdccd2236b6c007
|
Provenance
The following attestation bundles were made for leptris-1.9.86.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on leptris/leptris-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leptris-1.9.86.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
c9d98c2d48db44d7ad6cb2ebe3b477d940062e3721c1ad085911cb160c3c489e - Sigstore transparency entry: 2722396404
- Sigstore integration time:
-
Permalink:
leptris/leptris-py@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/leptris
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file leptris-1.9.86.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: leptris-1.9.86.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 101.6 kB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6994cf474bc57112f7bd5e0ea33d503baf04ff42c1cbc0fe8b1524eb5c5ea7da
|
|
| MD5 |
2ebc2c0ae9646effa638922bedd4690e
|
|
| BLAKE2b-256 |
ccac739497346ce98e429dd43a5d23a5c58f331c186531a9a7dc479c3e48ca0a
|
Provenance
The following attestation bundles were made for leptris-1.9.86.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on leptris/leptris-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leptris-1.9.86.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
6994cf474bc57112f7bd5e0ea33d503baf04ff42c1cbc0fe8b1524eb5c5ea7da - Sigstore transparency entry: 2722395312
- Sigstore integration time:
-
Permalink:
leptris/leptris-py@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/leptris
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file leptris-1.9.86.0-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: leptris-1.9.86.0-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 47.7 kB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
edcbd5737eae90801e80edcca661b059015762ba7ad1985c127f1a507e4fc7ea
|
|
| MD5 |
06186ae2ebb219eb9b39d4dccd0fe735
|
|
| BLAKE2b-256 |
53a3c6ac8401230a2842e7494ba59899672af52b2f4e980a6b40acff070a7a0a
|
Provenance
The following attestation bundles were made for leptris-1.9.86.0-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on leptris/leptris-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leptris-1.9.86.0-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
edcbd5737eae90801e80edcca661b059015762ba7ad1985c127f1a507e4fc7ea - Sigstore transparency entry: 2722396776
- Sigstore integration time:
-
Permalink:
leptris/leptris-py@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/leptris
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file leptris-1.9.86.0-cp39-abi3-macosx_10_9_x86_64.whl.
File metadata
- Download URL: leptris-1.9.86.0-cp39-abi3-macosx_10_9_x86_64.whl
- Upload date:
- Size: 47.1 kB
- Tags: CPython 3.9+, macOS 10.9+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3176ae12cbebd1bec69b032703240e48080bacc8d83c7da17e57e02620fc7365
|
|
| MD5 |
fb90ba56172e6a334ef53adb1c98bb1e
|
|
| BLAKE2b-256 |
2af40d17b0ef2bf2d6fe048d895ab4808b6c3c34dcbdb73151f33da5e084f5f3
|
Provenance
The following attestation bundles were made for leptris-1.9.86.0-cp39-abi3-macosx_10_9_x86_64.whl:
Publisher:
release.yml on leptris/leptris-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leptris-1.9.86.0-cp39-abi3-macosx_10_9_x86_64.whl -
Subject digest:
3176ae12cbebd1bec69b032703240e48080bacc8d83c7da17e57e02620fc7365 - Sigstore transparency entry: 2722394894
- Sigstore integration time:
-
Permalink:
leptris/leptris-py@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/leptris
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83b442880c2d9c8fdbcc5d144c44b816995278e7 -
Trigger Event:
workflow_dispatch
-
Statement type: