tiptap-python-utils 0.5.0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tiptap_python_utils-0.5.0/src/tiptap_python_utils.egg-info → tiptap_python_utils-0.6.0}/PKG-INFO +47 -58
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/README.md +45 -56
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/pyproject.toml +2 -2
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/__init__.py +2 -0
- tiptap_python_utils-0.6.0/src/tiptap_python_utils/task.py +55 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0/src/tiptap_python_utils.egg-info}/PKG-INFO +47 -58
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils.egg-info/SOURCES.txt +2 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_compat_imports.py +1 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_public_api.py +1 -0
- tiptap_python_utils-0.6.0/tests/test_task_namespace.py +90 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/LICENSE +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/MANIFEST.in +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/setup.cfg +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/codec/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/codec/raw.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/codec/reader.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/codec/writer.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/content.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/contract/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/contract/key.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/contract/kind.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/contract/policy.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/exceptions.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/identity.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/base.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/nodes.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/payload.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/registry.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/py.typed +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/select/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/select/selection.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/shared/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/shared/families.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/shared/fingerprint.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/shared/identity.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/tasks/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/tasks/query.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/text/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/text/extract.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/tree/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/tree/path.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/types.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/walk/__init__.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/walk/traversal.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils.egg-info/dependency_links.txt +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils.egg-info/requires.txt +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils.egg-info/top_level.txt +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_codec_raw.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_content.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_extract.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_filter.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_generic_helpers.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_mutations.py +0 -0
- {tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/tests/test_traverser.py +0 -0
{tiptap_python_utils-0.5.0/src/tiptap_python_utils.egg-info → tiptap_python_utils-0.6.0}/PKG-INFO
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tiptap_python_utils
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Python utilities for
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Pure-Python utilities for processing TipTap JSON on the server side. Parse, traverse, edit, and serialize TipTap documents — no JavaScript bridge required. Zero runtime dependencies, Python 3.9+.
|
|
5
5
|
Author: tiptap_python_utils contributors
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
@@ -56,23 +56,10 @@ Dynamic: license-file
|
|
|
56
56
|
[](https://github.com/tugkanpilka/tiptap-python-utils/actions/workflows/ci.yml)
|
|
57
57
|
[](LICENSE)
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
small helpers for traversal, immutable edits, visible text extraction, task
|
|
64
|
-
queries, and shared-node synchronization.
|
|
65
|
-
|
|
66
|
-
- **Zero runtime dependencies.** Standard library only.
|
|
67
|
-
- **Python 3.9+.** Tested on 3.9, 3.10, 3.11, 3.12, 3.13.
|
|
68
|
-
- **Lossless round trip.** Unknown node kinds and any extra fields are preserved.
|
|
69
|
-
- **Immutable AST.** All mutations return new instances via a fluent selection API.
|
|
70
|
-
|
|
71
|
-
## Install
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
pip install tiptap_python_utils
|
|
75
|
-
```
|
|
59
|
+
TipTap is a JavaScript editor. If your backend is Python and you need to
|
|
60
|
+
process TipTap JSON — extract text, query tasks, sync shared nodes — this
|
|
61
|
+
library does it in pure Python with zero dependencies. No JS bridge, no
|
|
62
|
+
Node.js subprocess.
|
|
76
63
|
|
|
77
64
|
## Quick Start
|
|
78
65
|
|
|
@@ -94,8 +81,24 @@ raw = {
|
|
|
94
81
|
updated = Content.require(raw).where_id("p1").leaf().text("New").dump()
|
|
95
82
|
```
|
|
96
83
|
|
|
84
|
+
## Features
|
|
85
|
+
|
|
86
|
+
- **Zero runtime dependencies.** Standard library only.
|
|
87
|
+
- **Python 3.9+.** Tested on 3.9, 3.10, 3.11, 3.12, 3.13.
|
|
88
|
+
- **Lossless round trip.** Unknown node kinds and any extra fields are preserved.
|
|
89
|
+
- **Immutable AST.** All mutations return new instances via a fluent selection API.
|
|
90
|
+
|
|
91
|
+
## Install
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install tiptap_python_utils
|
|
95
|
+
```
|
|
96
|
+
|
|
97
97
|
## Three Ways to Load a Document
|
|
98
98
|
|
|
99
|
+
Pick a constructor by how much you trust the input — lenient, strict, or
|
|
100
|
+
auto-wrapping a bare node into a `doc`.
|
|
101
|
+
|
|
99
102
|
| Constructor | When to use | On invalid input |
|
|
100
103
|
|---|---|---|
|
|
101
104
|
| `Content.parse(raw)` | Lenient — `raw` may be `None`, a string, or a dict | Returns a `Content` with `root=None` |
|
|
@@ -104,7 +107,8 @@ updated = Content.require(raw).where_id("p1").leaf().text("New").dump()
|
|
|
104
107
|
|
|
105
108
|
## Lossless Round Trip
|
|
106
109
|
|
|
107
|
-
Parsing never silently drops fields
|
|
110
|
+
Parsing never silently drops fields — custom nodes and unknown keys survive a
|
|
111
|
+
parse-then-serialize cycle byte-for-byte. Two mechanisms preserve information:
|
|
108
112
|
|
|
109
113
|
- `Node.extra` stores top-level keys that aren't part of the known schema
|
|
110
114
|
(e.g. custom node attributes, vendor-specific keys).
|
|
@@ -125,7 +129,8 @@ assert Content.require(raw).to_dict() == raw # byte-for-byte
|
|
|
125
129
|
|
|
126
130
|
## Typed Nodes
|
|
127
131
|
|
|
128
|
-
Build typed nodes directly and serialize them back to
|
|
132
|
+
Build typed nodes directly in Python and serialize them back to
|
|
133
|
+
TipTap-compatible JSON.
|
|
129
134
|
|
|
130
135
|
```python
|
|
131
136
|
from tiptap_python_utils import Content, Paragraph, Text
|
|
@@ -136,8 +141,8 @@ doc = Content.wrap(node.raw())
|
|
|
136
141
|
|
|
137
142
|
## Selection and Editing
|
|
138
143
|
|
|
139
|
-
The fluent selection API is the single home for mutation
|
|
140
|
-
|
|
144
|
+
The fluent selection API is the single home for mutation: every method returns
|
|
145
|
+
a new `Content`, so the original is never mutated.
|
|
141
146
|
|
|
142
147
|
### Select by id or kind
|
|
143
148
|
|
|
@@ -206,6 +211,9 @@ content.replace_by_id("p1", {
|
|
|
206
211
|
|
|
207
212
|
## Text Extraction
|
|
208
213
|
|
|
214
|
+
Pull the visible plain text out of a document — useful for search indexing,
|
|
215
|
+
word counts, or previews.
|
|
216
|
+
|
|
209
217
|
```python
|
|
210
218
|
from tiptap_python_utils import Content, text_slices, visible_text, word_count
|
|
211
219
|
|
|
@@ -218,6 +226,9 @@ slices = text_slices(content, context=True)
|
|
|
218
226
|
|
|
219
227
|
## Tasks
|
|
220
228
|
|
|
229
|
+
Query task lists in a document — find every task item or check whether any are
|
|
230
|
+
still open.
|
|
231
|
+
|
|
221
232
|
```python
|
|
222
233
|
from tiptap_python_utils import Content, has_open_tasks, open_tasks
|
|
223
234
|
|
|
@@ -240,6 +251,9 @@ task.shared_id # sharedId attr, if any
|
|
|
240
251
|
|
|
241
252
|
## Shared-Node Synchronization
|
|
242
253
|
|
|
254
|
+
Keep copies of the same logical node (linked by `sharedId`) in sync — collect
|
|
255
|
+
canonical bodies, then rewrite every matching node from them.
|
|
256
|
+
|
|
243
257
|
`Content.shared_families()` collects canonical bodies grouped by `sharedId` into
|
|
244
258
|
a `SharedFamilies` value object. `Content.sync_shared(families)` rewrites every
|
|
245
259
|
matching node in the document from those canonical bodies, preserving
|
|
@@ -278,17 +292,6 @@ Related helpers on `Content`:
|
|
|
278
292
|
- `node.with_shared_id(sid)` — stamp a sharedId onto a node (returns a new node).
|
|
279
293
|
- `new_shared_id()` — mint a fresh `shared-…` identifier.
|
|
280
294
|
|
|
281
|
-
## Architecture (one paragraph)
|
|
282
|
-
|
|
283
|
-
The package is layered: `contract` (key/kind/policy primitives) → `model`
|
|
284
|
-
(immutable AST with a registry of node classes; unknown kinds round-trip via
|
|
285
|
-
`Unknown`) → `codec` (raw I/O in `raw.py`, hydration in `reader.py`, dump in
|
|
286
|
-
`writer.py`) → `walk` & `tree` (traversal + path-based replacement on the
|
|
287
|
-
immutable tree) → `select` (fluent `Selection` — the single home for mutation)
|
|
288
|
-
→ `content` (public facade) → `text` / `tasks` / `shared` (user-facing
|
|
289
|
-
workflows built on `Content`). All nodes are `@dataclass(frozen=True)`;
|
|
290
|
-
mutations return new instances.
|
|
291
|
-
|
|
292
295
|
## Public API
|
|
293
296
|
|
|
294
297
|
Common imports are available from the package root:
|
|
@@ -311,35 +314,21 @@ from tiptap_python_utils import (
|
|
|
311
314
|
)
|
|
312
315
|
```
|
|
313
316
|
|
|
314
|
-
## Stability
|
|
315
|
-
|
|
316
|
-
The project is pre-1.0; minor versions may include breaking changes. See
|
|
317
|
-
[CHANGELOG.md](CHANGELOG.md) for what changed and when.
|
|
318
|
-
|
|
319
|
-
## Development
|
|
320
|
-
|
|
321
|
-
```bash
|
|
322
|
-
python -m venv .venv
|
|
323
|
-
. .venv/bin/activate
|
|
324
|
-
python -m pip install -e ".[dev]"
|
|
325
|
-
pytest -q
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
Build and validate a release artifact:
|
|
329
|
-
|
|
330
|
-
```bash
|
|
331
|
-
python -m build
|
|
332
|
-
python -m twine check dist/*
|
|
333
|
-
```
|
|
334
|
-
|
|
335
317
|
## Contributing
|
|
336
318
|
|
|
337
319
|
Issues and pull requests are welcome. Please read
|
|
338
|
-
[CONTRIBUTING.md](CONTRIBUTING.md) for the local setup
|
|
339
|
-
and open an issue at
|
|
320
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for the local setup, architecture overview,
|
|
321
|
+
and release checklist, and open an issue at
|
|
340
322
|
[github.com/tugkanpilka/tiptap-python-utils/issues](https://github.com/tugkanpilka/tiptap-python-utils/issues)
|
|
341
|
-
before
|
|
323
|
+
before opening a pull request so we can align on the approach.
|
|
342
324
|
|
|
343
325
|
## License
|
|
344
326
|
|
|
345
327
|
MIT — see [LICENSE](LICENSE).
|
|
328
|
+
|
|
329
|
+
## Stability
|
|
330
|
+
|
|
331
|
+
The project is pre-1.0; minor versions may include breaking changes. See
|
|
332
|
+
[CHANGELOG.md](CHANGELOG.md) for what changed and when.
|
|
333
|
+
</content>
|
|
334
|
+
</invoke>
|
|
@@ -5,23 +5,10 @@
|
|
|
5
5
|
[](https://github.com/tugkanpilka/tiptap-python-utils/actions/workflows/ci.yml)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
small helpers for traversal, immutable edits, visible text extraction, task
|
|
13
|
-
queries, and shared-node synchronization.
|
|
14
|
-
|
|
15
|
-
- **Zero runtime dependencies.** Standard library only.
|
|
16
|
-
- **Python 3.9+.** Tested on 3.9, 3.10, 3.11, 3.12, 3.13.
|
|
17
|
-
- **Lossless round trip.** Unknown node kinds and any extra fields are preserved.
|
|
18
|
-
- **Immutable AST.** All mutations return new instances via a fluent selection API.
|
|
19
|
-
|
|
20
|
-
## Install
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
pip install tiptap_python_utils
|
|
24
|
-
```
|
|
8
|
+
TipTap is a JavaScript editor. If your backend is Python and you need to
|
|
9
|
+
process TipTap JSON — extract text, query tasks, sync shared nodes — this
|
|
10
|
+
library does it in pure Python with zero dependencies. No JS bridge, no
|
|
11
|
+
Node.js subprocess.
|
|
25
12
|
|
|
26
13
|
## Quick Start
|
|
27
14
|
|
|
@@ -43,8 +30,24 @@ raw = {
|
|
|
43
30
|
updated = Content.require(raw).where_id("p1").leaf().text("New").dump()
|
|
44
31
|
```
|
|
45
32
|
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- **Zero runtime dependencies.** Standard library only.
|
|
36
|
+
- **Python 3.9+.** Tested on 3.9, 3.10, 3.11, 3.12, 3.13.
|
|
37
|
+
- **Lossless round trip.** Unknown node kinds and any extra fields are preserved.
|
|
38
|
+
- **Immutable AST.** All mutations return new instances via a fluent selection API.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install tiptap_python_utils
|
|
44
|
+
```
|
|
45
|
+
|
|
46
46
|
## Three Ways to Load a Document
|
|
47
47
|
|
|
48
|
+
Pick a constructor by how much you trust the input — lenient, strict, or
|
|
49
|
+
auto-wrapping a bare node into a `doc`.
|
|
50
|
+
|
|
48
51
|
| Constructor | When to use | On invalid input |
|
|
49
52
|
|---|---|---|
|
|
50
53
|
| `Content.parse(raw)` | Lenient — `raw` may be `None`, a string, or a dict | Returns a `Content` with `root=None` |
|
|
@@ -53,7 +56,8 @@ updated = Content.require(raw).where_id("p1").leaf().text("New").dump()
|
|
|
53
56
|
|
|
54
57
|
## Lossless Round Trip
|
|
55
58
|
|
|
56
|
-
Parsing never silently drops fields
|
|
59
|
+
Parsing never silently drops fields — custom nodes and unknown keys survive a
|
|
60
|
+
parse-then-serialize cycle byte-for-byte. Two mechanisms preserve information:
|
|
57
61
|
|
|
58
62
|
- `Node.extra` stores top-level keys that aren't part of the known schema
|
|
59
63
|
(e.g. custom node attributes, vendor-specific keys).
|
|
@@ -74,7 +78,8 @@ assert Content.require(raw).to_dict() == raw # byte-for-byte
|
|
|
74
78
|
|
|
75
79
|
## Typed Nodes
|
|
76
80
|
|
|
77
|
-
Build typed nodes directly and serialize them back to
|
|
81
|
+
Build typed nodes directly in Python and serialize them back to
|
|
82
|
+
TipTap-compatible JSON.
|
|
78
83
|
|
|
79
84
|
```python
|
|
80
85
|
from tiptap_python_utils import Content, Paragraph, Text
|
|
@@ -85,8 +90,8 @@ doc = Content.wrap(node.raw())
|
|
|
85
90
|
|
|
86
91
|
## Selection and Editing
|
|
87
92
|
|
|
88
|
-
The fluent selection API is the single home for mutation
|
|
89
|
-
|
|
93
|
+
The fluent selection API is the single home for mutation: every method returns
|
|
94
|
+
a new `Content`, so the original is never mutated.
|
|
90
95
|
|
|
91
96
|
### Select by id or kind
|
|
92
97
|
|
|
@@ -155,6 +160,9 @@ content.replace_by_id("p1", {
|
|
|
155
160
|
|
|
156
161
|
## Text Extraction
|
|
157
162
|
|
|
163
|
+
Pull the visible plain text out of a document — useful for search indexing,
|
|
164
|
+
word counts, or previews.
|
|
165
|
+
|
|
158
166
|
```python
|
|
159
167
|
from tiptap_python_utils import Content, text_slices, visible_text, word_count
|
|
160
168
|
|
|
@@ -167,6 +175,9 @@ slices = text_slices(content, context=True)
|
|
|
167
175
|
|
|
168
176
|
## Tasks
|
|
169
177
|
|
|
178
|
+
Query task lists in a document — find every task item or check whether any are
|
|
179
|
+
still open.
|
|
180
|
+
|
|
170
181
|
```python
|
|
171
182
|
from tiptap_python_utils import Content, has_open_tasks, open_tasks
|
|
172
183
|
|
|
@@ -189,6 +200,9 @@ task.shared_id # sharedId attr, if any
|
|
|
189
200
|
|
|
190
201
|
## Shared-Node Synchronization
|
|
191
202
|
|
|
203
|
+
Keep copies of the same logical node (linked by `sharedId`) in sync — collect
|
|
204
|
+
canonical bodies, then rewrite every matching node from them.
|
|
205
|
+
|
|
192
206
|
`Content.shared_families()` collects canonical bodies grouped by `sharedId` into
|
|
193
207
|
a `SharedFamilies` value object. `Content.sync_shared(families)` rewrites every
|
|
194
208
|
matching node in the document from those canonical bodies, preserving
|
|
@@ -227,17 +241,6 @@ Related helpers on `Content`:
|
|
|
227
241
|
- `node.with_shared_id(sid)` — stamp a sharedId onto a node (returns a new node).
|
|
228
242
|
- `new_shared_id()` — mint a fresh `shared-…` identifier.
|
|
229
243
|
|
|
230
|
-
## Architecture (one paragraph)
|
|
231
|
-
|
|
232
|
-
The package is layered: `contract` (key/kind/policy primitives) → `model`
|
|
233
|
-
(immutable AST with a registry of node classes; unknown kinds round-trip via
|
|
234
|
-
`Unknown`) → `codec` (raw I/O in `raw.py`, hydration in `reader.py`, dump in
|
|
235
|
-
`writer.py`) → `walk` & `tree` (traversal + path-based replacement on the
|
|
236
|
-
immutable tree) → `select` (fluent `Selection` — the single home for mutation)
|
|
237
|
-
→ `content` (public facade) → `text` / `tasks` / `shared` (user-facing
|
|
238
|
-
workflows built on `Content`). All nodes are `@dataclass(frozen=True)`;
|
|
239
|
-
mutations return new instances.
|
|
240
|
-
|
|
241
244
|
## Public API
|
|
242
245
|
|
|
243
246
|
Common imports are available from the package root:
|
|
@@ -260,35 +263,21 @@ from tiptap_python_utils import (
|
|
|
260
263
|
)
|
|
261
264
|
```
|
|
262
265
|
|
|
263
|
-
## Stability
|
|
264
|
-
|
|
265
|
-
The project is pre-1.0; minor versions may include breaking changes. See
|
|
266
|
-
[CHANGELOG.md](CHANGELOG.md) for what changed and when.
|
|
267
|
-
|
|
268
|
-
## Development
|
|
269
|
-
|
|
270
|
-
```bash
|
|
271
|
-
python -m venv .venv
|
|
272
|
-
. .venv/bin/activate
|
|
273
|
-
python -m pip install -e ".[dev]"
|
|
274
|
-
pytest -q
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
Build and validate a release artifact:
|
|
278
|
-
|
|
279
|
-
```bash
|
|
280
|
-
python -m build
|
|
281
|
-
python -m twine check dist/*
|
|
282
|
-
```
|
|
283
|
-
|
|
284
266
|
## Contributing
|
|
285
267
|
|
|
286
268
|
Issues and pull requests are welcome. Please read
|
|
287
|
-
[CONTRIBUTING.md](CONTRIBUTING.md) for the local setup
|
|
288
|
-
and open an issue at
|
|
269
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for the local setup, architecture overview,
|
|
270
|
+
and release checklist, and open an issue at
|
|
289
271
|
[github.com/tugkanpilka/tiptap-python-utils/issues](https://github.com/tugkanpilka/tiptap-python-utils/issues)
|
|
290
|
-
before
|
|
272
|
+
before opening a pull request so we can align on the approach.
|
|
291
273
|
|
|
292
274
|
## License
|
|
293
275
|
|
|
294
276
|
MIT — see [LICENSE](LICENSE).
|
|
277
|
+
|
|
278
|
+
## Stability
|
|
279
|
+
|
|
280
|
+
The project is pre-1.0; minor versions may include breaking changes. See
|
|
281
|
+
[CHANGELOG.md](CHANGELOG.md) for what changed and when.
|
|
282
|
+
</content>
|
|
283
|
+
</invoke>
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tiptap_python_utils"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "Python utilities for
|
|
7
|
+
version = "0.6.0"
|
|
8
|
+
description = "Pure-Python utilities for processing TipTap JSON on the server side. Parse, traverse, edit, and serialize TipTap documents — no JavaScript bridge required. Zero runtime dependencies, Python 3.9+."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
11
11
|
license = { file = "LICENSE" }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Public API for TipTap JSON utilities."""
|
|
2
2
|
|
|
3
|
+
from . import task
|
|
3
4
|
from .contract import key, kind
|
|
4
5
|
from .content import Content
|
|
5
6
|
from .exceptions import TiptapValidationError
|
|
@@ -65,6 +66,7 @@ __all__ = [
|
|
|
65
66
|
"open_tasks",
|
|
66
67
|
"registry",
|
|
67
68
|
"syncable_tasks",
|
|
69
|
+
"task",
|
|
68
70
|
"text_slices",
|
|
69
71
|
"tiptap_id",
|
|
70
72
|
"visible_text",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Pure, raw-dict helpers for TipTap ``taskList`` / ``taskItem`` shapes.
|
|
2
|
+
|
|
3
|
+
This module is the raw-dict counterpart to the typed ``tasks`` package:
|
|
4
|
+
``tasks`` works on hydrated ``Content``/``TaskItem`` objects, while ``task``
|
|
5
|
+
deals only with plain TipTap JSON dicts and never imports the model layer.
|
|
6
|
+
|
|
7
|
+
Read as a namespace: ``task.create_list(...)``, ``task.is_list(...)``,
|
|
8
|
+
``task.is_item(...)``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any, List
|
|
14
|
+
|
|
15
|
+
from .contract import key, kind
|
|
16
|
+
|
|
17
|
+
__all__ = ["create_list", "is_item", "is_list"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def create_list(items: List[Any]) -> dict:
|
|
21
|
+
"""Wrap ``items`` in a ``taskList`` block.
|
|
22
|
+
|
|
23
|
+
By design this does **not** copy ``items`` — the same list object is
|
|
24
|
+
stored on the returned block's ``content`` (by reference). Callers may
|
|
25
|
+
keep appending to the original list afterwards and see the change
|
|
26
|
+
reflected here. Do not introduce ``deepcopy``/``list(...)``/``[*items]``
|
|
27
|
+
here: the shared-reference behaviour is part of the contract and is
|
|
28
|
+
pinned by ``tests/test_task_namespace.py``.
|
|
29
|
+
"""
|
|
30
|
+
return {key.TYPE: kind.TASK_LIST, key.CONTENT: items}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def is_list(item: Any) -> bool:
|
|
34
|
+
"""True iff ``item`` is a valid ``taskList`` dict.
|
|
35
|
+
|
|
36
|
+
Safe on missing keys (uses ``.get()``): all three conditions must hold —
|
|
37
|
+
``item`` is a dict, its ``type`` is ``taskList``, and its ``content`` is a
|
|
38
|
+
list.
|
|
39
|
+
"""
|
|
40
|
+
if not isinstance(item, dict):
|
|
41
|
+
return False
|
|
42
|
+
return item.get(key.TYPE) == kind.TASK_LIST and isinstance(
|
|
43
|
+
item.get(key.CONTENT), list
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def is_item(node: Any) -> bool:
|
|
48
|
+
"""True iff ``node`` is a ``taskItem`` dict.
|
|
49
|
+
|
|
50
|
+
Safe on missing keys: ``node`` must be a dict whose ``type`` is
|
|
51
|
+
``taskItem``.
|
|
52
|
+
"""
|
|
53
|
+
if not isinstance(node, dict):
|
|
54
|
+
return False
|
|
55
|
+
return node.get(key.TYPE) == kind.TASK_ITEM
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0/src/tiptap_python_utils.egg-info}/PKG-INFO
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tiptap_python_utils
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Python utilities for
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Pure-Python utilities for processing TipTap JSON on the server side. Parse, traverse, edit, and serialize TipTap documents — no JavaScript bridge required. Zero runtime dependencies, Python 3.9+.
|
|
5
5
|
Author: tiptap_python_utils contributors
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
@@ -56,23 +56,10 @@ Dynamic: license-file
|
|
|
56
56
|
[](https://github.com/tugkanpilka/tiptap-python-utils/actions/workflows/ci.yml)
|
|
57
57
|
[](LICENSE)
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
small helpers for traversal, immutable edits, visible text extraction, task
|
|
64
|
-
queries, and shared-node synchronization.
|
|
65
|
-
|
|
66
|
-
- **Zero runtime dependencies.** Standard library only.
|
|
67
|
-
- **Python 3.9+.** Tested on 3.9, 3.10, 3.11, 3.12, 3.13.
|
|
68
|
-
- **Lossless round trip.** Unknown node kinds and any extra fields are preserved.
|
|
69
|
-
- **Immutable AST.** All mutations return new instances via a fluent selection API.
|
|
70
|
-
|
|
71
|
-
## Install
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
pip install tiptap_python_utils
|
|
75
|
-
```
|
|
59
|
+
TipTap is a JavaScript editor. If your backend is Python and you need to
|
|
60
|
+
process TipTap JSON — extract text, query tasks, sync shared nodes — this
|
|
61
|
+
library does it in pure Python with zero dependencies. No JS bridge, no
|
|
62
|
+
Node.js subprocess.
|
|
76
63
|
|
|
77
64
|
## Quick Start
|
|
78
65
|
|
|
@@ -94,8 +81,24 @@ raw = {
|
|
|
94
81
|
updated = Content.require(raw).where_id("p1").leaf().text("New").dump()
|
|
95
82
|
```
|
|
96
83
|
|
|
84
|
+
## Features
|
|
85
|
+
|
|
86
|
+
- **Zero runtime dependencies.** Standard library only.
|
|
87
|
+
- **Python 3.9+.** Tested on 3.9, 3.10, 3.11, 3.12, 3.13.
|
|
88
|
+
- **Lossless round trip.** Unknown node kinds and any extra fields are preserved.
|
|
89
|
+
- **Immutable AST.** All mutations return new instances via a fluent selection API.
|
|
90
|
+
|
|
91
|
+
## Install
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install tiptap_python_utils
|
|
95
|
+
```
|
|
96
|
+
|
|
97
97
|
## Three Ways to Load a Document
|
|
98
98
|
|
|
99
|
+
Pick a constructor by how much you trust the input — lenient, strict, or
|
|
100
|
+
auto-wrapping a bare node into a `doc`.
|
|
101
|
+
|
|
99
102
|
| Constructor | When to use | On invalid input |
|
|
100
103
|
|---|---|---|
|
|
101
104
|
| `Content.parse(raw)` | Lenient — `raw` may be `None`, a string, or a dict | Returns a `Content` with `root=None` |
|
|
@@ -104,7 +107,8 @@ updated = Content.require(raw).where_id("p1").leaf().text("New").dump()
|
|
|
104
107
|
|
|
105
108
|
## Lossless Round Trip
|
|
106
109
|
|
|
107
|
-
Parsing never silently drops fields
|
|
110
|
+
Parsing never silently drops fields — custom nodes and unknown keys survive a
|
|
111
|
+
parse-then-serialize cycle byte-for-byte. Two mechanisms preserve information:
|
|
108
112
|
|
|
109
113
|
- `Node.extra` stores top-level keys that aren't part of the known schema
|
|
110
114
|
(e.g. custom node attributes, vendor-specific keys).
|
|
@@ -125,7 +129,8 @@ assert Content.require(raw).to_dict() == raw # byte-for-byte
|
|
|
125
129
|
|
|
126
130
|
## Typed Nodes
|
|
127
131
|
|
|
128
|
-
Build typed nodes directly and serialize them back to
|
|
132
|
+
Build typed nodes directly in Python and serialize them back to
|
|
133
|
+
TipTap-compatible JSON.
|
|
129
134
|
|
|
130
135
|
```python
|
|
131
136
|
from tiptap_python_utils import Content, Paragraph, Text
|
|
@@ -136,8 +141,8 @@ doc = Content.wrap(node.raw())
|
|
|
136
141
|
|
|
137
142
|
## Selection and Editing
|
|
138
143
|
|
|
139
|
-
The fluent selection API is the single home for mutation
|
|
140
|
-
|
|
144
|
+
The fluent selection API is the single home for mutation: every method returns
|
|
145
|
+
a new `Content`, so the original is never mutated.
|
|
141
146
|
|
|
142
147
|
### Select by id or kind
|
|
143
148
|
|
|
@@ -206,6 +211,9 @@ content.replace_by_id("p1", {
|
|
|
206
211
|
|
|
207
212
|
## Text Extraction
|
|
208
213
|
|
|
214
|
+
Pull the visible plain text out of a document — useful for search indexing,
|
|
215
|
+
word counts, or previews.
|
|
216
|
+
|
|
209
217
|
```python
|
|
210
218
|
from tiptap_python_utils import Content, text_slices, visible_text, word_count
|
|
211
219
|
|
|
@@ -218,6 +226,9 @@ slices = text_slices(content, context=True)
|
|
|
218
226
|
|
|
219
227
|
## Tasks
|
|
220
228
|
|
|
229
|
+
Query task lists in a document — find every task item or check whether any are
|
|
230
|
+
still open.
|
|
231
|
+
|
|
221
232
|
```python
|
|
222
233
|
from tiptap_python_utils import Content, has_open_tasks, open_tasks
|
|
223
234
|
|
|
@@ -240,6 +251,9 @@ task.shared_id # sharedId attr, if any
|
|
|
240
251
|
|
|
241
252
|
## Shared-Node Synchronization
|
|
242
253
|
|
|
254
|
+
Keep copies of the same logical node (linked by `sharedId`) in sync — collect
|
|
255
|
+
canonical bodies, then rewrite every matching node from them.
|
|
256
|
+
|
|
243
257
|
`Content.shared_families()` collects canonical bodies grouped by `sharedId` into
|
|
244
258
|
a `SharedFamilies` value object. `Content.sync_shared(families)` rewrites every
|
|
245
259
|
matching node in the document from those canonical bodies, preserving
|
|
@@ -278,17 +292,6 @@ Related helpers on `Content`:
|
|
|
278
292
|
- `node.with_shared_id(sid)` — stamp a sharedId onto a node (returns a new node).
|
|
279
293
|
- `new_shared_id()` — mint a fresh `shared-…` identifier.
|
|
280
294
|
|
|
281
|
-
## Architecture (one paragraph)
|
|
282
|
-
|
|
283
|
-
The package is layered: `contract` (key/kind/policy primitives) → `model`
|
|
284
|
-
(immutable AST with a registry of node classes; unknown kinds round-trip via
|
|
285
|
-
`Unknown`) → `codec` (raw I/O in `raw.py`, hydration in `reader.py`, dump in
|
|
286
|
-
`writer.py`) → `walk` & `tree` (traversal + path-based replacement on the
|
|
287
|
-
immutable tree) → `select` (fluent `Selection` — the single home for mutation)
|
|
288
|
-
→ `content` (public facade) → `text` / `tasks` / `shared` (user-facing
|
|
289
|
-
workflows built on `Content`). All nodes are `@dataclass(frozen=True)`;
|
|
290
|
-
mutations return new instances.
|
|
291
|
-
|
|
292
295
|
## Public API
|
|
293
296
|
|
|
294
297
|
Common imports are available from the package root:
|
|
@@ -311,35 +314,21 @@ from tiptap_python_utils import (
|
|
|
311
314
|
)
|
|
312
315
|
```
|
|
313
316
|
|
|
314
|
-
## Stability
|
|
315
|
-
|
|
316
|
-
The project is pre-1.0; minor versions may include breaking changes. See
|
|
317
|
-
[CHANGELOG.md](CHANGELOG.md) for what changed and when.
|
|
318
|
-
|
|
319
|
-
## Development
|
|
320
|
-
|
|
321
|
-
```bash
|
|
322
|
-
python -m venv .venv
|
|
323
|
-
. .venv/bin/activate
|
|
324
|
-
python -m pip install -e ".[dev]"
|
|
325
|
-
pytest -q
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
Build and validate a release artifact:
|
|
329
|
-
|
|
330
|
-
```bash
|
|
331
|
-
python -m build
|
|
332
|
-
python -m twine check dist/*
|
|
333
|
-
```
|
|
334
|
-
|
|
335
317
|
## Contributing
|
|
336
318
|
|
|
337
319
|
Issues and pull requests are welcome. Please read
|
|
338
|
-
[CONTRIBUTING.md](CONTRIBUTING.md) for the local setup
|
|
339
|
-
and open an issue at
|
|
320
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for the local setup, architecture overview,
|
|
321
|
+
and release checklist, and open an issue at
|
|
340
322
|
[github.com/tugkanpilka/tiptap-python-utils/issues](https://github.com/tugkanpilka/tiptap-python-utils/issues)
|
|
341
|
-
before
|
|
323
|
+
before opening a pull request so we can align on the approach.
|
|
342
324
|
|
|
343
325
|
## License
|
|
344
326
|
|
|
345
327
|
MIT — see [LICENSE](LICENSE).
|
|
328
|
+
|
|
329
|
+
## Stability
|
|
330
|
+
|
|
331
|
+
The project is pre-1.0; minor versions may include breaking changes. See
|
|
332
|
+
[CHANGELOG.md](CHANGELOG.md) for what changed and when.
|
|
333
|
+
</content>
|
|
334
|
+
</invoke>
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils.egg-info/SOURCES.txt
RENAMED
|
@@ -7,6 +7,7 @@ src/tiptap_python_utils/content.py
|
|
|
7
7
|
src/tiptap_python_utils/exceptions.py
|
|
8
8
|
src/tiptap_python_utils/identity.py
|
|
9
9
|
src/tiptap_python_utils/py.typed
|
|
10
|
+
src/tiptap_python_utils/task.py
|
|
10
11
|
src/tiptap_python_utils/types.py
|
|
11
12
|
src/tiptap_python_utils.egg-info/PKG-INFO
|
|
12
13
|
src/tiptap_python_utils.egg-info/SOURCES.txt
|
|
@@ -48,4 +49,5 @@ tests/test_filter.py
|
|
|
48
49
|
tests/test_generic_helpers.py
|
|
49
50
|
tests/test_mutations.py
|
|
50
51
|
tests/test_public_api.py
|
|
52
|
+
tests/test_task_namespace.py
|
|
51
53
|
tests/test_traverser.py
|
|
@@ -66,6 +66,7 @@ SUBPACKAGE_PUBLIC_NAMES: dict[str, frozenset[str]] = {
|
|
|
66
66
|
"new_shared_id",
|
|
67
67
|
}
|
|
68
68
|
),
|
|
69
|
+
"tiptap_python_utils.task": frozenset({"create_list", "is_item", "is_list"}),
|
|
69
70
|
"tiptap_python_utils.tasks": frozenset(
|
|
70
71
|
{"has_open_tasks", "open_tasks", "syncable_tasks"}
|
|
71
72
|
),
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Unit tests for the pure raw-dict `task` namespace."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from tiptap_python_utils import task
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# --- create_list -----------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_create_list_wraps_items_in_task_list_block():
|
|
12
|
+
items = [{"type": "taskItem"}]
|
|
13
|
+
block = task.create_list(items)
|
|
14
|
+
assert block == {"type": "taskList", "content": items}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_create_list_accepts_empty_list():
|
|
18
|
+
assert task.create_list([]) == {"type": "taskList", "content": []}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_create_list_stores_items_by_reference_not_a_copy():
|
|
22
|
+
items = [{"type": "taskItem", "n": 1}]
|
|
23
|
+
block = task.create_list(items)
|
|
24
|
+
# Same object, not a copy.
|
|
25
|
+
assert block["content"] is items
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_create_list_reflects_later_mutations_of_original_list():
|
|
29
|
+
items = [{"type": "taskItem", "n": 1}]
|
|
30
|
+
block = task.create_list(items)
|
|
31
|
+
# Caller keeps appending to the original list after wrapping.
|
|
32
|
+
items.append({"type": "taskItem", "n": 2})
|
|
33
|
+
# The change is visible inside the block (by-reference contract).
|
|
34
|
+
assert block["content"] == [
|
|
35
|
+
{"type": "taskItem", "n": 1},
|
|
36
|
+
{"type": "taskItem", "n": 2},
|
|
37
|
+
]
|
|
38
|
+
assert len(block["content"]) == 2
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# --- is_list ---------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_is_list_true_for_valid_task_list():
|
|
45
|
+
assert task.is_list({"type": "taskList", "content": []}) is True
|
|
46
|
+
assert task.is_list({"type": "taskList", "content": [{"type": "taskItem"}]}) is True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_is_list_false_for_wrong_type():
|
|
50
|
+
assert task.is_list({"type": "bulletList", "content": []}) is False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_is_list_false_when_content_not_a_list():
|
|
54
|
+
assert task.is_list({"type": "taskList", "content": {}}) is False
|
|
55
|
+
assert task.is_list({"type": "taskList", "content": "x"}) is False
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_is_list_false_on_missing_keys_without_raising():
|
|
59
|
+
assert task.is_list({}) is False
|
|
60
|
+
assert task.is_list({"type": "taskList"}) is False # no content key
|
|
61
|
+
assert task.is_list({"content": []}) is False # no type key
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_is_list_false_for_non_dict():
|
|
65
|
+
assert task.is_list(None) is False
|
|
66
|
+
assert task.is_list([]) is False
|
|
67
|
+
assert task.is_list("taskList") is False
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# --- is_item ---------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_is_item_true_for_task_item():
|
|
74
|
+
assert task.is_item({"type": "taskItem"}) is True
|
|
75
|
+
assert task.is_item({"type": "taskItem", "attrs": {"checked": True}}) is True
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_is_item_false_for_wrong_type():
|
|
79
|
+
assert task.is_item({"type": "taskList"}) is False
|
|
80
|
+
assert task.is_item({"type": "listItem"}) is False
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_is_item_false_on_missing_keys_without_raising():
|
|
84
|
+
assert task.is_item({}) is False
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_is_item_false_for_non_dict():
|
|
88
|
+
assert task.is_item(None) is False
|
|
89
|
+
assert task.is_item([]) is False
|
|
90
|
+
assert task.is_item("taskItem") is False
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/codec/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/codec/raw.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/codec/reader.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/codec/writer.py
RENAMED
|
File without changes
|
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/contract/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/contract/key.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/contract/kind.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/contract/policy.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/base.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/nodes.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/payload.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/model/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/select/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/select/selection.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/shared/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/shared/families.py
RENAMED
|
File without changes
|
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/shared/identity.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/tasks/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/tasks/query.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/text/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/text/extract.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/tree/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/tree/path.py
RENAMED
|
File without changes
|
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/walk/__init__.py
RENAMED
|
File without changes
|
{tiptap_python_utils-0.5.0 → tiptap_python_utils-0.6.0}/src/tiptap_python_utils/walk/traversal.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|