prosemirror-py
This package provides Python implementations of the following ProseMirror packages:
prosemirror-modelversion 1.25.4prosemirror-transformversion 1.11.0prosemirror-test-builderversion 1.1.1prosemirror-schema-basicversion 1.2.4prosemirror-schema-listversion 1.5.1 (node specs andwrapRangeInListonly; command functions that depend onprosemirror-stateare excluded)
The original implementation has been followed as closely as possible during translation to simplify keeping this package up-to-date with any upstream changes.
Why?
ProseMirror provides a powerful toolkit for building rich-text editors, but it's JavaScript-only. Until now, the only option for manipulating and working with ProseMirror documents from Python was to embed a JS runtime. With this translation, you can now define schemas, parse documents, and apply transforms directly via a native Python API.
Status
The full ProseMirror test suite has been translated and passes. This project only supports Python 3. The code has type annotations to support mypy or other typechecking tools.
Usage
Since this library is a direct port, the best place to learn how to use it is the official ProseMirror documentation. Here is a simple example using the included "basic" schema:
from prosemirror.transform import Transform
from prosemirror.schema.basic import schema
# Create a document containing a single paragraph with the text "Hello, world!"
doc = schema.node(
"doc", {}, [schema.node("paragraph", {}, [schema.text("Hello, world!")])]
)
# Create a Transform which will be applied to the document.
tr = Transform(doc)
# Delete the text from position 3 to 5. Adds a ReplaceStep to the transform.
tr.delete(3, 5)
# Make the first three characters bold. Adds an AddMarkStep to the transform.
tr.add_mark(1, 4, schema.mark("strong"))
# This transform can be converted to JSON to be sent and applied elsewhere.
assert [step.to_json() for step in tr.steps] == [
{"stepType": "replace", "from": 3, "to": 5},
{"stepType": "addMark", "mark": {"type": "strong"}, "from": 1, "to": 4},
]
# The resulting document can also be converted to JSON.
assert tr.doc.to_json() == {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{"type": "text", "marks": [{"type": "strong"}], "text": "Heo"},
{"type": "text", "text": ", world!"},
],
}
],
}
Differences from Upstream
While the translation follows the original TypeScript implementation as closely as possible, some adaptations were necessary for Python. These are documented here for reference.
Naming Conventions
Python's snake_case naming is used throughout:
camelCasemethods/properties becomesnake_case(e.g.nodeSize->node_size,isBlock->is_block,textBetween->text_between)from(a Python keyword) becomesfrom_in parameter names and theFragment.from_()static method
DOM Handling
The upstream uses browser DOM APIs. The Python port uses
lxml for parsing and a lightweight custom Element /
DocumentFragment model for serialization:
DOMParser: Useslxml.htmlfor HTML parsing. Text nodes are wrapped in<lxmltext>pseudo-elements since lxml doesn't represent text nodes as separate child elements. CSS selector matching useslxml.cssselect.DOMSerializer: Outputs HTML strings via customElementandDocumentFragmentclasses rather than creating real DOM nodes.- XML namespaces: Not supported (raises
NotImplementedError). This only affects SVG or MathML node serialization.
String Length and Slicing (UTF-16 Semantics)
JavaScript strings use UTF-16 encoding, so string.length counts UTF-16 code
units (surrogate pairs count as 2). The Python port preserves these semantics
using a text_length() helper and UTF-16 encode/decode for slicing in:
Node.node_size/TextNode.node_sizeTextNode.cut()TextNode.text_between()Fragment.findIndex()/Fragment.cut()diff.py(character-by-character comparison)
Deep Comparison
The upstream uses a custom compareDeep function for recursive comparison of
arrays/objects. The Python port uses native ==, which already performs deep
comparison of dicts and lists.
Resolve Cache
The upstream uses a WeakMap<Node, ResolveCache> for caching resolved
positions. Python uses a dict[int, _ResolveCache] keyed by id(doc) with a
weakref.ref callback to clean up entries when the document node is garbage
collected.
Type System
- TypeScript interfaces (
NodeSpec,MarkSpec,ParseOptions, etc.) are translated asTypedDictor frozendataclasstypes. - Union types use
X | Ysyntax (Python 3.10+).
Additional Conveniences
These are Python-specific additions not present in the upstream:
Fragment.from_json()accepts a JSONstrand parses it automatically.from_dom.pyincludes afrom_html()helper to parse an HTML string directly to a ProseMirror document.DOMSerializeroutput type is namedHTMLOutputSpec(instead ofDOMOutputSpec) to reflect that it produces HTML strings.
AI Disclosure
The initial version of this translation was written manually in 2019. AI is now used to help keep this translation up-to-date with upstream changes.
Metadata
Release files for prosemirror 0.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| prosemirror-0.6.1.tar.gz | 76.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| prosemirror-0.6.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 144.1 kB
Release files / prosemirror-0.6.1.tar.gz
| Download URL | prosemirror-0.6.1.tar.gz |
|---|---|
| Size | 76.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
eec45a4f35d03ddb58700199292646c34b334bbad385a21679fc7a8d181cd272
|
|
BLAKE2b-256 checksum How to use checksums |
d68a36cd9224f70441fd66d428f7cad650923d949d0d9395cbae82aab6b78df5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / prosemirror-0.6.1-py3-none-any.whl
| Download URL | prosemirror-0.6.1-py3-none-any.whl |
|---|---|
| Size | 67.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f9d38313a72af1c579cbb87beac3a765f399416afc4567cb016aca53ec4cdae6
|
|
BLAKE2b-256 checksum How to use checksums |
8c6bff4f2362320c53ea989ef32e4ac978233b65ffb2e6e3131aea7860c740cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|