OVAPortableText 0.1.0__tar.gz → 0.1.2__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.
- {ovaportabletext-0.1.0/docs/dev/ova → ovaportabletext-0.1.2}/CHANGELOG.md +14 -7
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/PKG-INFO +65 -16
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/README.md +64 -15
- ovaportabletext-0.1.2/docs/API_REFERENCE.md +149 -0
- ovaportabletext-0.1.2/docs/PUBLISHING_CHECKLIST.md +56 -0
- ovaportabletext-0.1.2/docs/dev/ova/CHANGELOG.md +38 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/pyproject.toml +1 -1
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/__init__.py +1 -1
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/document.py +103 -5
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/helpers.py +11 -4
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/section.py +74 -3
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/version.py +1 -1
- ovaportabletext-0.1.2/tests/test_content_flow_helpers.py +44 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_numbering.py +33 -0
- ovaportabletext-0.1.2/tests/test_strict_ids.py +49 -0
- ovaportabletext-0.1.0/docs/API_REFERENCE.md +0 -77
- ovaportabletext-0.1.0/docs/PUBLISHING_CHECKLIST.md +0 -32
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/.gitignore +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/LICENSE +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/PROTOCOL_ALIGNMENT.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/QUICKSTART.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/REAL_WORLD_RECIPES.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/TEST_MATRIX.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/USER_TESTING_CHECKLIST.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/VALIDATION_AND_RESOLVER.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/native/portable_text_basics.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_1.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_10.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_2.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_3.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_4.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_5.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_6.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_7.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_8.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_9.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/report_profile_v1.0.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/report_profile_v1_draft.md +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/builder_numbering_roundtrip_demo.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/extended_registries_demo.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/full_report_workflow_demo.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/inline_objects_report.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/marks_and_lists_report.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/minimal_report.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/patent_valuation_style_report.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/registry_blocks_report.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/save_and_load_json_demo.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/validation_context_demo.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/validation_report.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/base.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/block_objects.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/content.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/exceptions.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/inline.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/numbering.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/py.typed +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/registry.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/resolver.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/text.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/theme.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/validator.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_blocks_and_registry.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_builder_roundtrip_and_theme.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_document_validation_error_rendering.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_examples_smoke.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_extended_registries_and_resolver.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_file_io_roundtrip.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_inline_objects.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_mark_validation.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_marks_and_lists.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_minimal_report.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_pie_chart_parallel_arrays.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_resolver_debug_summary.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_resolver_semantic_figure_alias.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_roundtrip_and_runtime_version.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_section_batch_helpers.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_style_validation.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_table_dataset_validation.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validation_context_output.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validation_failures.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validation_report_python_alias.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validation_success.py +0 -0
- {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validator_extended_rules.py +0 -0
|
@@ -5,14 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.1.2]
|
|
9
|
+
|
|
8
10
|
### Added
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
- `
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
11
|
+
- optional `strict_ids=True` fail-early duplicate-ID checks for common authoring paths
|
|
12
|
+
- continuous-content helpers on `Section`:
|
|
13
|
+
- `append_to_last_content()`
|
|
14
|
+
- `append_blocks_to_last_content()`
|
|
15
|
+
- `append_text_block_to_last_content()`
|
|
16
|
+
- `append_paragraph_to_last_content()`
|
|
17
|
+
- release-facing docs now explain the implemented v1.0 protocol subset more explicitly
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- packaging and release metadata were aligned for a cleaner publication flow
|
|
21
|
+
- `Section.numbering` now accepts only protocol-approved values: `auto`, `none`, and `manual`
|
|
22
|
+
- publishing checklist now includes changelog layout and sdist verification guidance
|
|
16
23
|
|
|
17
24
|
## [0.1.1]
|
|
18
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: OVAPortableText
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python builder for generating OVAPortableText / Report Profile v1 JSON documents
|
|
5
5
|
Author: FENG QU
|
|
6
6
|
License-Expression: MIT
|
|
@@ -29,7 +29,10 @@ OVAPortableText 的目标不是直接渲染 PDF,而是让 Python 端**以强
|
|
|
29
29
|
|
|
30
30
|
## Current scope / 当前实现范围
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
The package currently implements an intentionally selected, production-usable subset of the v1.0 protocol rather than every reserved taxonomy item.
|
|
33
|
+
当前实现是 v1.0 协议里一个**可生产使用的已落地子集**,并不是把规范里所有预留 taxonomy 一次性全部实现。
|
|
34
|
+
|
|
35
|
+
Implemented today:
|
|
33
36
|
|
|
34
37
|
- top-level document / section skeleton
|
|
35
38
|
- content body items
|
|
@@ -37,19 +40,19 @@ Step 9 currently includes:
|
|
|
37
40
|
- protocol-approved text styles for v1
|
|
38
41
|
- decorator marks + annotation `markDefs`
|
|
39
42
|
- list semantics: `listItem` / `level`
|
|
40
|
-
-
|
|
43
|
+
- inline objects:
|
|
41
44
|
- `hard_break`
|
|
42
45
|
- `xref`
|
|
43
46
|
- `citation_ref`
|
|
44
47
|
- `footnote_ref`
|
|
45
48
|
- `glossary_term`
|
|
46
|
-
-
|
|
49
|
+
- block objects:
|
|
47
50
|
- `image`
|
|
48
51
|
- `chart`
|
|
49
52
|
- `table`
|
|
50
53
|
- `math_block`
|
|
51
54
|
- `callout`
|
|
52
|
-
-
|
|
55
|
+
- typed registries:
|
|
53
56
|
- `assets.images / logos / backgrounds / icons / attachments`
|
|
54
57
|
- `datasets.tables / charts(pie) / metrics`
|
|
55
58
|
- `bibliography / footnotes / glossary`
|
|
@@ -57,9 +60,16 @@ Step 9 currently includes:
|
|
|
57
60
|
- section / figure / table / equation numbering helpers
|
|
58
61
|
- global resolver / index builder
|
|
59
62
|
- structured document validation report with issue context
|
|
60
|
-
- detailed bilingual comments / 详细中英文双语注释
|
|
61
63
|
- round-trip helpers: `from_dict()` / `from_json()` / `save_json()` / `load_json()`
|
|
62
64
|
|
|
65
|
+
Not yet implemented as first-class authoring helpers:
|
|
66
|
+
|
|
67
|
+
- reserved or future taxonomy items that are present in the protocol but not yet exposed as stable Python helpers
|
|
68
|
+
- a full generated symbol reference for every internal class or helper
|
|
69
|
+
|
|
70
|
+
This boundary is intentional: the package focuses on the pieces that are already stable enough for Python authoring and downstream renderer handoff.
|
|
71
|
+
这个边界是有意为之:当前包优先把已经稳定、适合 Python 生产 JSON 和交给下游渲染器的部分做好。
|
|
72
|
+
|
|
63
73
|
## Install / 安装
|
|
64
74
|
|
|
65
75
|
### PIP
|
|
@@ -71,12 +81,13 @@ pip install OVAPortableText
|
|
|
71
81
|
## Quick start / 快速开始
|
|
72
82
|
|
|
73
83
|
```python
|
|
74
|
-
from ova_portable_text import create_document
|
|
84
|
+
from ova_portable_text import create_document
|
|
75
85
|
|
|
76
86
|
report = create_document(
|
|
77
87
|
title="Patent Valuation Report",
|
|
78
88
|
language="en",
|
|
79
89
|
documentType="report",
|
|
90
|
+
strict_ids=True,
|
|
80
91
|
)
|
|
81
92
|
|
|
82
93
|
intro = report.new_section(id="sec-1", level=1, title="Executive Summary")
|
|
@@ -85,7 +96,7 @@ intro.append_paragraph("This is the opening introduction of the chapter.")
|
|
|
85
96
|
background = intro.new_subsection(id="sec-1-1", title="Background")
|
|
86
97
|
background.append_paragraph("This is the body text of subsection 1.1.")
|
|
87
98
|
|
|
88
|
-
intro.
|
|
99
|
+
intro.append_paragraph_to_last_content("This is a concluding paragraph after subsection 1.1.")
|
|
89
100
|
|
|
90
101
|
report.assert_valid()
|
|
91
102
|
print(report.to_json())
|
|
@@ -95,9 +106,10 @@ print(report.to_json())
|
|
|
95
106
|
|
|
96
107
|
1. create one `Document`
|
|
97
108
|
2. append sections and registries
|
|
98
|
-
3.
|
|
99
|
-
4. call `
|
|
100
|
-
5.
|
|
109
|
+
3. enable `strict_ids=True` during authoring when you want duplicate IDs to fail early
|
|
110
|
+
4. call `validate()` during development
|
|
111
|
+
5. call `assert_valid()` before exporting or handing off to Java
|
|
112
|
+
6. export with `to_dict()` / `to_json()`
|
|
101
113
|
|
|
102
114
|
## Common authoring patterns / 常见写法
|
|
103
115
|
|
|
@@ -158,7 +170,36 @@ report.add_chart_dataset(
|
|
|
158
170
|
)
|
|
159
171
|
```
|
|
160
172
|
|
|
161
|
-
### 3)
|
|
173
|
+
### 3) Fail duplicate IDs earlier when needed / 需要时尽早拦截重复 ID
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from ova_portable_text import create_document
|
|
177
|
+
|
|
178
|
+
report = create_document(title="Strict IDs", language="en", strict_ids=True)
|
|
179
|
+
report.new_section(id="sec-1", level=1, title="Intro")
|
|
180
|
+
|
|
181
|
+
# Raises immediately instead of waiting until validate()
|
|
182
|
+
report.new_section(id="sec-1", level=1, title="Duplicate Intro")
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 4) Keep a continuous content flow / 保持连续 content 语义
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from ova_portable_text import create_document
|
|
189
|
+
|
|
190
|
+
report = create_document(title="Flow Demo", language="en")
|
|
191
|
+
sec = report.new_section(id="sec-1", level=1, title="Intro")
|
|
192
|
+
|
|
193
|
+
sec.append_paragraph("Opening paragraph.")
|
|
194
|
+
sec.append_paragraph_to_last_content("Still part of the same content item.")
|
|
195
|
+
|
|
196
|
+
sub = sec.new_subsection(id="sec-1-1", title="Background")
|
|
197
|
+
sub.append_paragraph("Subsection text.")
|
|
198
|
+
|
|
199
|
+
sec.append_paragraph_to_last_content("This now starts a new content item after the subsection.")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 5) Validate before export / 导出前校验
|
|
162
203
|
|
|
163
204
|
```python
|
|
164
205
|
validation = report.validate()
|
|
@@ -166,7 +207,7 @@ print(validation.to_text())
|
|
|
166
207
|
report.assert_valid()
|
|
167
208
|
```
|
|
168
209
|
|
|
169
|
-
###
|
|
210
|
+
### 6) Save JSON to disk and read it back / 落盘 JSON 再读回
|
|
170
211
|
|
|
171
212
|
```python
|
|
172
213
|
from pathlib import Path
|
|
@@ -185,8 +226,8 @@ print(restored.meta.title)
|
|
|
185
226
|
`validate()` returns a structured `ValidationReport`.
|
|
186
227
|
`validate()` 会返回结构化的 `ValidationReport`。
|
|
187
228
|
|
|
188
|
-
|
|
189
|
-
|
|
229
|
+
Each issue tries to include maintenance-friendly context, such as:
|
|
230
|
+
每条 issue 会尽量附带更适合维护的上下文,例如:
|
|
190
231
|
|
|
191
232
|
- `sectionId`
|
|
192
233
|
- `sectionTitle`
|
|
@@ -209,14 +250,23 @@ print(resolver.debug_summary())
|
|
|
209
250
|
print(resolver.resolve_xref(target_type="section", target_id="sec-1"))
|
|
210
251
|
```
|
|
211
252
|
|
|
253
|
+
## Protocol-aligned authoring notes / 与协议对齐的写作说明
|
|
254
|
+
|
|
255
|
+
- `Section.numbering` only accepts `"auto"`, `"none"`, or `"manual"`.
|
|
256
|
+
- `strict_ids=True` is an authoring-time safety helper and is **not** serialized into the final JSON.
|
|
257
|
+
- `append_*_to_last_content(...)` helpers are ergonomic helpers for preserving the protocol meaning of a continuous `content` item.
|
|
258
|
+
- The recommended chart dataset structure is the protocol-native pie `slices[]` shape; `pie_chart_from_parallel_arrays(...)` is a compatibility/helper layer for older parallel-array inputs.
|
|
259
|
+
|
|
212
260
|
## Included docs / 附带文档
|
|
213
261
|
|
|
214
262
|
- `docs/QUICKSTART.md`
|
|
263
|
+
- `docs/API_REFERENCE.md`
|
|
215
264
|
- `docs/VALIDATION_AND_RESOLVER.md`
|
|
216
265
|
- `docs/TEST_MATRIX.md`
|
|
217
266
|
- `docs/REAL_WORLD_RECIPES.md`
|
|
218
267
|
- `docs/USER_TESTING_CHECKLIST.md`
|
|
219
268
|
- `docs/PROTOCOL_ALIGNMENT.md`
|
|
269
|
+
- `docs/PUBLISHING_CHECKLIST.md`
|
|
220
270
|
|
|
221
271
|
## Included examples / 附带样例
|
|
222
272
|
|
|
@@ -232,7 +282,6 @@ print(resolver.resolve_xref(target_type="section", target_id="sec-1"))
|
|
|
232
282
|
- `examples/save_and_load_json_demo.py`
|
|
233
283
|
- `examples/patent_valuation_style_report.py`
|
|
234
284
|
|
|
235
|
-
|
|
236
285
|
## Version / 版本
|
|
237
286
|
|
|
238
287
|
```python
|
|
@@ -6,7 +6,10 @@ OVAPortableText 的目标不是直接渲染 PDF,而是让 Python 端**以强
|
|
|
6
6
|
|
|
7
7
|
## Current scope / 当前实现范围
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The package currently implements an intentionally selected, production-usable subset of the v1.0 protocol rather than every reserved taxonomy item.
|
|
10
|
+
当前实现是 v1.0 协议里一个**可生产使用的已落地子集**,并不是把规范里所有预留 taxonomy 一次性全部实现。
|
|
11
|
+
|
|
12
|
+
Implemented today:
|
|
10
13
|
|
|
11
14
|
- top-level document / section skeleton
|
|
12
15
|
- content body items
|
|
@@ -14,19 +17,19 @@ Step 9 currently includes:
|
|
|
14
17
|
- protocol-approved text styles for v1
|
|
15
18
|
- decorator marks + annotation `markDefs`
|
|
16
19
|
- list semantics: `listItem` / `level`
|
|
17
|
-
-
|
|
20
|
+
- inline objects:
|
|
18
21
|
- `hard_break`
|
|
19
22
|
- `xref`
|
|
20
23
|
- `citation_ref`
|
|
21
24
|
- `footnote_ref`
|
|
22
25
|
- `glossary_term`
|
|
23
|
-
-
|
|
26
|
+
- block objects:
|
|
24
27
|
- `image`
|
|
25
28
|
- `chart`
|
|
26
29
|
- `table`
|
|
27
30
|
- `math_block`
|
|
28
31
|
- `callout`
|
|
29
|
-
-
|
|
32
|
+
- typed registries:
|
|
30
33
|
- `assets.images / logos / backgrounds / icons / attachments`
|
|
31
34
|
- `datasets.tables / charts(pie) / metrics`
|
|
32
35
|
- `bibliography / footnotes / glossary`
|
|
@@ -34,9 +37,16 @@ Step 9 currently includes:
|
|
|
34
37
|
- section / figure / table / equation numbering helpers
|
|
35
38
|
- global resolver / index builder
|
|
36
39
|
- structured document validation report with issue context
|
|
37
|
-
- detailed bilingual comments / 详细中英文双语注释
|
|
38
40
|
- round-trip helpers: `from_dict()` / `from_json()` / `save_json()` / `load_json()`
|
|
39
41
|
|
|
42
|
+
Not yet implemented as first-class authoring helpers:
|
|
43
|
+
|
|
44
|
+
- reserved or future taxonomy items that are present in the protocol but not yet exposed as stable Python helpers
|
|
45
|
+
- a full generated symbol reference for every internal class or helper
|
|
46
|
+
|
|
47
|
+
This boundary is intentional: the package focuses on the pieces that are already stable enough for Python authoring and downstream renderer handoff.
|
|
48
|
+
这个边界是有意为之:当前包优先把已经稳定、适合 Python 生产 JSON 和交给下游渲染器的部分做好。
|
|
49
|
+
|
|
40
50
|
## Install / 安装
|
|
41
51
|
|
|
42
52
|
### PIP
|
|
@@ -48,12 +58,13 @@ pip install OVAPortableText
|
|
|
48
58
|
## Quick start / 快速开始
|
|
49
59
|
|
|
50
60
|
```python
|
|
51
|
-
from ova_portable_text import create_document
|
|
61
|
+
from ova_portable_text import create_document
|
|
52
62
|
|
|
53
63
|
report = create_document(
|
|
54
64
|
title="Patent Valuation Report",
|
|
55
65
|
language="en",
|
|
56
66
|
documentType="report",
|
|
67
|
+
strict_ids=True,
|
|
57
68
|
)
|
|
58
69
|
|
|
59
70
|
intro = report.new_section(id="sec-1", level=1, title="Executive Summary")
|
|
@@ -62,7 +73,7 @@ intro.append_paragraph("This is the opening introduction of the chapter.")
|
|
|
62
73
|
background = intro.new_subsection(id="sec-1-1", title="Background")
|
|
63
74
|
background.append_paragraph("This is the body text of subsection 1.1.")
|
|
64
75
|
|
|
65
|
-
intro.
|
|
76
|
+
intro.append_paragraph_to_last_content("This is a concluding paragraph after subsection 1.1.")
|
|
66
77
|
|
|
67
78
|
report.assert_valid()
|
|
68
79
|
print(report.to_json())
|
|
@@ -72,9 +83,10 @@ print(report.to_json())
|
|
|
72
83
|
|
|
73
84
|
1. create one `Document`
|
|
74
85
|
2. append sections and registries
|
|
75
|
-
3.
|
|
76
|
-
4. call `
|
|
77
|
-
5.
|
|
86
|
+
3. enable `strict_ids=True` during authoring when you want duplicate IDs to fail early
|
|
87
|
+
4. call `validate()` during development
|
|
88
|
+
5. call `assert_valid()` before exporting or handing off to Java
|
|
89
|
+
6. export with `to_dict()` / `to_json()`
|
|
78
90
|
|
|
79
91
|
## Common authoring patterns / 常见写法
|
|
80
92
|
|
|
@@ -135,7 +147,36 @@ report.add_chart_dataset(
|
|
|
135
147
|
)
|
|
136
148
|
```
|
|
137
149
|
|
|
138
|
-
### 3)
|
|
150
|
+
### 3) Fail duplicate IDs earlier when needed / 需要时尽早拦截重复 ID
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from ova_portable_text import create_document
|
|
154
|
+
|
|
155
|
+
report = create_document(title="Strict IDs", language="en", strict_ids=True)
|
|
156
|
+
report.new_section(id="sec-1", level=1, title="Intro")
|
|
157
|
+
|
|
158
|
+
# Raises immediately instead of waiting until validate()
|
|
159
|
+
report.new_section(id="sec-1", level=1, title="Duplicate Intro")
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 4) Keep a continuous content flow / 保持连续 content 语义
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from ova_portable_text import create_document
|
|
166
|
+
|
|
167
|
+
report = create_document(title="Flow Demo", language="en")
|
|
168
|
+
sec = report.new_section(id="sec-1", level=1, title="Intro")
|
|
169
|
+
|
|
170
|
+
sec.append_paragraph("Opening paragraph.")
|
|
171
|
+
sec.append_paragraph_to_last_content("Still part of the same content item.")
|
|
172
|
+
|
|
173
|
+
sub = sec.new_subsection(id="sec-1-1", title="Background")
|
|
174
|
+
sub.append_paragraph("Subsection text.")
|
|
175
|
+
|
|
176
|
+
sec.append_paragraph_to_last_content("This now starts a new content item after the subsection.")
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 5) Validate before export / 导出前校验
|
|
139
180
|
|
|
140
181
|
```python
|
|
141
182
|
validation = report.validate()
|
|
@@ -143,7 +184,7 @@ print(validation.to_text())
|
|
|
143
184
|
report.assert_valid()
|
|
144
185
|
```
|
|
145
186
|
|
|
146
|
-
###
|
|
187
|
+
### 6) Save JSON to disk and read it back / 落盘 JSON 再读回
|
|
147
188
|
|
|
148
189
|
```python
|
|
149
190
|
from pathlib import Path
|
|
@@ -162,8 +203,8 @@ print(restored.meta.title)
|
|
|
162
203
|
`validate()` returns a structured `ValidationReport`.
|
|
163
204
|
`validate()` 会返回结构化的 `ValidationReport`。
|
|
164
205
|
|
|
165
|
-
|
|
166
|
-
|
|
206
|
+
Each issue tries to include maintenance-friendly context, such as:
|
|
207
|
+
每条 issue 会尽量附带更适合维护的上下文,例如:
|
|
167
208
|
|
|
168
209
|
- `sectionId`
|
|
169
210
|
- `sectionTitle`
|
|
@@ -186,14 +227,23 @@ print(resolver.debug_summary())
|
|
|
186
227
|
print(resolver.resolve_xref(target_type="section", target_id="sec-1"))
|
|
187
228
|
```
|
|
188
229
|
|
|
230
|
+
## Protocol-aligned authoring notes / 与协议对齐的写作说明
|
|
231
|
+
|
|
232
|
+
- `Section.numbering` only accepts `"auto"`, `"none"`, or `"manual"`.
|
|
233
|
+
- `strict_ids=True` is an authoring-time safety helper and is **not** serialized into the final JSON.
|
|
234
|
+
- `append_*_to_last_content(...)` helpers are ergonomic helpers for preserving the protocol meaning of a continuous `content` item.
|
|
235
|
+
- The recommended chart dataset structure is the protocol-native pie `slices[]` shape; `pie_chart_from_parallel_arrays(...)` is a compatibility/helper layer for older parallel-array inputs.
|
|
236
|
+
|
|
189
237
|
## Included docs / 附带文档
|
|
190
238
|
|
|
191
239
|
- `docs/QUICKSTART.md`
|
|
240
|
+
- `docs/API_REFERENCE.md`
|
|
192
241
|
- `docs/VALIDATION_AND_RESOLVER.md`
|
|
193
242
|
- `docs/TEST_MATRIX.md`
|
|
194
243
|
- `docs/REAL_WORLD_RECIPES.md`
|
|
195
244
|
- `docs/USER_TESTING_CHECKLIST.md`
|
|
196
245
|
- `docs/PROTOCOL_ALIGNMENT.md`
|
|
246
|
+
- `docs/PUBLISHING_CHECKLIST.md`
|
|
197
247
|
|
|
198
248
|
## Included examples / 附带样例
|
|
199
249
|
|
|
@@ -209,7 +259,6 @@ print(resolver.resolve_xref(target_type="section", target_id="sec-1"))
|
|
|
209
259
|
- `examples/save_and_load_json_demo.py`
|
|
210
260
|
- `examples/patent_valuation_style_report.py`
|
|
211
261
|
|
|
212
|
-
|
|
213
262
|
## Version / 版本
|
|
214
263
|
|
|
215
264
|
```python
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
This page is a practical API map instead of a generated full symbol dump.
|
|
4
|
+
本文档是实用型 API 地图,而不是自动生成的完整符号清单。
|
|
5
|
+
|
|
6
|
+
## Scope note / 范围说明
|
|
7
|
+
|
|
8
|
+
This package intentionally documents the stable, author-facing subset of the protocol that is already implemented.
|
|
9
|
+
本文档刻意只覆盖已经稳定、面向作者使用的那部分 API。
|
|
10
|
+
|
|
11
|
+
That means:
|
|
12
|
+
|
|
13
|
+
- the protocol may reserve more taxonomy items than this package currently exposes as helpers
|
|
14
|
+
- internal classes may exist without being recommended as public authoring entry points
|
|
15
|
+
|
|
16
|
+
## Main entry points / 主要入口
|
|
17
|
+
|
|
18
|
+
- `create_document(...)`
|
|
19
|
+
- `document(...)`
|
|
20
|
+
- `Document.from_meta(...)`
|
|
21
|
+
- `Document.from_dict(...)`
|
|
22
|
+
- `Document.from_json(...)`
|
|
23
|
+
|
|
24
|
+
Commonly used constructor options:
|
|
25
|
+
|
|
26
|
+
- `title`
|
|
27
|
+
- `language`
|
|
28
|
+
- `documentType`
|
|
29
|
+
- `strict_ids=False`
|
|
30
|
+
|
|
31
|
+
## Core authoring objects / 核心写作对象
|
|
32
|
+
|
|
33
|
+
- `Document`
|
|
34
|
+
- `Section`
|
|
35
|
+
- `TextBlock`
|
|
36
|
+
- `Span`
|
|
37
|
+
- `ImageBlock`
|
|
38
|
+
- `ChartBlock`
|
|
39
|
+
- `TableBlock`
|
|
40
|
+
- `MathBlock`
|
|
41
|
+
- `CalloutBlock`
|
|
42
|
+
|
|
43
|
+
## Registries / 注册表对象
|
|
44
|
+
|
|
45
|
+
- `ImageAsset`
|
|
46
|
+
- `LogoAsset`
|
|
47
|
+
- `BackgroundAsset`
|
|
48
|
+
- `IconAsset`
|
|
49
|
+
- `AttachmentAsset`
|
|
50
|
+
- `TableDataset`
|
|
51
|
+
- `PieChartDataset`
|
|
52
|
+
- `MetricDataset`
|
|
53
|
+
- `BibliographyEntry`
|
|
54
|
+
- `FootnoteEntry`
|
|
55
|
+
- `GlossaryEntry`
|
|
56
|
+
|
|
57
|
+
## Validation / 校验
|
|
58
|
+
|
|
59
|
+
- `Document.validate()`
|
|
60
|
+
- `Document.assert_valid()`
|
|
61
|
+
- `ValidationReport`
|
|
62
|
+
- `DocumentValidationError`
|
|
63
|
+
|
|
64
|
+
## Resolver / 解析器
|
|
65
|
+
|
|
66
|
+
- `Document.build_resolver()`
|
|
67
|
+
- `DocumentResolver.resolve_xref(...)`
|
|
68
|
+
- `DocumentResolver.get_by_id(...)`
|
|
69
|
+
- `DocumentResolver.get_by_anchor(...)`
|
|
70
|
+
- `DocumentResolver.debug_summary()`
|
|
71
|
+
|
|
72
|
+
## Numbering / 编号辅助
|
|
73
|
+
|
|
74
|
+
- `Document.build_numbering()`
|
|
75
|
+
- `NumberingConfig`
|
|
76
|
+
- `DocumentNumbering`
|
|
77
|
+
- `Section.numbering`
|
|
78
|
+
- `NumberingMode = Literal["auto", "none", "manual"]`
|
|
79
|
+
|
|
80
|
+
## Export / 导出
|
|
81
|
+
|
|
82
|
+
- `to_dict(exclude_none=True)`
|
|
83
|
+
- `to_json(indent=2, exclude_none=True)`
|
|
84
|
+
- `save_json(path, indent=2, exclude_none=True)`
|
|
85
|
+
- `load_json(path)`
|
|
86
|
+
|
|
87
|
+
## Recommended import style / 推荐导入方式
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from ova_portable_text import (
|
|
91
|
+
create_document,
|
|
92
|
+
section,
|
|
93
|
+
paragraph,
|
|
94
|
+
xref,
|
|
95
|
+
citation_ref,
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Authoring helpers / 常用 authoring helper
|
|
100
|
+
|
|
101
|
+
### Document-level helpers
|
|
102
|
+
|
|
103
|
+
- `Document.new_section(...)`
|
|
104
|
+
- `Document.append_section(...)`
|
|
105
|
+
- `Document.add_image_asset(...)`
|
|
106
|
+
- `Document.add_chart_dataset(...)`
|
|
107
|
+
- `Document.add_table_dataset(...)`
|
|
108
|
+
- `Document.add_bibliography_entry(...)`
|
|
109
|
+
- `Document.add_footnote(...)`
|
|
110
|
+
- `Document.add_glossary_entry(...)`
|
|
111
|
+
|
|
112
|
+
### Section-level helpers
|
|
113
|
+
|
|
114
|
+
- `Section.append_paragraph(...)`
|
|
115
|
+
- `Section.append_paragraphs(*paragraphs)`
|
|
116
|
+
- `Section.append_lead(...)`
|
|
117
|
+
- `Section.append_bullet_item(...)`
|
|
118
|
+
- `Section.append_bullet_items(*items, level=1)`
|
|
119
|
+
- `Section.append_number_item(...)`
|
|
120
|
+
- `Section.append_number_items(*items, level=1)`
|
|
121
|
+
- `Section.new_subsection(...)`
|
|
122
|
+
|
|
123
|
+
### Continuous-content helpers
|
|
124
|
+
|
|
125
|
+
- `Section.append_to_last_content(block)`
|
|
126
|
+
- `Section.append_blocks_to_last_content(*blocks)`
|
|
127
|
+
- `Section.append_text_block_to_last_content(block)`
|
|
128
|
+
- `Section.append_paragraph_to_last_content(...)`
|
|
129
|
+
|
|
130
|
+
Use these when you want multiple blocks to remain in the same protocol `content` item until a subsection boundary naturally starts a new one.
|
|
131
|
+
当你希望多个 block 仍然属于同一个协议 `content` item 时,优先使用这些 helper;遇到 `subsection` 边界后,再自然开始新的 `content`。
|
|
132
|
+
|
|
133
|
+
## Strict ID mode / 严格 ID 模式
|
|
134
|
+
|
|
135
|
+
`create_document(..., strict_ids=True)` enables fail-early duplicate-ID checks for the most common authoring paths.
|
|
136
|
+
`create_document(..., strict_ids=True)` 会在最常见的 authoring 路径上,把重复 ID 尽量前置到添加当下报错。
|
|
137
|
+
|
|
138
|
+
Important notes:
|
|
139
|
+
|
|
140
|
+
- this mode is authoring-time only
|
|
141
|
+
- it does **not** serialize into final JSON
|
|
142
|
+
- full validation is still available through `validate()` / `assert_valid()`
|
|
143
|
+
|
|
144
|
+
## Compatibility helpers / 兼容性 helper
|
|
145
|
+
|
|
146
|
+
- `pie_chart_from_parallel_arrays(...)`
|
|
147
|
+
|
|
148
|
+
This helper converts older parallel-array pie inputs into the protocol-native pie `slices[]` dataset structure.
|
|
149
|
+
这个 helper 会把旧的并行数组饼图输入,转换成协议原生的 pie `slices[]` 数据结构。
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Publishing Checklist
|
|
2
|
+
|
|
3
|
+
## Before release / 发布前检查
|
|
4
|
+
|
|
5
|
+
- [ ] confirm `pyproject.toml` package metadata
|
|
6
|
+
- [ ] confirm `src/ova_portable_text/version.py` matches the release version
|
|
7
|
+
- [ ] confirm root `CHANGELOG.md` exists and is updated
|
|
8
|
+
- [ ] confirm `docs/dev/ova/CHANGELOG.md` is synced if you keep both copies
|
|
9
|
+
- [ ] replace repository URLs if needed
|
|
10
|
+
- [ ] run `pytest -q`
|
|
11
|
+
- [ ] run `python -m build`
|
|
12
|
+
- [ ] inspect the generated sdist and wheel filenames
|
|
13
|
+
- [ ] verify root `CHANGELOG.md` is included in the sdist
|
|
14
|
+
- [ ] install the built wheel in a clean virtual environment
|
|
15
|
+
- [ ] verify README examples still run
|
|
16
|
+
- [ ] tag the release in Git
|
|
17
|
+
|
|
18
|
+
## Suggested release flow / 建议发布流程
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
python -m pip install --upgrade build twine
|
|
22
|
+
python -m pytest -q
|
|
23
|
+
python -m build
|
|
24
|
+
|
|
25
|
+
# Optional: inspect the build artifacts
|
|
26
|
+
ls -lh dist/
|
|
27
|
+
|
|
28
|
+
tar -tf dist/ovaportabletext-*.tar.gz | grep CHANGELOG
|
|
29
|
+
|
|
30
|
+
python -m venv .venv-publish-test
|
|
31
|
+
source .venv-publish-test/bin/activate
|
|
32
|
+
pip install dist/*.whl
|
|
33
|
+
python -c "import ova_portable_text; print(ova_portable_text.__version__)"
|
|
34
|
+
python -c "from ova_portable_text import create_document; print(create_document(title='Smoke', language='en').meta.title)"
|
|
35
|
+
|
|
36
|
+
twine check dist/*
|
|
37
|
+
twine upload --repository testpypi dist/*
|
|
38
|
+
# After verifying TestPyPI, upload to the real PyPI repository.
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Release notes for 0.1.2 / 0.1.2 发布重点
|
|
42
|
+
|
|
43
|
+
- packaging metadata and changelog layout were aligned for release
|
|
44
|
+
- `Section.numbering` is now restricted to the protocol values: `auto` / `none` / `manual`
|
|
45
|
+
- optional `strict_ids=True` was added to fail earlier on common duplicate-ID mistakes
|
|
46
|
+
- continuous-content helpers were added to make protocol-aligned `content` authoring easier
|
|
47
|
+
- docs now state more clearly that the package implements a stable subset of the v1.0 protocol
|
|
48
|
+
|
|
49
|
+
## Notes / 备注
|
|
50
|
+
|
|
51
|
+
- Use TestPyPI first.
|
|
52
|
+
- 先发 TestPyPI,再发正式 PyPI。
|
|
53
|
+
- Keep version bumps explicit and consistent.
|
|
54
|
+
- 版本号变更要明确且保持一致。
|
|
55
|
+
- Treat `validate()` / `assert_valid()` as the final gate even if `strict_ids=True` is enabled.
|
|
56
|
+
- 即使启用了 `strict_ids=True`,`validate()` / `assert_valid()` 仍然应作为最后一道闸门。
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
本项目的重要变更会记录在此文件中。
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.1.2]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- optional `strict_ids=True` fail-early duplicate-ID checks for common authoring paths
|
|
12
|
+
- continuous-content helpers on `Section`:
|
|
13
|
+
- `append_to_last_content()`
|
|
14
|
+
- `append_blocks_to_last_content()`
|
|
15
|
+
- `append_text_block_to_last_content()`
|
|
16
|
+
- `append_paragraph_to_last_content()`
|
|
17
|
+
- release-facing docs now explain the implemented v1.0 protocol subset more explicitly
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- packaging and release metadata were aligned for a cleaner publication flow
|
|
21
|
+
- `Section.numbering` now accepts only protocol-approved values: `auto`, `none`, and `manual`
|
|
22
|
+
- publishing checklist now includes changelog layout and sdist verification guidance
|
|
23
|
+
|
|
24
|
+
## [0.1.1]
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
- improved authoring ergonomics for local save/load and batch section writing
|
|
28
|
+
- more release-prep docs and smoke-test coverage
|
|
29
|
+
|
|
30
|
+
## [0.1.0]
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- document / section tree builder
|
|
34
|
+
- text blocks, spans, marks, markDefs, and list semantics
|
|
35
|
+
- inline refs: `xref`, `citation_ref`, `footnote_ref`, `glossary_term`, `hard_break`
|
|
36
|
+
- block objects: `image`, `chart`, `table`, `math_block`, `callout`
|
|
37
|
+
- registries: assets, datasets, bibliography, footnotes, glossary
|
|
38
|
+
- numbering helpers, resolver, validator, and round-trip helpers
|
|
@@ -85,7 +85,7 @@ from .registry import (
|
|
|
85
85
|
TableDataset,
|
|
86
86
|
)
|
|
87
87
|
from .resolver import DocumentResolver, ResolvedTarget
|
|
88
|
-
from .section import Section
|
|
88
|
+
from .section import NumberingMode, Section
|
|
89
89
|
from .theme import ThemeConfig
|
|
90
90
|
from .validator import assert_valid_document, validate_document
|
|
91
91
|
from .version import __version__
|