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.
Files changed (83) hide show
  1. {ovaportabletext-0.1.0/docs/dev/ova → ovaportabletext-0.1.2}/CHANGELOG.md +14 -7
  2. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/PKG-INFO +65 -16
  3. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/README.md +64 -15
  4. ovaportabletext-0.1.2/docs/API_REFERENCE.md +149 -0
  5. ovaportabletext-0.1.2/docs/PUBLISHING_CHECKLIST.md +56 -0
  6. ovaportabletext-0.1.2/docs/dev/ova/CHANGELOG.md +38 -0
  7. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/pyproject.toml +1 -1
  8. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/__init__.py +1 -1
  9. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/document.py +103 -5
  10. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/helpers.py +11 -4
  11. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/section.py +74 -3
  12. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/version.py +1 -1
  13. ovaportabletext-0.1.2/tests/test_content_flow_helpers.py +44 -0
  14. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_numbering.py +33 -0
  15. ovaportabletext-0.1.2/tests/test_strict_ids.py +49 -0
  16. ovaportabletext-0.1.0/docs/API_REFERENCE.md +0 -77
  17. ovaportabletext-0.1.0/docs/PUBLISHING_CHECKLIST.md +0 -32
  18. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/.gitignore +0 -0
  19. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/LICENSE +0 -0
  20. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/PROTOCOL_ALIGNMENT.md +0 -0
  21. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/QUICKSTART.md +0 -0
  22. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/REAL_WORLD_RECIPES.md +0 -0
  23. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/TEST_MATRIX.md +0 -0
  24. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/USER_TESTING_CHECKLIST.md +0 -0
  25. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/VALIDATION_AND_RESOLVER.md +0 -0
  26. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/native/portable_text_basics.md +0 -0
  27. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_1.md +0 -0
  28. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_10.md +0 -0
  29. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_2.md +0 -0
  30. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_3.md +0 -0
  31. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_4.md +0 -0
  32. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_5.md +0 -0
  33. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_6.md +0 -0
  34. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_7.md +0 -0
  35. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_8.md +0 -0
  36. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/IMPLEMENTATION_STEP_9.md +0 -0
  37. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/report_profile_v1.0.md +0 -0
  38. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/docs/dev/ova/report_profile_v1_draft.md +0 -0
  39. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/builder_numbering_roundtrip_demo.py +0 -0
  40. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/extended_registries_demo.py +0 -0
  41. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/full_report_workflow_demo.py +0 -0
  42. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/inline_objects_report.py +0 -0
  43. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/marks_and_lists_report.py +0 -0
  44. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/minimal_report.py +0 -0
  45. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/patent_valuation_style_report.py +0 -0
  46. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/registry_blocks_report.py +0 -0
  47. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/save_and_load_json_demo.py +0 -0
  48. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/validation_context_demo.py +0 -0
  49. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/examples/validation_report.py +0 -0
  50. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/base.py +0 -0
  51. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/block_objects.py +0 -0
  52. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/content.py +0 -0
  53. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/exceptions.py +0 -0
  54. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/inline.py +0 -0
  55. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/numbering.py +0 -0
  56. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/py.typed +0 -0
  57. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/registry.py +0 -0
  58. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/resolver.py +0 -0
  59. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/text.py +0 -0
  60. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/theme.py +0 -0
  61. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/src/ova_portable_text/validator.py +0 -0
  62. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_blocks_and_registry.py +0 -0
  63. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_builder_roundtrip_and_theme.py +0 -0
  64. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_document_validation_error_rendering.py +0 -0
  65. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_examples_smoke.py +0 -0
  66. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_extended_registries_and_resolver.py +0 -0
  67. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_file_io_roundtrip.py +0 -0
  68. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_inline_objects.py +0 -0
  69. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_mark_validation.py +0 -0
  70. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_marks_and_lists.py +0 -0
  71. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_minimal_report.py +0 -0
  72. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_pie_chart_parallel_arrays.py +0 -0
  73. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_resolver_debug_summary.py +0 -0
  74. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_resolver_semantic_figure_alias.py +0 -0
  75. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_roundtrip_and_runtime_version.py +0 -0
  76. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_section_batch_helpers.py +0 -0
  77. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_style_validation.py +0 -0
  78. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_table_dataset_validation.py +0 -0
  79. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validation_context_output.py +0 -0
  80. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validation_failures.py +0 -0
  81. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validation_report_python_alias.py +0 -0
  82. {ovaportabletext-0.1.0 → ovaportabletext-0.1.2}/tests/test_validation_success.py +0 -0
  83. {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
- - publish-readiness improvements for packaging, CI, docs, and edge tests
10
- - runtime `__version__` single source module
11
- - `py.typed` marker for typed package consumers
12
- - release-oriented docs: API reference and publishing checklist
13
- - file-based round-trip helpers: `save_json()` / `load_json()`
14
- - section batch helpers: `append_paragraphs()` / `append_bullet_items()` / `append_number_items()`
15
- - additional real-world docs, smoke examples, and regression-oriented tests
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.0
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
- Step 9 currently includes:
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
- - first batch of inline objects:
43
+ - inline objects:
41
44
  - `hard_break`
42
45
  - `xref`
43
46
  - `citation_ref`
44
47
  - `footnote_ref`
45
48
  - `glossary_term`
46
- - first batch of block objects:
49
+ - block objects:
47
50
  - `image`
48
51
  - `chart`
49
52
  - `table`
50
53
  - `math_block`
51
54
  - `callout`
52
- - first typed registries:
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, section
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.append_paragraph("This is a concluding paragraph after subsection 1.1.")
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. call `validate()` during development
99
- 4. call `assert_valid()` before exporting or handing off to Java
100
- 5. export with `to_dict()` / `to_json()`
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) Validate before export / 导出前校验
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
- ### 4) Save JSON to disk and read it back / 落盘 JSON 再读回
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
- Step 8 adds maintenance-friendly context in each issue, such as:
189
- 8 步开始,每条 issue 会尽量附带更适合维护的上下文,例如:
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
- Step 9 currently includes:
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
- - first batch of inline objects:
20
+ - inline objects:
18
21
  - `hard_break`
19
22
  - `xref`
20
23
  - `citation_ref`
21
24
  - `footnote_ref`
22
25
  - `glossary_term`
23
- - first batch of block objects:
26
+ - block objects:
24
27
  - `image`
25
28
  - `chart`
26
29
  - `table`
27
30
  - `math_block`
28
31
  - `callout`
29
- - first typed registries:
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, section
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.append_paragraph("This is a concluding paragraph after subsection 1.1.")
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. call `validate()` during development
76
- 4. call `assert_valid()` before exporting or handing off to Java
77
- 5. export with `to_dict()` / `to_json()`
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) Validate before export / 导出前校验
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
- ### 4) Save JSON to disk and read it back / 落盘 JSON 再读回
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
- Step 8 adds maintenance-friendly context in each issue, such as:
166
- 8 步开始,每条 issue 会尽量附带更适合维护的上下文,例如:
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "OVAPortableText"
7
- version = "0.1.0"
7
+ version = "0.1.2"
8
8
  description = "Python builder for generating OVAPortableText / Report Profile v1 JSON documents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -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__